From bf019733b2b4b9ed958a52bea0933e2b010d50dc Mon Sep 17 00:00:00 2001 From: jens Date: Sat, 2 Oct 2021 11:10:43 +0200 Subject: [PATCH] - added abstarct PID APid - added PidFactory - use variable args for factory --- brewpi.py | 6 ++-- components/__init__.py | 1 + components/actor/heaterFactory.py | 8 +++-- components/actor/heater_sim.py | 2 +- components/apid.py | 43 ++++++++++++++++++++++++ components/pid/__init__.py | 2 +- components/pid/pid_factory.py | 11 ++++++ components/pid/temp_controller.py | 6 ++-- components/pid/temp_controller_smith.py | 24 +++++++++++-- components/sensor/tempSensorSim.py | 8 ++--- components/sensor/tempSensor_max31865.py | 2 +- components/sensor/tempsensor_factory.py | 6 ++-- results.m | 16 +++++++++ tasks/tempctrl.py | 4 +-- tasks/tracer.py | 4 +-- 15 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 components/apid.py create mode 100644 components/pid/pid_factory.py diff --git a/brewpi.py b/brewpi.py index e1db75a..bfcad9d 100755 --- a/brewpi.py +++ b/brewpi.py @@ -5,7 +5,7 @@ from utils import ChangedFloat from ws.message import MessageDispatcher from ws.server.ws_server_multi_user import WsServerMultiUser from components.sensor import TempSensorFactory -from components.pid import TempController +from components.pid import PidFactory from components.plant import Pot from components.actor import HeaterFactory, StirrerFactory from tasks import TaskManager, TempSensorTask, HeaterTask, PotTask, TcTask, StirrerTask, TracerTask @@ -31,14 +31,14 @@ if __name__ == '__main__': taskmgr.add(PotTask(pot, DT_TASK, dispatcher.msgio_get("Pot"))) # Heater - heater = HeaterFactory.create(config['Controller']['heater_name'], DT, config['Heater']) + heater = HeaterFactory.create(config['Controller']['heater_name'], config['Heater']) heater.set_on_changed("power_eff", ChangedFloat(pot.set_power, prec=0).set) heater_task = HeaterTask(heater, DT_TASK, dispatcher.msgio_get("Heater")) taskmgr.add(heater_task) # Temperature Controller tc_params = config['TempCtrl'] - tc = TempController(DT, tc_params) + tc = PidFactory.create('Normal', DT, tc_params) tc.set_on_changed("y", heater_task.actor) tc_task = TcTask(tc, DT_TASK, dispatcher.msgio_get("TempCtrl")) taskmgr.add(tc_task) diff --git a/components/__init__.py b/components/__init__.py index 58ecf73..75455ab 100644 --- a/components/__init__.py +++ b/components/__init__.py @@ -1,3 +1,4 @@ from components.atemperatureSensor import * from components.astirrer import * from components.aheater import * +from components.apid import * diff --git a/components/actor/heaterFactory.py b/components/actor/heaterFactory.py index 81d0fc2..f899886 100644 --- a/components/actor/heaterFactory.py +++ b/components/actor/heaterFactory.py @@ -2,10 +2,12 @@ class HeaterFactory: @staticmethod - def create(name, dt, params): + def create(name, *args, **kwargs): if "sim" in name: from components.actor.heater_sim import HeaterSim - return HeaterSim() + print (*args) + print (**kwargs) + return HeaterSim(*args, **kwargs) elif "Hendi" in name: from components.actor.heater_hendi import HeaterHendi - return HeaterHendi(params) + return HeaterHendi(*args, **kwargs) diff --git a/components/actor/heater_sim.py b/components/actor/heater_sim.py index ec013e2..1fddc82 100644 --- a/components/actor/heater_sim.py +++ b/components/actor/heater_sim.py @@ -2,7 +2,7 @@ from components.aheater import AHeater class HeaterSim(AHeater): - def __init__(self): + def __init__(self, params): AHeater.__init__(self) self.power_set = 0 self.power_eff = 0 diff --git a/components/apid.py b/components/apid.py new file mode 100644 index 0000000..ada426e --- /dev/null +++ b/components/apid.py @@ -0,0 +1,43 @@ +import abc +from utils.value import AttributeChange + + +class APid(AttributeChange): + def __init__(self): + AttributeChange.__init__(self) + + @abc.abstractmethod + def set_theta_soll(self, value): + return None + + @abc.abstractmethod + def set_heatrate_soll(self, value): + return None + + @abc.abstractmethod + def get_theta_ist(self): + return None + + @abc.abstractmethod + def get_heatrate_ist(self): + return None + + @abc.abstractmethod + def get_theta_soll_set(self): + return None + + @abc.abstractmethod + def get_theta_soll(self): + return None + + @abc.abstractmethod + def get_heatrate_soll_set(self): + return None + + @abc.abstractmethod + def get_heatrate_soll(self): + return None + + @abc.abstractmethod + def process(self): + pass diff --git a/components/pid/__init__.py b/components/pid/__init__.py index 8b40e26..fb14e21 100644 --- a/components/pid/__init__.py +++ b/components/pid/__init__.py @@ -1,3 +1,3 @@ from components.pid.pid import * from components.pid.kalman import * -from components.pid.temp_controller_smith import * +from components.pid.pid_factory import PidFactory diff --git a/components/pid/pid_factory.py b/components/pid/pid_factory.py new file mode 100644 index 0000000..d49ef6f --- /dev/null +++ b/components/pid/pid_factory.py @@ -0,0 +1,11 @@ + + +class PidFactory: + @staticmethod + def create(name, *args, **kwargs): + if "Normal" in name: + from components.pid.temp_controller import TempController + return TempController(*args, **kwargs) + elif "Smith" in name: + from components.pid.temp_controller_smith import TempController + return TempController(*args, **kwargs) diff --git a/components/pid/temp_controller.py b/components/pid/temp_controller.py index 7311a92..78f2fe7 100644 --- a/components/pid/temp_controller.py +++ b/components/pid/temp_controller.py @@ -1,8 +1,8 @@ from components.plant.pot import Pot from matplotlib.pyplot import plot, figure, subplot, grid, show, legend from components.pid import Pid, Kalman +from components import APid import numpy as np -from utils.value import AttributeChange from enum import Enum @@ -12,9 +12,9 @@ class States(Enum): HOLD = 2 -class TempController(AttributeChange): +class TempController(APid): def __init__(self, dt, params): - AttributeChange.__init__(self) + APid.__init__(self) self.pid_hold = Pid(dt) self.pid_rate = Pid(dt) self.theta_ist_set = 20 diff --git a/components/pid/temp_controller_smith.py b/components/pid/temp_controller_smith.py index e034073..bc619da 100644 --- a/components/pid/temp_controller_smith.py +++ b/components/pid/temp_controller_smith.py @@ -1,8 +1,8 @@ from components.plant.pot import Pot, Delay from matplotlib.pyplot import plot, figure, subplot, grid, show, legend from components.pid import Pid, Kalman +from components import APid import numpy as np -from utils.value import AttributeChange from enum import Enum @@ -12,9 +12,9 @@ class States(Enum): HOLD = 2 -class TempController(AttributeChange): +class TempController(APid): def __init__(self, dt, params): - AttributeChange.__init__(self) + APid.__init__(self) self.pid_hold = Pid(dt) self.pid_rate = Pid(dt) self.theta_ist_set = 20 @@ -41,15 +41,33 @@ class TempController(AttributeChange): def set_theta_ist(self, value): self.theta_ist_set = value + def get_theta_ist(self): + return self.theta_ist + def set_heatrate_ist(self, value): self.heatrate_ist_set = value + def get_heatrate_ist(self): + return self.heatrate_ist + def set_theta_soll(self, value): self.theta_soll_set = value + def get_theta_soll(self): + return self.theta_soll + + def get_theta_soll_set(self): + return self.theta_soll_set + def set_heatrate_soll(self, value): self.heatrate_soll_set = value + def get_heatrate_soll(self): + return self.heatrate_soll + + def get_heatrate_soll_set(self): + return self.heatrate_soll_set + def process(self): # Process Kalman of Model Z_model = self.kalman_model.process_measurement((self.model.get_temperature_intermediate(), 0), 0.0) diff --git a/components/sensor/tempSensorSim.py b/components/sensor/tempSensorSim.py index b924923..01ad7bb 100644 --- a/components/sensor/tempSensorSim.py +++ b/components/sensor/tempSensorSim.py @@ -6,8 +6,9 @@ class TempSensorSim(ATemperatureSensor): def name(self): return "FakeTemp" - def __init__(self): + def __init__(self, temp_offset=0): ATemperatureSensor.__init__(self) + self.temp_offset = temp_offset self.temp = 22.37 self.temp_set = self.temp self.k_noise = 0.01 @@ -16,8 +17,7 @@ class TempSensorSim(ATemperatureSensor): self.temp_set = temp def temperature(self): - return self.temp_set + self.k_noise * np.random.normal(0, 1) / np.sqrt(12.0) + return self.temp_offset + self.temp def process(self): - temp = self.temperature() - self.temp = temp + self.temp = self.temp_set + self.k_noise * np.random.normal(0, 1) / np.sqrt(12.0) diff --git a/components/sensor/tempSensor_max31865.py b/components/sensor/tempSensor_max31865.py index 69257ca..3c48cdd 100755 --- a/components/sensor/tempSensor_max31865.py +++ b/components/sensor/tempSensor_max31865.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import time from components import ATemperatureSensor import spidev diff --git a/components/sensor/tempsensor_factory.py b/components/sensor/tempsensor_factory.py index 050393b..dc7aa71 100644 --- a/components/sensor/tempsensor_factory.py +++ b/components/sensor/tempsensor_factory.py @@ -2,10 +2,10 @@ class TempSensorFactory: @staticmethod - def create(name): + def create(name, *args, **kwargs): if "sim" in name: from components.sensor.tempSensorSim import TempSensorSim - return TempSensorSim() + return TempSensorSim(*args, **kwargs) elif "31865" in name: from components.sensor.tempSensor_max31865 import TempSensor_max31865 - return TempSensor_max31865(temp_offset=0) + return TempSensor_max31865(*args, **kwargs) diff --git a/results.m b/results.m index d4d8144..e77828a 100644 --- a/results.m +++ b/results.m @@ -26,11 +26,27 @@ function retval = results() load brewpi.mat + +close all; + +figure(1) + set(0, "defaultlinelinewidth", 1.5); subplot(3,1,1) plot(time, tc_temp_soll, time, tc_temp_ist); grid legend("Temp_{soll}","Temp_{ist}") subplot(3,1,2) +plot(time, tc_temp_ist-tc_temp_soll, "ro"); grid +legend("Temp_{ist} - dTemp_{soll}") +subplot(3,1,3) +plot(time, heater_power); grid +legend("Power_{Heater}") + +figure(2) +subplot(3,1,1) +plot(time, tc_temp_soll, time, tc_temp_ist); grid +legend("Temp_{soll}","Temp_{ist}") +subplot(3,1,2) plot(time, tc_dtemp_soll, time, tc_dtemp_ist, time, tc_dtemp_commanded); grid legend("dTemp_{soll}","dTemp_{ist}","dTemp_{cmd}") subplot(3,1,3) diff --git a/tasks/tempctrl.py b/tasks/tempctrl.py index f49b30b..3aabfdb 100644 --- a/tasks/tempctrl.py +++ b/tasks/tempctrl.py @@ -2,11 +2,11 @@ import asyncio from tasks import ATask from ws.message import MsgIo from utils.value import ChangedFloat -from components.pid import TempController +from components import APid class TcTask(ATask): - def __init__(self, tc: TempController, interval, msg_handler: MsgIo): + def __init__(self, tc: APid, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.tc = tc diff --git a/tasks/tracer.py b/tasks/tracer.py index b8e3aa5..937492d 100644 --- a/tasks/tracer.py +++ b/tasks/tracer.py @@ -4,14 +4,14 @@ from tasks import ATask from ws.message import MsgIo from components import ATemperatureSensor from components import AHeater -from components.pid import TempController +from components import APid import numpy as np import scipy.io class TracerTask(ATask): - def __init__(self, sensor: ATemperatureSensor, heater: AHeater, temp_ctrl: TempController, interval, msg_handler: MsgIo): + def __init__(self, sensor: ATemperatureSensor, heater: AHeater, temp_ctrl: APid, interval, msg_handler: MsgIo): ATask.__init__(self, interval) self.msg_handler = msg_handler