TempControllerBase: require PID gains via set_params(), not the constructor
Mirrors components/pid/pid.py's own Pid.set_params() pattern: params/ thresholds start out None, and set_params() configures pid_hold/pid_heat/ pid_cool from them. process()/process_fsm() fail naturally (TypeError on None) if called before set_params() - same as Pid.process() already does - rather than a new bespoke check. Updates all callers (server/brewpi.py, SudForecastEstimator, and the pid/sud demo scripts) to call set_params() right after construction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
This commit is contained in:
@@ -2,11 +2,11 @@ from components.pid.temp_controller_base import TempControllerBase
|
|||||||
|
|
||||||
|
|
||||||
class TempController(TempControllerBase):
|
class TempController(TempControllerBase):
|
||||||
def __init__(self, dt, params, model_params=None, theta_amb=20):
|
def __init__(self, dt, model_params=None, theta_amb=20):
|
||||||
# model_params/theta_amb are accepted (but unused) for constructor
|
# model_params/theta_amb are accepted (but unused) for constructor
|
||||||
# compatibility with TempControllerSmith - PidFactory.create() calls
|
# compatibility with TempControllerSmith - PidFactory.create() calls
|
||||||
# either with the same arguments; "Normal" has no internal model.
|
# either with the same arguments; "Normal" has no internal model.
|
||||||
TempControllerBase.__init__(self, dt, params)
|
TempControllerBase.__init__(self, dt)
|
||||||
self.dt = dt
|
self.dt = dt
|
||||||
self.last_theta_ist = 20
|
self.last_theta_ist = 20
|
||||||
self.heatrate_ist = 0
|
self.heatrate_ist = 0
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class States(enum.Enum):
|
|||||||
|
|
||||||
class TempControllerBase(APid):
|
class TempControllerBase(APid):
|
||||||
|
|
||||||
def __init__(self, dt, params):
|
def __init__(self, dt):
|
||||||
APid.__init__(self)
|
APid.__init__(self)
|
||||||
self.pid_hold = Pid(dt)
|
self.pid_hold = Pid(dt)
|
||||||
self.pid_heat = Pid(dt)
|
self.pid_heat = Pid(dt)
|
||||||
@@ -44,13 +44,13 @@ class TempControllerBase(APid):
|
|||||||
self.heatrate_soll = 1.0
|
self.heatrate_soll = 1.0
|
||||||
self.theta_ist = 0
|
self.theta_ist = 0
|
||||||
self.heatrate_ist = 0
|
self.heatrate_ist = 0
|
||||||
self.params = params
|
# None until set_params() is called - mirrors Pid's own
|
||||||
self.thresholds = {**DEFAULT_THRESHOLDS, **params.get('Thresholds', {})}
|
# params/set_params() (components/pid/pid.py), whose process()
|
||||||
|
# already relies on the same "None means not configured yet".
|
||||||
|
self.params = None
|
||||||
|
self.thresholds = None
|
||||||
self.y = -1
|
self.y = -1
|
||||||
self.state = States.INIT
|
self.state = States.INIT
|
||||||
self.pid_hold.set_params(params['Hold'])
|
|
||||||
self.pid_heat.set_params(params['Heat'])
|
|
||||||
self.pid_cool.set_params(params['Cool'])
|
|
||||||
self.is_startup = True
|
self.is_startup = True
|
||||||
# Master on/off switch: while disabled, the FSM is held in IDLE and
|
# Master on/off switch: while disabled, the FSM is held in IDLE and
|
||||||
# the controller tries not to drive the heater at all (output
|
# the controller tries not to drive the heater at all (output
|
||||||
@@ -58,6 +58,13 @@ class TempControllerBase(APid):
|
|||||||
# (manual mode) or by SudTask for the duration of a run.
|
# (manual mode) or by SudTask for the duration of a run.
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
|
|
||||||
|
def set_params(self, params):
|
||||||
|
self.params = params
|
||||||
|
self.thresholds = {**DEFAULT_THRESHOLDS, **params.get('Thresholds', {})}
|
||||||
|
self.pid_hold.set_params(params['Hold'])
|
||||||
|
self.pid_heat.set_params(params['Heat'])
|
||||||
|
self.pid_cool.set_params(params['Cool'])
|
||||||
|
|
||||||
def on_state_entered(self, state):
|
def on_state_entered(self, state):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from components.pid.temp_controller_base import TempControllerBase, States
|
|||||||
|
|
||||||
|
|
||||||
class TempController(TempControllerBase):
|
class TempController(TempControllerBase):
|
||||||
def __init__(self, dt, params, model_params, theta_amb=20):
|
def __init__(self, dt, model_params, theta_amb=20):
|
||||||
TempControllerBase.__init__(self, dt, params)
|
TempControllerBase.__init__(self, dt)
|
||||||
self.dt = dt
|
self.dt = dt
|
||||||
self.last_theta_ist = 20
|
self.last_theta_ist = 20
|
||||||
self.heatrate_ist = 0
|
self.heatrate_ist = 0
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ class SudForecastEstimator:
|
|||||||
pot.set_plant_params(self.plant_params)
|
pot.set_plant_params(self.plant_params)
|
||||||
pot.set_ambient_temperature(self.theta_amb)
|
pot.set_ambient_temperature(self.theta_amb)
|
||||||
pot.initial(start_theta)
|
pot.initial(start_theta)
|
||||||
tc = PidFactory.create(self.pid_type, self.dt, self.tempctrl_params, self.plant_params, theta_amb=self.theta_amb)
|
tc = PidFactory.create(self.pid_type, self.dt, self.plant_params, theta_amb=self.theta_amb)
|
||||||
|
tc.set_params(self.tempctrl_params)
|
||||||
tc.set_enabled(True)
|
tc.set_enabled(True)
|
||||||
tc.set_theta_ist(pot.get_temperature())
|
tc.set_theta_ist(pot.get_temperature())
|
||||||
# Seed the target at start_theta - this tc is a fresh, throwaway
|
# Seed the target at start_theta - this tc is a fresh, throwaway
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ if __name__ == '__main__':
|
|||||||
temp_ist = 0
|
temp_ist = 0
|
||||||
temp_soll = 20
|
temp_soll = 20
|
||||||
heatrate_soll = 1.25
|
heatrate_soll = 1.25
|
||||||
ctrl = TempController(dt, ctrl_params)
|
ctrl = TempController(dt)
|
||||||
|
ctrl.set_params(ctrl_params)
|
||||||
ctrl.set_enabled(True)
|
ctrl.set_enabled(True)
|
||||||
plant = Pot(dt)
|
plant = Pot(dt)
|
||||||
plant.set_plant_params(plant_params)
|
plant.set_plant_params(plant_params)
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ if __name__ == '__main__':
|
|||||||
temp_ist = 0
|
temp_ist = 0
|
||||||
temp_soll = 20
|
temp_soll = 20
|
||||||
heatrate_soll = 1.25
|
heatrate_soll = 1.25
|
||||||
ctrl = TempController(dt, ctrl_params, plant_params, theta_amb)
|
ctrl = TempController(dt, plant_params, theta_amb)
|
||||||
|
ctrl.set_params(ctrl_params)
|
||||||
ctrl.set_enabled(True)
|
ctrl.set_enabled(True)
|
||||||
plant = Pot(dt)
|
plant = Pot(dt)
|
||||||
plant.set_plant_params(plant_params)
|
plant.set_plant_params(plant_params)
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ if __name__ == '__main__':
|
|||||||
"Td" : 60
|
"Td" : 60
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl = TempController(dt, ctrl_params, plant_params, theta_amb)
|
ctrl = TempController(dt, plant_params, theta_amb)
|
||||||
|
ctrl.set_params(ctrl_params)
|
||||||
plant = Pot(dt)
|
plant = Pot(dt)
|
||||||
plant.set_plant_params(plant_params)
|
plant.set_plant_params(plant_params)
|
||||||
plant.set_ambient_temperature(theta_amb)
|
plant.set_ambient_temperature(theta_amb)
|
||||||
|
|||||||
+2
-1
@@ -88,7 +88,8 @@ if __name__ == '__main__':
|
|||||||
taskmgr.add(heater_task)
|
taskmgr.add(heater_task)
|
||||||
|
|
||||||
# Temperature Controller
|
# Temperature Controller
|
||||||
tc = PidFactory.create(config['Controller']['pid_type'], DT, config['TempCtrl'], DEFAULT_PLANT_PARAMS, theta_amb=theta_amb)
|
tc = PidFactory.create(config['Controller']['pid_type'], DT, DEFAULT_PLANT_PARAMS, theta_amb=theta_amb)
|
||||||
|
tc.set_params(config['TempCtrl'])
|
||||||
tc_task = TcTask(tc, DT_TASK, dispatcher.msgio_get("TempCtrl"))
|
tc_task = TcTask(tc, DT_TASK, dispatcher.msgio_get("TempCtrl"))
|
||||||
taskmgr.add(tc_task)
|
taskmgr.add(tc_task)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user