From c06491a8b21984f945183f9283c429a2c674dca7 Mon Sep 17 00:00:00 2001 From: linuswck Date: Mon, 18 Mar 2024 13:26:23 +0800 Subject: [PATCH] Update PID Autotune Code --- pykirdy/pid_autotune.py | 136 +++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/pykirdy/pid_autotune.py b/pykirdy/pid_autotune.py index ea33c7c..e73d43c 100644 --- a/pykirdy/pid_autotune.py +++ b/pykirdy/pid_autotune.py @@ -6,6 +6,8 @@ import socket import json import time import signal +from driver.kirdy_async import Kirdy +import asyncio # Based on hirshmann pid-autotune libiary # See https://github.com/hirschmann/pid-autotune @@ -219,92 +221,96 @@ class PIDAutotune: return True return False -tec_power_up = { - "thermostat_cmd": "PowerUp", -} -tec_power_down = { - "thermostat_cmd": "PowerDown", -} +async def main(): + """ + PID AutoTune Tools for Kirdy + The obtained temperature works best at the target temperature specified. + Before running PID AutoTune, please + 1. Secure the laser diode onto the LD adapter and copper heat sink + 2. Make sure Kirdy has warmed up and reached thermal equilibrium state + + In case of PID Autotune Failure, you can + 1. Run the PID Autotune again + 2. Or increase the lookback period + 3. Or increase the sampling rate + """ -kirdy_get_status_report = { - "device_cmd": "GetStatusReport", -} - -tec_get_tec_status = { - "thermostat_cmd": "GetTecStatus", -} - -tec_pid_dis_engage = { - "thermostat_cmd": "SetPidDisEngage", -} - -tec_set_i_out = { - "tec_set_i": 0.0, -} - -# Kirdy IP and Port Number -HOST = "192.168.1.132" -PORT = 1337 -SAMPLING_RATE = 16.67 - -def send_cmd(input, socket): - socket.send(bytes(json.dumps(input), "UTF-8")) - time.sleep(0.5) - -def read_cmd(input, socket): - socket.send(bytes(json.dumps(input), "UTF-8")) - data = socket.recv(1024).decode('utf8') - return json.loads(data) - -def main(): # Target temperature of the autotune routine, celsius target_temperature = 20 # Value by which output will be increased/decreased from zero, amps output_step = 1 # Reference period for local minima/maxima, seconds - lookback = 1 + lookback = 2.0 # Determines by how much the input value must # overshoot/undershoot the setpoint, celsius noiseband = 1.5 + kirdy = Kirdy() + await kirdy.start_session(host='192.168.1.128', port=1337, timeout=0.25) + + await kirdy.laser.set_power_on(False) + await kirdy.laser.set_i(0) + + await kirdy.thermostat.set_power_on(False) + await kirdy.thermostat.set_constant_current_control_mode() + await kirdy.thermostat.set_tec_i_out(0) + await kirdy.thermostat.clear_alarm() + + class SignalHandler: + KEEP_PROCESSING = True + def __init__(self): + signal.signal(signal.SIGINT, self.exit_gracefully) + signal.signal(signal.SIGTERM, self.exit_gracefully) + + def exit_gracefully(self, signum, frame): + self.KEEP_PROCESSING = False + signal_handler = SignalHandler() + + await kirdy.device.set_active_report_mode(False) + + # Configure the Thermistor Parameters + await kirdy.thermostat.set_sh_beta(3900) + await kirdy.thermostat.set_sh_r0(10.0 * 1000) + await kirdy.thermostat.set_sh_t0(25) + + # Set a large enough temperature range so that it won't trigger overtemperature protection + await kirdy.thermostat.set_temp_mon_upper_limit(target_temperature + 20) + await kirdy.thermostat.set_temp_mon_lower_limit(target_temperature - 20) + + await kirdy.thermostat.set_tec_max_i_pos(output_step) + await kirdy.thermostat.set_tec_max_i_neg(output_step) + + # The Polling Rate of Temperature Adc is equal to the PID Update Interval + await kirdy.thermostat.config_temp_adc_filter("Sinc5Sinc1With50hz60HzRejection", "F16SPS") + settings = await kirdy.device.get_settings_summary() + sampling_rate = settings["thermostat"]["temp_adc_settings"]["rate"] + + print("Settings: {0}".format(settings)) + tuner = PIDAutotune(target_temperature, output_step, - lookback, noiseband, 1/SAMPLING_RATE) + lookback, noiseband, 1/sampling_rate) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + await kirdy.thermostat.set_power_on(True) - def signal_handler(sig, frame): - send_cmd(tec_power_down, s) - s.close() - exit() - - signal.signal(signal.SIGINT, signal_handler) - - s.connect((HOST, PORT)) - - send_cmd(tec_pid_dis_engage, s) - send_cmd(tec_power_down, s) - send_cmd(tec_power_up, s) - - while True: - status_report = read_cmd(kirdy_get_status_report, s) + while True and signal_handler.KEEP_PROCESSING: + status_report = await kirdy.device.get_status_report() - temperature = status_report["tec"]["temperature"] - 273.15 - print(temperature) + temperature = status_report["thermostat"]["temperature"] ts = status_report['ts'] + print("Ts: {0} Current Temperature: {1} degree".format(ts, temperature)) if (tuner.run(temperature, ts / 1000.0)): + print(tuner._state) break tuner_out = tuner.output() - - tec_set_i_out["tec_set_i"] = float(tuner_out * 1000.0) - - send_cmd(tec_set_i_out, s) + await kirdy.thermostat.set_tec_i_out(float(tuner_out)) - tec_set_i_out["tec_set_i"] = 0.0 - send_cmd(tec_power_down, s) - s.close() + await kirdy.thermostat.set_tec_i_out(0) + await kirdy.thermostat.set_power_on(False) + + await kirdy.end_session() if __name__ == "__main__": - main() + asyncio.run(main())