From d9c587476f9f20f93b7554ce502e88bbf5ba8d43 Mon Sep 17 00:00:00 2001 From: jens Date: Sun, 29 Nov 2020 14:35:44 +0100 Subject: [PATCH] - added Temp controller - use AttributeChange for Processing objects --- brewpi.py | 50 +++++++++++++++++++++++++++---- components/actor/heater.py | 3 +- components/aheater.py | 3 ++ components/aplant.py | 3 ++ components/pid/temp_controller.py | 14 +++++++-- components/plant/pot.py | 1 + utils/value.py | 12 +++++--- 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/brewpi.py b/brewpi.py index ecda2fd..f3cbefc 100644 --- a/brewpi.py +++ b/brewpi.py @@ -46,7 +46,7 @@ class TempSensorTask(ATask): self.kalman.initial((self.sensor.temperature(), 0)) temp = ValueChanged(self.on_temp_changed, prec=1) temp_kalman = ValueChanged(self.on_temp_changed_kalman, prec=1) - self.sensor.set_on_changed("temp", temp) + self.sensor.set_on_changed("temp", temp.set) while True: self.sensor.process() Z = self.kalman.process_measurement((self.sensor.temperature(), 0), 0) @@ -64,6 +64,11 @@ class HeaterTask(ATask): self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) self.heater = heater + self.y = 0 + self.power_soll = 0 + + def actor(self, y): + self.y = y async def recv(self, data): print(data) @@ -82,6 +87,8 @@ class HeaterTask(ATask): power = Value() while True: + self.power_soll = 200 + self.heater.get_power_max()*self.y + self.heater.setPower(self.power_soll) self.heater.process() power.set(round(self.heater.getPower())) if power.is_changed(): @@ -125,6 +132,31 @@ class PotTask(ATask): await asyncio.sleep(self.interval) +class TcTask(ATask): + def __init__(self, tc: temp_controller.TempController, interval, msg_handler: MsgIo): + ATask.__init__(self, interval) + + self.msg_handler = msg_handler + msg_handler.set_recv_handler(self.recv) + self.tc = tc + + async def recv(self, data): + print(data) + for pair in data.items(): + if 'Soll' in pair[0]: + self.tc.set_theta_soll(pair[1]) + + async def send(self, data): + await self.msg_handler.send(data) + + async def on_process(self): + print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) + self.tc.set_theta_soll(20) + while True: + self.tc.process() + await asyncio.sleep(self.interval) + + class TaskManager: def __init__(self): self.tasks = [] @@ -166,7 +198,7 @@ if __name__ == '__main__': # Sensor sensor = TempSensorSim() - taskmgr.add(TempSensorTask(sensor, 0.2, dispatcher.msgio_get("Sensor"), kalman)) + taskmgr.add(TempSensorTask(sensor, 1.0, dispatcher.msgio_get("Sensor"), kalman)) # Plant pot_params = { @@ -179,13 +211,14 @@ if __name__ == '__main__': "kn" : 0.2 } pot = Pot(pot_params) - pot.set_on_changed("temp", ValueChanged(sensor.set_fake_temp, prec=1)) - taskmgr.add(PotTask(pot, 0.1, dispatcher.msgio_get("Pot"))) + pot.set_on_changed("temp", ValueChanged(sensor.set_fake_temp, prec=1).set) + taskmgr.add(PotTask(pot, 1.0, dispatcher.msgio_get("Pot"))) # Heater heater = Heater() - heater.set_on_changed("power_eff", ValueChanged(pot.setPower, prec=0)) - taskmgr.add(HeaterTask(heater, 0.02, dispatcher.msgio_get("Heater"))) + heater.set_on_changed("power_eff", ValueChanged(pot.setPower, prec=0).set) + heater_task = HeaterTask(heater, 1.0, dispatcher.msgio_get("Heater")) + taskmgr.add(heater_task) # Temperature Controller tc_params = { @@ -208,7 +241,12 @@ if __name__ == '__main__': } } tc = temp_controller.TempController(tc_params) + tc.set_on_changed("y_hold", heater_task.actor) + tc_task = TcTask(tc, 1.0, dispatcher.msgio_get("Tc")) + taskmgr.add(tc_task) + sensor.set_on_changed("temp", ValueChanged(tc.set_theta_ist, prec=1).set) + # Message dispatcher h_dispatcher = taskmgr.start() h_server = server.listen("localhost", 8765) asyncio.gather(h_dispatcher, h_server) diff --git a/components/actor/heater.py b/components/actor/heater.py index 2da0b12..c0be6a4 100644 --- a/components/actor/heater.py +++ b/components/actor/heater.py @@ -3,12 +3,13 @@ from components.aheater import AHeater class Heater(AHeater): def __init__(self): + AHeater.__init__(self) self.power_set = self.get_power_min() self.is_active = False self.power_eff = 0 def get_power_min(self): - return 500 + return 0 def get_power_max(self): return 3500 diff --git a/components/aheater.py b/components/aheater.py index 16a531f..9b9904e 100644 --- a/components/aheater.py +++ b/components/aheater.py @@ -3,6 +3,9 @@ from utils.value import AttributeChange class AHeater(AttributeChange): + def __init__(self): + AttributeChange.__init__(self) + @abc.abstractmethod def get_power_min(self): pass diff --git a/components/aplant.py b/components/aplant.py index 25b7607..21c62f8 100644 --- a/components/aplant.py +++ b/components/aplant.py @@ -3,6 +3,9 @@ from utils.value import AttributeChange class APlant(AttributeChange): + def __init__(self): + AttributeChange.__init__(self) + @abc.abstractmethod def activate(self, enable): return None diff --git a/components/pid/temp_controller.py b/components/pid/temp_controller.py index 32d6971..e97182e 100644 --- a/components/pid/temp_controller.py +++ b/components/pid/temp_controller.py @@ -1,10 +1,13 @@ from components.pid.pid import Pid from matplotlib.pyplot import plot, figure, subplot, title, xlabel, ylabel, grid, show import numpy as np +from utils.value import AttributeChange -class TempController: +class TempController(AttributeChange): def __init__(self, params): + AttributeChange.__init__(self) + self.dt = params['dt'] self.pid_hold = Pid() self.pid_rate = Pid() @@ -13,6 +16,8 @@ class TempController: self.heatrate_ist = 0 self.heatrate_soll = 0 self.params = params + self.y_hold = 0 + self.y_heat = 0 def set_theta_ist(self, value): self.theta_ist = value @@ -33,11 +38,14 @@ class TempController: self.pid_hold.process(self.dt, self.params['Hold']['Pid'], theta_err) self.pid_rate.process(self.dt, self.params['Heat']['Pid'], heatrate_err) + self.y_hold = self.pid_hold.get_y() + self.y_heat = self.pid_rate.get_y() + def get_power_hold(self): - return self.pid_hold.get_y() + return self.y_hold def get_power_heat(self): - return self.pid_rate.get_y() + return self.y_heat if __name__ == '__main__': diff --git a/components/plant/pot.py b/components/plant/pot.py index b98cdae..72bd472 100644 --- a/components/plant/pot.py +++ b/components/plant/pot.py @@ -4,6 +4,7 @@ from components.aplant import APlant class Pot(APlant): def __init__(self, params): + APlant.__init__(self) self.dt = params['dt'] self.alpha = 1.0 diff --git a/utils/value.py b/utils/value.py index b562e6e..f37a5de 100644 --- a/utils/value.py +++ b/utils/value.py @@ -33,11 +33,14 @@ class ValueChanged(object): class AttributeChange(object): - callbacks = {} + def __init__(self): + self.callbacks = {} - def set_on_changed(self, key, on_changed: ValueChanged): + def set_on_changed(self, key, on_changed): if key not in self.callbacks: - self.callbacks[key] = on_changed + self.callbacks[key] = [on_changed] + else: + self.callbacks[key].append(on_changed) def __setattr__(self, key, value): try: @@ -48,4 +51,5 @@ class AttributeChange(object): super().__setattr__(key, value) if key in self.callbacks: - self.callbacks[key].set(value) + for cb in self.callbacks[key]: + cb(value)