diff --git a/components/pid/TODO.md b/components/pid/TODO.md index 1041177..8be35a9 100644 --- a/components/pid/TODO.md +++ b/components/pid/TODO.md @@ -118,6 +118,43 @@ git history for `temp_controller.py`/`temp_controller_smith.py`). `TestHoldOvershootRecoversToSetpoint` in `tests/components/pid/test_temp_controller_closed_loop.py`. +- [ ] **Architecture isn't ready for a real active cooler yet, only a + heat-only actuator.** Asked (not yet built): would the cascade/FSM + design still hold up if an active cooler (compressor/chiller, some + finite cooling power) replaced "heater off + passive ambient loss"? + Mostly yes at the PID/plant-model level: `Pid.y_min`/`y_max` are + already symmetric `-1.0`/`1.0` (`pid.py:12-13`), `Pot.set_power()`/ + `process()` are sign-agnostic so the simulator already models negative + power correctly, and the FSM already has a dedicated `COOL` state with + its own PID instance (`pid_inner_cool`, `temp_controller_fsm.py:35-39`) + whose comment explicitly anticipates this ("the actuator ... is + responsible for clamping the resulting negative power to whatever it's + actually capable of"). + The gap is at the actuator boundary: today `y` only ever reaches one + consumer, `tasks/heater.py:59`'s `self.power_actor = max(0, ... * y)`, + which silently discards every negative command — that's what's made + tuning mismatches free so far. A real cooler needs (a) a second + actuator/device class consuming the negative half instead of that + `max(0, ...)` clamp — there's no `Cooler`/chiller abstraction anywhere + yet (`grep -rniE "cooler|chiller|compressor"` across all `.py` is + empty, fully greenfield), and `heater_hendi.py:80`'s `set_power` only + clamps to a max, not a min, so feeding it a negative value today would + call `setPowerWatts(negative)` on real hardware with undefined result; + and (b) its own power ceiling, since one normalized `y` scaled by one + `get_power_max()` breaks once heater and cooler have different max + power. + Biggest risk once that clamp is removed: two separate paths start + issuing real negative-power commands that were previously harmless - + HOLD's `Outer.y_hold_min` floor (via `Inner.Hold`, see the steady-state + overshoot item above) and the pre-existing `pid_inner_cool` (via + `Inner.Cool`) - and neither has been tuned against actual active-cooling + dynamics (compressor lag, min-on-time). `Inner.Cool` in the demo + configs is literally a copy of `Inner.Heat`'s gains, never validated + independently. So adding a real cooler is a wiring task (new actuator + class, per-actuator power scaling) plus a re-tuning task (`Inner.Cool`, + and re-checking the `HoldCool`/`CoolHold` thresholds in + `temp_controller_fsm.py:14-17`), not just wiring. + - [ ] **`kalman.py` is now dead code in production.** Neither `temp_controller.py` nor `temp_controller_smith.py` uses `Kalman` anymore; the only remaining references are