From 2d628e151c90ecd65c960c63a59a9b98ae11d4bb Mon Sep 17 00:00:00 2001 From: Oksana Shliakhtun Date: Wed, 26 Apr 2023 10:23:14 +0200 Subject: [PATCH] finished thermofisher but: convergence does not work yet properly Change-Id: I834f8368730c347ba9f08a03eceae1a60fc66f90 --- {frappy_psi => cfg}/TFA10_cfg.py | 7 +- frappy/mixins.py | 2 +- frappy_psi/convergence.py | 3 +- frappy_psi/qnw.py | 11 +-- frappy_psi/thermofisher.py | 121 ++++++++++++++++++++++--------- 5 files changed, 96 insertions(+), 48 deletions(-) rename {frappy_psi => cfg}/TFA10_cfg.py (68%) diff --git a/frappy_psi/TFA10_cfg.py b/cfg/TFA10_cfg.py similarity index 68% rename from frappy_psi/TFA10_cfg.py rename to cfg/TFA10_cfg.py index 69fceda..c1356d1 100644 --- a/frappy_psi/TFA10_cfg.py +++ b/cfg/TFA10_cfg.py @@ -1,5 +1,5 @@ Node('TFA10.psi.ch', - 'TFA10', + 'TFA10 test', 'tcp://5000', ) @@ -10,13 +10,14 @@ Mod('io', ) Mod('T', - 'frappy_psi.qnw.TemperatureLoopA10', + 'frappy_psi.thermofisher.TemperatureLoopA10', 'holder temperature', io='io', + target=Param(max=100), ) Mod('Th', - 'frappy_psi.qnw.SensorA10', + 'frappy_psi.thermofisher.SensorA10', 'heat exch. temperature', io='io', ) diff --git a/frappy/mixins.py b/frappy/mixins.py index 2945604..c353ad4 100644 --- a/frappy/mixins.py +++ b/frappy/mixins.py @@ -65,7 +65,7 @@ class HasOutputModule(Writable): """ # mandatory=False: it should be possible to configure a module with fixed control output_module = Attached(HasControlledBy, mandatory=False) - control_active = Parameter('control mode', BoolType()) + control_active = Parameter('control mode', BoolType(), default=False) def initModule(self): super().initModule() diff --git a/frappy_psi/convergence.py b/frappy_psi/convergence.py index f7820ea..0a34a95 100644 --- a/frappy_psi/convergence.py +++ b/frappy_psi/convergence.py @@ -21,10 +21,11 @@ # ***************************************************************************** from frappy.core import Parameter, FloatRange, BUSY, IDLE, WARN +from frappy.states import HasStates from frappy.lib.statemachine import StateMachine, Retry, Stop -class HasConvergence: +class HasConvergence(HasStates): """mixin for convergence checks Implementation based on tolerance, settling time and timeout. diff --git a/frappy_psi/qnw.py b/frappy_psi/qnw.py index f60d6da..96f2a1e 100644 --- a/frappy_psi/qnw.py +++ b/frappy_psi/qnw.py @@ -121,6 +121,7 @@ class TemperatureLoopTC1(SensorTC1, Drivable): return True self.set_param('TC', '-') return False +########### def read_ramp(self): return float(self.get_param('RR')) @@ -145,13 +146,3 @@ class TemperatureLoopTC1(SensorTC1, Drivable): def stop(self): if self.control and self.ramp_used: self.write_target(self.value) - - - - - - - - - - diff --git a/frappy_psi/thermofisher.py b/frappy_psi/thermofisher.py index 3112c6a..6f2ff10 100644 --- a/frappy_psi/thermofisher.py +++ b/frappy_psi/thermofisher.py @@ -20,90 +20,145 @@ # ***************************************************************************** from frappy.core import StringIO, Parameter, Readable, HasIO, \ - Drivable, FloatRange + Drivable, FloatRange, IDLE, ERROR, WARN, BoolType +from frappy_psi.convergence import HasConvergence class ThermFishIO(StringIO): end_of_line = '\r' - identification = [('RVER', r'.[.*')] # Firmware Version + identification = [('RVER', r'.*')] # Firmware Version class SensorA10(HasIO, Readable): - ClassIO = ThermFishIO + ioClass = ThermFishIO value = Parameter('internal temperature', unit='degC') + def get_par(self, cmd): + new_cmd = 'R' + cmd + reply = self.communicate(new_cmd) + if any(unit.isalpha() for unit in reply): + reply = ''.join(unit for unit in reply if not unit.isalpha()) + return float(reply) + + # def set_par(self, cmd, arg): + # new_cmd = 'S' + cmd.format(arg=arg) + # return self.communicate(new_cmd) + # # return self.get_par(cmd) + def read_value(self): - return self.communicate('RT') # return the value and the units without space + return self.get_par('T') - def set_par(self, cmd): + def read_status(self): + result_str = self.communicate('RUFS') + values_str = result_str.strip().split() + values_int = [int(val) for val in values_str] + v1, v2, v3, v4, v5 = values_int[:5] + + status_messages = [ + (ERROR, 'high tempr. cutout fault', v2, 0), + (ERROR, 'high RA tempr. fault', v2, 1), + (ERROR, 'high temperature fixed fault', v3, 7), + (ERROR, 'low temperature fixed fault', v3, 6), + (ERROR, 'high temperature fault', v3, 5), + (ERROR, 'low temperature fault', v3, 4), + (ERROR, 'low level fault', v3, 3), + (ERROR, 'circulator fault', v4, 5), + (ERROR, 'high press. cutout', v5, 2), + (ERROR, 'motor overloaded', v5, 1), + (ERROR, 'pump speed fault', v5, 0), + (WARN, 'open internal sensor', v1, 7), + (WARN, 'shorted internal sensor', v1, 6), + (WARN, 'high temperature warn', v3, 2), + (WARN, 'low temperature warn', v3, 1), + (WARN, 'low level warn', v3, 0), + (IDLE, 'max. heating', v5, 5), + (IDLE, 'heating', v5, 6), + (IDLE, 'cooling', v5, 4), + (IDLE, 'max cooling', v5, 3), + (IDLE, '', v4, 3), + ] + + for status_type, status_msg, vi,bit in status_messages: + if vi & (1 << bit): + return status_type, status_msg + return WARN, 'circulation off' - -class TemperatureLoopA10(SensorSC, Drivable): +class TemperatureLoopA10(HasConvergence, SensorA10, Drivable): value = Parameter('temperature', unit='degC') - target = Parameter('setpoint', FloatRange, readonly=False) - p_heat = Parameter('proportional heat parameter', FloatRange(), unit='degC', readonly=False) + target = Parameter('setpoint/target', datatype=FloatRange, unit='degC', default=0) + circ_on = Parameter('is circulation running', BoolType(), readonly=False, default=False) + # pids + p_heat = Parameter('proportional heat parameter', FloatRange(), readonly=False) i_heat = Parameter('integral heat parameter', FloatRange(), readonly=False) d_heat = Parameter('derivative heat parameter', FloatRange(), readonly=False) p_cool = Parameter('proportional cool parameter', FloatRange(), readonly=False) i_cool = Parameter('integral cool parameter', FloatRange(), readonly=False) d_cool = Parameter('derivative cool parameter', FloatRange(), readonly=False) - setpoint_num = ['', 1, 2, 3, 4, 5] + def read_circ_on(self): + return self.communicate('RO') + + def write_circ_on(self, circ_on): + circ_on_str = '1' if circ_on else '0' + self.communicate(f'SO {circ_on_str}') + return self.read_circ_on() def read_target(self): - return self.communicate(f'RS{self.setpoint_num}') + return self.get_par('S') - def write_target(self): - target = self.communicate(f'SS{self.setpoint_num} {self.target}') + def write_target(self, target): + self.write_circ_on('1') + self.communicate(f'SS {target}') + self.start_state() return target -## heat PID + ## heat PID def read_p_heat(self): - p_heat = self.communicate(f'RPH') - return p_heat + p_heat = self.get_par('PH') + return float(p_heat) def write_p_heat(self, p_heat): self.communicate(f'SPH {p_heat}') - return self.read_p_heat() + return p_heat def read_i_heat(self): - i_heat = self.communicate(f'RIH') - return i_heat + i_heat = self.get_par('IH') + return float(i_heat) def write_i_heat(self, i_heat): self.communicate(f'SIH {i_heat}') - return self.read_i_heat() + return i_heat def read_d_heat(self): - d_heat = self.communicate(f'RDH') - return d_heat + d_heat = self.get_par('DH') + return float(d_heat) def write_d_heat(self, d_heat): self.communicate(f'SDH {d_heat}') - return self.read_d_heat() + return d_heat -## cool PID + ## cool PID def read_p_cool(self): - p_cool = self.communicate(f'RPC') - return p_cool + p_cool = self.get_par('PC') + return float(p_cool) def write_p_cool(self, p_cool): self.communicate(f'SPC {p_cool}') - return self.read_p_cool() + return p_cool def read_i_cool(self): - i_cool = self.communicate(f'RIC') - return i_cool + i_cool = self.get_par('IC') + return float(i_cool) def write_i_cool(self, i_cool): self.communicate(f'SIC {i_cool}') - return self.read_i_cool() + return i_cool def read_d_cool(self): - d_cool = self.communicate(f'RDC') - return d_cool + d_cool = self.get_par('DC') + return float(d_cool) def write_d_cool(self, d_cool): self.communicate(f'SDC {d_cool}') - return self.read_d_cool() \ No newline at end of file + return d_cool