IDLE conflated two unrelated things: "controller disabled" and "needs to cool, which this heat-only actuator fakes via zero output." Split them apart: - IDLE now means disabled only - the FSM forces it whenever enabled=False, regardless of the temperature gap, and process_pid() zeroes y for it same as before. - New COOL state (mirroring HEAT) takes over the negative-diff case, with its own pid_cool (separate "Cool" gains, alongside Hold/Heat) instead of reusing pid_rate. Its output can legitimately be negative - it's the actuator (tasks/heater.py's actor(), already max(0, ...)) that clamps it to 0 because *this* plant (Pot) can only heat. A plant with real cooling capability could one day honor it directly. - Thresholds renamed accordingly (HoldIdle->HoldCool, HeatIdle-> HeatCool, new CoolHold/CoolHeat); config.json/.sim/.templ and the hand-rolled ctrl_params in scripts/demos/pid/ and demo_sud.py updated with a "Cool" params section (mirrors "Heat" for now, since there's no real cooling actuator to tune against yet). Also fixes a regression in demo_sud.py/the other PID demos: none of them ever called set_enabled(True), so since enabled defaults to False they never drove the heater at all - only caught because this change's demo_sud.py re-run got stuck in RAMPING forever.
42 lines
572 B
Plaintext
Executable File
42 lines
572 B
Plaintext
Executable File
{
|
|
"ambient_temperature": 20,
|
|
"Controller" : {
|
|
"dt": 0.1,
|
|
"sim_warp_factor": 10.0,
|
|
"stirrer_name": "sim",
|
|
"heater_name": "sim",
|
|
"sensor_name": "sim",
|
|
"plant_name": "sim",
|
|
"pid_type": "Smith"
|
|
},
|
|
"TempCtrl": {
|
|
"Hold": {
|
|
"kp": 0.25,
|
|
"ki": 0.0,
|
|
"kd": 0.0,
|
|
"kt": 0.0
|
|
},
|
|
"Heat": {
|
|
"kp": 0.05,
|
|
"ki": 0.01,
|
|
"kd": 0.0,
|
|
"kt": 1.5
|
|
},
|
|
"Cool": {
|
|
"kp": 0.05,
|
|
"ki": 0.01,
|
|
"kd": 0.0,
|
|
"kt": 1.5
|
|
}
|
|
},
|
|
"Heater": {
|
|
"port": "/dev/ttyUSB0",
|
|
"speed": "115200"
|
|
},
|
|
"Stirrer": {
|
|
"port": "/dev/ttyACM0",
|
|
"speed": "115200"
|
|
}
|
|
}
|
|
|