Warm the loop by the mixed bulk; record the flow check to the heater's ceiling

flow_warm_validate.py warms in rounds (the heater at 50 percent for three
minutes, off, 45 s of circulation, the two sensors' mean read) and judges
the target on that mixed bulk, not on the upstream sensor beside the
heater, which reached any target within two minutes while the bulk had
barely moved. Run with a 28 C target the loop plateaus at 27.2 C in a
20 C room; six checks at 26.2 to 27.2 C read every verdict right, the flow
band under 11.9 C and the no-flow band over 18.0 C against the 14.4 C
limit. CAMPAIGN-LOG records the run; BRINGUP item 1 keeps only the
button-latch check, the flow check's bands holding from 19 to 27 C.

No catalog consequence: a bench tool and documentation.
This commit is contained in:
ScottW514
2026-08-29 19:37:26 -04:00
parent 9bfdba44c8
commit cd00b0d16f
3 changed files with 64 additions and 29 deletions
+4 -5
View File
@@ -1045,11 +1045,10 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
1. **Laser commissioning leftovers.** Verify the hardware button latch persists
across kernel-run gaps mid-job (if OK_2_FIRE drops between motion bursts, the
fix is a stream keepalive across armed gaps); the flow check's bands from
a loop warmer than 25 C (the bands hold from 19 to 25 C with the margin
widening warm; the warm-up in `flow_warm_validate.py` must be judged on
the mixed bulk, not the upstream sensor beside the heater, to reach 28 C
and above).
fix is a stream keepalive across armed gaps). The flow check's bands
hold from 19 to 27 C, the loop heater's ceiling in a 20 C room, with the
margin widening warm; above that only a running tube warms the loop,
and the check takes the tube's share off.
2. **Low-temperature gates and warm-up (planned).** Two keys in the Cooling
card: `cool_temp_min` (hard floor, default ~5 °C, a fire gate) and
`cool_temp_start` (warm-up gate, default ~16 °C) — a job starting below the
+24
View File
@@ -4535,6 +4535,30 @@ compensation's whole path stands on the bench: the tool measures the
machine's number, Apply writes it, and both coolant readings hold within
0.1 C when the run airflow comes on.
## 2026-08-29: the flow check from a warm loop, to the heater's ceiling
`flow_warm_validate.py` with its warm-up rewritten to judge the mixed bulk
(the heater at 50 % for three minutes, off, 45 s of circulation, the two
sensors' mean; a round that lifts the bulk under 0.15 C ends the warm-up),
run from the bench page as the `flow-warm` takeover with a 28 C target and
a 20 min budget, three checks pump on and three pump off, alternating.
The bulk plateaus at 27.2 C in this room, so the checks ran at 26.2 to
27.2 C baselines, the most the loop heater can give.
| case | rises (C) | band |
|---|---|---|
| pump on | 11.08, 11.89, 10.98 | max 11.89 |
| pump off | 18.69, 18.42, 18.00 | min 18.00 |
Every verdict correct; the 14.4 C limit sits 2.51 C above the warm flow
band and 3.60 C below the warm no-flow band. With the 19 to 23 C
characterization (12.75 / 16.04) and the 24 to 25 C run earlier in the
day (12.15 / 18.07), the bands hold from 19 to 27 C with the margin
widening warm. Above 27 C only a running tube warms this loop, and the
check takes the tube's share off; `cool_flow_rise` needs no warm-end
value. Records `bench-data/flow_warm_log_20260829b.txt`,
`flow_warm_results_20260829b.json`.
## Superseded status notes
### Shared machine services — remaining polish, as listed 2026-08-13
+36 -24
View File
@@ -68,41 +68,53 @@ def pump(on):
board('echo %d > /sys/glowforge/thermal/water_pump_on' % (1 if on else 0))
WARM_ROUND_S = 180 # heater on per round, then a mix and a bulk reading
WARM_MIX_S = 45
WARM_PLATEAU_C = 0.15 # a round that lifts the bulk less than this is the end
def warm_to(target, log):
"""Warm with the loop heater, pump circulating, fans off."""
"""Warm with the loop heater in rounds, pump circulating, fans off:
heater on for WARM_ROUND_S, heater off and WARM_MIX_S of circulation,
then the bulk read as the two sensors' mean. Judged on that mixed
bulk, never on the upstream sensor beside the heater, which reaches
any target within two minutes while the bulk has barely moved (the
2026-08-29 run stopped at 24.5 C that way). 50 % is the practical
heater ceiling: the downstream sensor sits at the element and 100 %
drives it past 50 C in 30 s."""
pump(True)
board(FANS_OFF)
# 50% is the practical ceiling: the downstream sensor sits AT the
# heater element, so 100% drives it past 50 C within 30 s while the
# bulk has barely moved. At 50% it plateaus near 41 C, leaving the
# bulk free to climb for as long as we let it.
heater(50)
t0 = time.time()
# Plateau detection compares against the reading two minutes back:
# with the pump circulating, the bulk climbs only ~0.5-0.8 C/min, so
# a per-sample threshold mistakes normal warming for a plateau (it
# did exactly that on the first attempt and the whole run executed
# at ambient).
hist = []
last_bulk = None
while time.time() - t0 < WARM_MAX_S:
heater(50)
r0 = time.time()
abort = False
while time.time() - r0 < WARM_ROUND_S and time.time() - t0 < WARM_MAX_S:
d, u = temps()
if d >= ABORT_C:
log(' warm abort: downstream %.2f C' % d)
abort = True
break
time.sleep(15)
heater(0)
if abort:
break
time.sleep(WARM_MIX_S)
d, u = temps()
bulk = (d + u) / 2.0
el = (time.time() - t0) / 60
if u >= target:
log(' warm target reached: up=%.2f at %.1f min' % (u, el))
log(' warming: %.1f min bulk %.2f (down %.2f, up %.2f)' % (el, bulk, d, u))
if bulk >= target:
log(' warm target reached: bulk %.2f at %.1f min' % (bulk, el))
break
if d >= ABORT_C:
log(' warm abort: downstream %.2f at %.1f min' % (d, el))
if last_bulk is not None and bulk - last_bulk < WARM_PLATEAU_C:
log(' (warming plateaued at %.2f C after %.1f min)' % (bulk, el))
break
hist.append(u)
if len(hist) % 4 == 0:
log(' warming: %.1f min down=%.2f up=%.2f' % (el, d, u))
if len(hist) > 8 and u - hist[-9] < 0.3:
log(' (warming plateaued at %.2f C after %.1f min)' % (u, el))
break
time.sleep(15)
last_bulk = bulk
heater(0)
pump(True)
time.sleep(45) # mix so the bulk is uniform before measuring
time.sleep(WARM_MIX_S) # mix so the bulk is uniform before measuring
d, u = temps()
log(' warmed to down=%.2f up=%.2f in %.1f min' % (d, u, (time.time() - t0) / 60))
return u