class RelayMax6675BangBangModule(ArduinoBoardModule): max6675 = Max6675BoardModule relay = DutyCycleBoardModule pid = PIDModule target_temperature = python_variable( "target_temperature", type=np.float, default=300.0 ) max_temperature = python_variable( "max_temperature", type=np.float, default=300, minimum=0 ) min_temperature = python_variable("min_temperature", type=np.float) running = python_variable("running", type=np.bool, default=False, save=False) def post_initalization(self): self.max6675.temperature.data_point_modification(self.bang_bang_temperature) self.relay.duty_cycle.is_data_point = True self.relay.duty_cycle.changeable = False self.pid.minimum = self.relay.duty_cycle.minimum self.pid.maximum = self.relay.duty_cycle.maximum def bang_bang_temperature(self, data): self.pid.current = data self.pid.target = self.target_temperature if self.running: pid = self.pid.pid() if pid is None: pid = 0 self.relay.duty_cycle = pid else: self.pid.reset() self.relay.duty_cycle = 0 return data
class ThermistorBoard2(ThermistorBoard, AnalogReadBoard2): FIRMWARE = 15650180050147573 thermistor_base_resistance2 = arduio_variable( name="thermistor_base_resistance2", arduino_data_type=uint32_t, eeprom=True, default=10**5, ) reference_resistance2 = arduio_variable( name="reference_resistance2", arduino_data_type=uint32_t, eeprom=True, default=10**5, ) temperature2 = python_variable("temperature2", type=np.float, changeable=False, is_data_point=True, save=False) reference_temperature2 = python_variable("reference_temperature2", type=np.float, default=298.15, minimum=0) a2 = python_variable("a2", type=np.float, default=1.009249522e-03) b2 = python_variable("b2", type=np.float, default=2.378405444e-04) c2 = python_variable("c2", type=np.float, default=2.019202697e-07) def pre_ini_function(self): super().pre_ini_function() self.thermistor_base_resistance.name = ( self.thermistor_base_resistance.name + "1") self.reference_resistance.name = self.reference_resistance.name + "1" self.temperature.name = self.temperature.name + "1" self.reference_temperature.name = self.reference_temperature.name + "1" self.a.name = self.a.name + "1" self.b.name = self.b.name + "1" self.c.name = self.c.name + "1" self.analog_value2.name = self.analog_value.name + "2" self.analog_value.name = self.analog_value.name + "1" self.analog_value2.setter = self.resistance_to_temperature2 @staticmethod def resistance_to_temperature2(var, instance, data, send_to_board=True): var.default_setter(var=var, instance=instance, data=data, send_to_board=send_to_board) try: R2 = instance.reference_resistance2 * (1023.0 - data) / data logR2 = np.log(R2) T = 1.0 / (instance.a2 + instance.b2 * logR2 + instance.c2 * logR2 * logR2 * logR2) instance.temperature2 = T except ZeroDivisionError: pass
class ThermistorBoardModule(ArduinoBoardModule): analog_read_module = AnalogReadModule # analog_read_module.analog_value.is_data_point = False # arduino_variables thermistor_base_resistance = arduio_variable( name="thermistor_base_resistance", arduino_data_type=uint32_t, eeprom=True, default=10 ** 5, ) reference_resistance = arduio_variable( name="reference_resistance", arduino_data_type=uint32_t, eeprom=True, default=10 ** 5, ) # python_variables temperature = python_variable( "temperature", type=np.float, changeable=False, is_data_point=True, save=False ) reference_temperature = python_variable( "reference_temperature", type=np.float, default=298.15, minimum=0 ) b = python_variable("b", type=np.uint32, default=4000) # a = python_variable("a", type=np.float,default=1.009249522) # b = python_variable("b", type=np.float,default=2.378405444) # c = python_variable("c", type=np.float,default=2.019202697) @classmethod def module_arduino_code(cls, board, arduino_code_creator): arduino_code_creator.setup.add_call(Arduino.analogReference(Arduino.EXTERNAL)) def post_initalization(self): self.analog_read_module.analog_value.data_point_modification( self.resistance_to_temperature ) def resistance_to_temperature(self, data): try: R2 = self.reference_resistance * data / (1023.0 - data) Tk = R2 / self.thermistor_base_resistance Tk = np.log(Tk) Tk /= self.b Tk += 1 / self.reference_temperature Tk = 1 / Tk self.temperature = Tk except ZeroDivisionError: pass return data
class PIDModule(ArduinoBoardModule): # depencies basic_board_module = BasicBoardModule target = 0 current = 0 minimum = 0 maximim = 0 # python_variables kp = python_variable("kp", type=np.float, html_attributes={"step": 0.1}, minimum=0) ki = python_variable("ki", type=np.float, html_attributes={"step": 0.001}, minimum=0) kd = python_variable("kd", type=np.float, html_attributes={"step": 0.01}, minimum=0) # arduino_variables def post_initalization(self): self._last_time = _current_time() self._last_input = None self._integral = 0 def instance_arduino_code(self, ad): ad.loop.add_call() ad.setup.add_call() self.basic_board_module.dataloop.add_call() def crop(self, value): return min(self.maximum, max(self.minimum, value)) def reset(self): self._last_time = None self._last_input = None self._integral = 0 def pid(self): if self._last_input is None: self._last_time = _current_time() time.sleep(0.01) now = _current_time() if now - self._last_time: dt = now - self._last_time else: return None error = self.target - self.current d_input = self.current - (self._last_input if self._last_input is not None else self.current) # compute integral and derivative terms proportional = self.kp * error self._integral += self.ki * error * dt self._integral = self.crop(self._integral) # avoid integral windup derivative = -self.kd * d_input / dt # compute final output output = proportional + self._integral + derivative output = self.crop(output) self._last_input = self.current self._last_time = now if output is None: if self.minimum is None: return 0 return self.minimum return output
class RelayThermistorBoard(ThermistorBoard, RelayBoard): FIRMWARE = 15650261815701852 target_temperature = python_variable("target_temperature", type=np.float, default=298.15, minimum=0) max_temperature = python_variable("max_temperature", type=np.float, default=500, minimum=0) min_temperature = python_variable("min_temperature", type=np.float, default=0, minimum=0) max_on_time = 100 min_on_time = 0 threshold = python_variable("threshold", type=np.float, default=50, minimum=0, maximum=100) running = python_variable("running", type=np.bool, default=False, save=False) kp = python_variable("kp", type=np.float, default=1) ki = python_variable("ki", type=np.float) kd = python_variable("kd", type=np.float) def __init__(self): super().__init__() self.get_module_var_by_name("temperature").setter = pdi_temperature self._last_time = _current_time() self._last_input = None self._integral = 0 def reset(self): self._last_time = _current_time() self._last_input = None self._integral = 0 def pid(self, input): if self._last_input is None: self._last_time = _current_time() time.sleep(0.01) now = _current_time() if now - self._last_time: dt = now - self._last_time else: return None error = self.target_temperature - input d_input = input - (self._last_input if self._last_input is not None else input) # compute integral and derivative terms proportional = self.kp * error self._integral += self.ki * error * dt self._integral = min(self.max_on_time, max(self.min_on_time, self._integral)) # avoid integral windup derivative = -self.kd * d_input / dt # compute final output output = proportional + self._integral + derivative output = min(self.max_on_time, max(self.min_on_time, output)) self._last_input = input self._last_time = now return output
class RelayThermistorModule(ArduinoBoardModule): thermistor = ThermistorBoardModule relay = RelayBoardModule target_temperature = python_variable("target_temperature", type=np.float, default=298.15) max_temperature = python_variable("max_temperature", type=np.float, default=300, minimum=0) min_temperature = python_variable("min_temperature", type=np.float) max_on_time = 100 min_on_time = 0 threshold = python_variable("threshold", type=np.float, default=50, minimum=0, maximum=100) running = python_variable("running", type=np.bool, default=False, save=False) kp = python_variable("kp", type=np.float, default=1) ki = python_variable("ki", type=np.float) kd = python_variable("kd", type=np.float) def post_initalization(self): self.thermistor.temperature.setter = self.pdi_temperature self._last_time = _current_time() self._last_input = None self._integral = 0 def pdi_temperature(self, var, instance, data): kelvin = var.default_setter(var=var, instance=instance, data=data) target = self.target_temperature print("kelvin", kelvin, "target", target) if self.running: on_time = self.pid(data, target) if on_time is not None: if on_time > self.threshold: self.relay.active = False else: self.relay.active = True else: self.reset() def reset(self): self._last_time = _current_time() self._last_input = None self._integral = 0 def pid(self, input, target): if self._last_input is None: self._last_time = _current_time() time.sleep(0.01) now = _current_time() if now - self._last_time: dt = now - self._last_time else: return None error = target - input d_input = input - (self._last_input if self._last_input is not None else input) # compute integral and derivative terms proportional = self.kp * error self._integral += self.ki * error * dt self._integral = min(self.max_on_time, max(self.min_on_time, self._integral)) # avoid integral windup derivative = -self.kd * d_input / dt # compute final output output = proportional + self._integral + derivative output = min(self.max_on_time, max(self.min_on_time, output)) self._last_input = input self._last_time = now return output