1
0
forked from M-Labs/thermostat

Move pid autotuning request to CtrlPanel

And update autotune UI only on state change instead of every single
report update
This commit is contained in:
atse 2024-08-27 16:46:48 +08:00
parent fcda46d1f3
commit b32b38d830
3 changed files with 28 additions and 35 deletions

View File

@ -1,9 +1,11 @@
from PyQt6.QtCore import QObject, pyqtSlot from PyQt6.QtCore import QObject, pyqtSlot, pyqtSignal
from qasync import asyncSlot from qasync import asyncSlot
from autotune import PIDAutotuneState, PIDAutotune from autotune import PIDAutotuneState, PIDAutotune
class PIDAutoTuner(QObject): class PIDAutoTuner(QObject):
autotune_state_changed = pyqtSignal(int, PIDAutotuneState)
def __init__(self, parent, thermostat, num_of_channel): def __init__(self, parent, thermostat, num_of_channel):
super().__init__(parent) super().__init__(parent)
@ -37,9 +39,11 @@ class PIDAutoTuner(QObject):
self.lookback[ch], self.lookback[ch],
) )
self.autotuners[ch].setReady() self.autotuners[ch].setReady()
self.autotune_state_changed.emit(ch, self.autotuners[ch].state())
async def stop_pid_from_running(self, ch): async def stop_pid_from_running(self, ch):
self.autotuners[ch].setOff() self.autotuners[ch].setOff()
self.autotune_state_changed.emit(ch, self.autotuners[ch].state())
await self._thermostat.set_param("pwm", ch, "i_set", 0) await self._thermostat.set_param("pwm", ch, "i_set", 0)
@asyncSlot(list) @asyncSlot(list)
@ -65,6 +69,7 @@ class PIDAutoTuner(QObject):
case PIDAutotuneState.STATE_SUCCEEDED: case PIDAutotuneState.STATE_SUCCEEDED:
kp, ki, kd = self.autotuners[ch].get_tec_pid() kp, ki, kd = self.autotuners[ch].get_tec_pid()
self.autotuners[ch].setOff() self.autotuners[ch].setOff()
self.autotune_state_changed.emit(ch, self.autotuners[ch].state())
await self._thermostat.set_param("pid", ch, "kp", kp) await self._thermostat.set_param("pid", ch, "kp", kp)
await self._thermostat.set_param("pid", ch, "ki", ki) await self._thermostat.set_param("pid", ch, "ki", ki)
@ -76,4 +81,5 @@ class PIDAutoTuner(QObject):
) )
case PIDAutotuneState.STATE_FAILED: case PIDAutotuneState.STATE_FAILED:
self.autotuners[ch].setOff() self.autotuners[ch].setOff()
self.autotune_state_changed.emit(ch, self.autotuners[ch].state())
await self._thermostat.set_param("pwm", ch, "i_set", 0) await self._thermostat.set_param("pwm", ch, "i_set", 0)

View File

@ -6,7 +6,7 @@ from pyqtgraph.parametertree import (
registerParameterType, registerParameterType,
) )
from qasync import asyncSlot from qasync import asyncSlot
from functools import partial from autotune import PIDAutotuneState
class MutexParameter(pTypes.ListParameter): class MutexParameter(pTypes.ListParameter):
@ -55,7 +55,6 @@ class CtrlPanel(QObject):
info_box, info_box,
trees_ui, trees_ui,
param_tree, param_tree,
sigActivated_handles,
parent=None, parent=None,
): ):
super().__init__(parent) super().__init__(parent)
@ -93,8 +92,9 @@ class CtrlPanel(QObject):
self.params[i].child("Load from flash").sigActivated.connect( self.params[i].child("Load from flash").sigActivated.connect(
partial(self.load_settings, i) partial(self.load_settings, i)
) )
for handle in sigActivated_handles[i]: self.params[i].child(
self.params[i].child(*handle[0]).sigActivated.connect(handle[1]) "PID Config", "PID Auto Tune", "Run"
).sigActivated.connect(partial(self.pid_auto_tune_request, i))
self.thermostat.pid_update.connect(self.update_pid) self.thermostat.pid_update.connect(self.update_pid)
self.thermostat.report_update.connect(self.update_report) self.thermostat.report_update.connect(self.update_report)
@ -277,3 +277,17 @@ class CtrlPanel(QObject):
f"Channel {ch} settings has been saved to flash.\n" f"Channel {ch} settings has been saved to flash.\n"
"It will be loaded on Thermostat reset, or when settings are explicitly loaded.", "It will be loaded on Thermostat reset, or when settings are explicitly loaded.",
) )
@asyncSlot()
async def pid_auto_tune_request(self, ch=0):
match self.autotuners.get_state(ch):
case PIDAutotuneState.STATE_OFF | PIDAutotuneState.STATE_FAILED:
self.autotuners.load_params_and_set_ready(ch)
case (
PIDAutotuneState.STATE_READY
| PIDAutotuneState.STATE_RELAY_STEP_UP
| PIDAutotuneState.STATE_RELAY_STEP_DOWN
):
await self.autotuners.stop_pid_from_running(ch)

