diff --git a/flake.nix b/flake.nix index 209c7c1..db5a916 100644 --- a/flake.nix +++ b/flake.nix @@ -73,7 +73,7 @@ src = "${self}/pykirdy"; nativeBuildInputs = [ pkgs.qt6.wrapQtAppsHook ]; - propagatedBuildInputs = [ pkgs.qt6.qtbase ] ++ (with pkgs.python3Packages; [ pyqtgraph pyqt6 qasync pglive aenum]); + propagatedBuildInputs = [ pkgs.qt6.qtbase ] ++ (with pkgs.python3Packages; [ pyqtgraph pyqt6 qasync pglive aenum sipyco]); dontWrapQtApps = true; postFixup = '' @@ -94,7 +94,7 @@ buildInputs = with pkgs; [ rust openocd dfu-util glibc ] ++ (with python3Packages; [ - numpy matplotlib pyqtgraph setuptools pyqt6 qasync pglive aenum + numpy matplotlib pyqtgraph setuptools pyqt6 qasync pglive aenum sipyco ]); shellHook= '' diff --git a/pykirdy/pid_autotune.py b/pykirdy/pid_autotune.py index 8ad9580..22b3eab 100644 --- a/pykirdy/pid_autotune.py +++ b/pykirdy/pid_autotune.py @@ -8,6 +8,7 @@ import time import signal from driver.kirdy import Kirdy, FilterConfig import asyncio +from sipyco.asyncio_tools import SignalHandler # Based on hirshmann pid-autotune libiary # See https://github.com/hirschmann/pid-autotune @@ -76,6 +77,10 @@ class PIDAutotune: def setOff(self): self._state = PIDAutotuneState.STATE_OFF + def setFailed(self): + self._state = PIDAutotuneState.STATE_FAILED + self._peak_count = 30 + def state(self): """Get the current state.""" return self._state @@ -246,7 +251,7 @@ class PIDAutotune: return False -def main(): +async def main(): """ PID AutoTune Tools for Kirdy The obtained temperature works best at the target temperature specified. @@ -271,46 +276,46 @@ def main(): noiseband = 2.0 kirdy = Kirdy() - kirdy.start_session(host='192.168.1.128', port=1337) + kirdy.start_session(host='192.168.1.126', port=1337) + + await kirdy.wait_until_connected() while not(kirdy.connected()): pass - kirdy.laser.set_power_on(False) - kirdy.laser.set_i(0) + await kirdy.laser.set_power_on(False) + await kirdy.laser.set_i(0) - kirdy.thermostat.set_power_on(False) - kirdy.thermostat.set_constant_current_control_mode() - kirdy.thermostat.set_tec_i_out(0) - kirdy.thermostat.clear_alarm() + 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() - - kirdy.device.set_active_report_mode(False) + signal_handler.setup() + async def sig_handling(): + await signal_handler.wait_terminate() + tuner.setFailed() + asyncio.create_task(sig_handling()) + + await kirdy.device.set_active_report_mode(False) # Configure the Thermistor Parameters - kirdy.thermostat.set_sh_beta(3950) - kirdy.thermostat.set_sh_r0(10.0 * 1000) - kirdy.thermostat.set_sh_t0(25) + await kirdy.thermostat.set_sh_beta(3950) + 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 - kirdy.thermostat.set_temp_mon_upper_limit(target_temperature + 20) - kirdy.thermostat.set_temp_mon_lower_limit(target_temperature - 20) + await kirdy.thermostat.set_temp_mon_upper_limit(target_temperature + 20) + await kirdy.thermostat.set_temp_mon_lower_limit(target_temperature - 20) - kirdy.thermostat.set_tec_max_cooling_i(output_step) - kirdy.thermostat.set_tec_max_heating_i(output_step) + await kirdy.thermostat.set_tec_max_cooling_i(output_step) + await kirdy.thermostat.set_tec_max_heating_i(output_step) # The Polling Rate of Temperature Adc is equal to the PID Update Interval - kirdy.thermostat.config_temp_adc_filter(FilterConfig.Sinc5Sinc1With50hz60HzRejection.f16sps) - settings = kirdy.device.get_settings_summary() + await kirdy.thermostat.config_temp_adc_filter(FilterConfig.Sinc5Sinc1With50hz60HzRejection.f16sps) + settings = await kirdy.device.get_settings_summary() sampling_rate = settings["thermostat"]["temp_adc_settings"]["rate"] print("Settings: {0}".format(settings)) @@ -318,10 +323,10 @@ def main(): tuner = PIDAutotune(target_temperature, output_step, lookback, noiseband, 1/sampling_rate) - kirdy.thermostat.set_power_on(True) + await kirdy.thermostat.set_power_on(True) - while True and signal_handler.KEEP_PROCESSING: - status_report = kirdy.device.get_status_report() + while True: + status_report = await kirdy.device.get_status_report() temperature = status_report["thermostat"]["temperature"] ts = status_report['ts'] @@ -332,19 +337,20 @@ def main(): break tuner_out = tuner.output() - kirdy.thermostat.set_tec_i_out(float(tuner_out)) + await kirdy.thermostat.set_tec_i_out(float(tuner_out)) - kirdy.thermostat.set_tec_i_out(0) - kirdy.thermostat.set_power_on(False) + await kirdy.thermostat.set_tec_i_out(0) + await kirdy.thermostat.set_power_on(False) - pid_params = tuner.get_pid_parameters(tuning_rule="tyreus-luyben") - kirdy.thermostat.set_pid_kp(pid_params.Kp) - kirdy.thermostat.set_pid_ki(pid_params.Ki) - kirdy.thermostat.set_pid_kd(pid_params.Kd) - kirdy.thermostat.set_pid_output_max(1.0) - kirdy.thermostat.set_pid_output_min(1.0) + if tuner.state() == PIDAutotuneState.STATE_SUCCEEDED: + pid_params = tuner.get_pid_parameters(tuning_rule="tyreus-luyben") + await kirdy.thermostat.set_pid_kp(pid_params.Kp) + await kirdy.thermostat.set_pid_ki(pid_params.Ki) + await kirdy.thermostat.set_pid_kd(pid_params.Kd) + await kirdy.thermostat.set_pid_output_max(1.0) + await kirdy.thermostat.set_pid_output_min(1.0) - kirdy.end_session(block=True) + await kirdy.end_session() if __name__ == "__main__": - main() + asyncio.run(main())