View File

@ -76,28 +76,18 @@ class MainWindow(QtWidgets.QMainWindow):
self.thermostat.connection_state_changed.connect(self._on_connection_changed) self.thermostat.connection_state_changed.connect(self._on_connection_changed)
self.autotuners = PIDAutoTuner(self, self.thermostat, 2) self.autotuners = PIDAutoTuner(self, self.thermostat, 2)
self.autotuners.autotune_state_changed.connect(self.pid_autotune_handler)
def get_ctrl_panel_config(args): def get_ctrl_panel_config(args):
with open(args.param_tree, "r", encoding="utf-8") as f: with open(args.param_tree, "r", encoding="utf-8") as f:
return json.load(f)["ctrl_panel"] return json.load(f)["ctrl_panel"]
param_tree_sigActivated_handles = [
[
[
["PID Config", "PID Auto Tune", "Run"],
partial(self.pid_auto_tune_request, ch),
],
]
for ch in range(self.NUM_CHANNELS)
]
self.ctrl_panel_view = CtrlPanel( self.ctrl_panel_view = CtrlPanel(
self.thermostat, self.thermostat,
self.autotuners, self.autotuners,
self.info_box, self.info_box,
[self.ch0_tree, self.ch1_tree], [self.ch0_tree, self.ch1_tree],
get_ctrl_panel_config(args), get_ctrl_panel_config(args),
param_tree_sigActivated_handles,
) )
self.zero_limits_warning = ZeroLimitsWarningView( self.zero_limits_warning = ZeroLimitsWarningView(
@ -107,8 +97,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.zero_limits_warning.set_limits_warning self.zero_limits_warning.set_limits_warning
) )
self.thermostat.report_update.connect(self.pid_autotune_handler)
self.thermostat.hw_rev_update.connect(self._status) self.thermostat.hw_rev_update.connect(self._status)
self.report_apply_btn.clicked.connect( self.report_apply_btn.clicked.connect(
lambda: self.thermostat.set_update_s(self.report_refresh_spin.value()) lambda: self.thermostat.set_update_s(self.report_refresh_spin.value())
@ -218,23 +206,8 @@ class MainWindow(QtWidgets.QMainWindow):
else: else:
await self.thermostat.end_session() await self.thermostat.end_session()
@asyncSlot() @asyncSlot(int, PIDAutotuneState)
async def pid_auto_tune_request(self, ch=0): async def pid_autotune_handler(self, _ch, _state):
match self.autotuners.get_state(ch):
case PIDAutotuneState.STATE_OFF | PIDAutotuneState.STATE_FAILED:
self.autotuners.load_params_and_set_ready(ch)
case (
PIDAutotuneState.STATE_READY
| PIDAutotuneState.STATE_RELAY_STEP_UP
| PIDAutotuneState.STATE_RELAY_STEP_DOWN
):
await self.autotuners.stop_pid_from_running(ch)
# To Update the UI elements
self.pid_autotune_handler([])
@asyncSlot(list)
async def pid_autotune_handler(self, _):
ch_tuning = [] ch_tuning = []
for ch in range(self.NUM_CHANNELS): for ch in range(self.NUM_CHANNELS):
match self.autotuners.get_state(ch): match self.autotuners.get_state(ch):