This commit is contained in:
atse 2023-08-30 15:23:03 +08:00
parent c9e8c4f4a1
commit 4635e71ebf
2 changed files with 65 additions and 2 deletions

View File

@ -14,5 +14,5 @@ setup(
"tec_qt = tec_qt:main", "tec_qt = tec_qt:main",
] ]
}, },
py_modules=['tec_qt', 'ui_tec_qt'], py_modules=['tec_qt', 'ui_tec_qt', 'autotune'],
) )

View File

@ -15,6 +15,7 @@ import asyncio
from pytec.aioclient import Client, StoppedConnecting from pytec.aioclient import Client, StoppedConnecting
import qasync import qasync
from qasync import asyncSlot, asyncClose from qasync import asyncSlot, asyncClose
from autotune import PIDAutotune, PIDAutotuneState
# pyuic6 -x tec_qt.ui -o ui_tec_qt.py # pyuic6 -x tec_qt.ui -o ui_tec_qt.py
from ui_tec_qt import Ui_MainWindow from ui_tec_qt import Ui_MainWindow
@ -257,7 +258,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
{'name': 'Target Temperature', 'type': 'float', 'value': 20, 'step': 0.1, 'siPrefix': True, 'suffix': '°C'}, {'name': 'Target Temperature', 'type': 'float', 'value': 20, 'step': 0.1, 'siPrefix': True, 'suffix': '°C'},
{'name': 'Test Current', 'type': 'float', 'value': 1, 'step': 0.1, 'siPrefix': True, 'suffix': 'A'}, {'name': 'Test Current', 'type': 'float', 'value': 1, 'step': 0.1, 'siPrefix': True, 'suffix': 'A'},
{'name': 'Temperature Swing', 'type': 'float', 'value': 1.5, 'step': 0.1, 'siPrefix': True, 'prefix': '±', 'suffix': '°C'}, {'name': 'Temperature Swing', 'type': 'float', 'value': 1.5, 'step': 0.1, 'siPrefix': True, 'prefix': '±', 'suffix': '°C'},
{'name': 'Run', 'type': 'action', 'tip': 'Run'}, {'name': 'Run', 'type': 'action', 'tip': 'Run', 'children': [
{'name': 'Autotuning...', 'type': 'progress', 'value': 0, 'readonly': True, 'visible': False},
]},
]}, ]},
]}, ]},
{'name': 'Save to flash', 'type': 'action', 'tip': 'Save config to thermostat, applies on reset'}, {'name': 'Save to flash', 'type': 'action', 'tip': 'Save config to thermostat, applies on reset'},
@ -299,6 +302,11 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
for ch in range(2) for ch in range(2)
] ]
self.autotuners = [
PIDAutotune(25)
for _ in range(2)
]
self.hw_rev_data = None self.hw_rev_data = None
if args.connect: if args.connect:
@ -656,6 +664,61 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.params[i].child('Load from flash').sigActivated.connect(load) self.params[i].child('Load from flash').sigActivated.connect(load)
@asyncSlot()
async def autotune(param, ch=i):
match self.autotuners[ch].state():
case PIDAutotuneState.STATE_OFF:
self.autotuners[ch].setParam(
param.parent().child('Target Temperature').value(),
param.parent().child('Test Current').value(),
param.parent().child('Temperature Swing').value(),
self.report_refresh_spin.value(),
3)
self.autotuners[ch].setReady()
param.child('Autotuning...').show(True)
param.setOpts(title="Stop")
self.client_watcher.report_update.connect(self.autotune_tick)
case PIDAutotuneState.STATE_READY | PIDAutotuneState.STATE_RELAY_STEP_UP | PIDAutotuneState.STATE_RELAY_STEP_DOWN:
self.autotuners[ch].setOff()
param.child('Autotuning...').hide()
param.setOpts(title="Run")
await self.client.set_param('pwm', ch, 'i_set', 0)
self.client_watcher.report_update.disconnect(self.autotune_tick)
param.child('Autotuning...').setValue(0)
self.params[i].child('PID Config', 'PID Auto Tune', 'Run').sigActivated.connect(autotune)
@asyncSlot(list)
async def autotune_tick(self, report):
for channel_report in report:
channel = channel_report['channel']
match self.autotuners[channel].state():
case PIDAutotuneState.STATE_READY | PIDAutotuneState.STATE_RELAY_STEP_UP | PIDAutotuneState.STATE_RELAY_STEP_DOWN:
self.autotuners[channel].run(channel_report['temperature'], channel_report['time'])
progress_bar = self.params[channel].child('PID Config', 'PID Auto Tune', 'Run', 'Autotuning...')
if progress_bar.value() < 99:
progress_bar.setValue(progress_bar.value() + 1) # TODO: Measure the progress better
await self.client.set_param('pwm', channel, 'i_set', self.autotuners[channel].output())
case PIDAutotuneState.STATE_SUCCEEDED:
kp, ki, kd = self.autotuners[channel].get_tec_pid()
self.autotuners[channel].setOff()
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run').setOpts(title="Run")
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run', 'Autotuning...').hide()
await self.client.set_param('pid', channel, 'kp', kp)
await self.client.set_param('pid', channel, 'ki', ki)
await self.client.set_param('pid', channel, 'kd', kd)
await self.client.set_param('pwm', channel, 'pid')
await self.client.set_param('pid', channel, 'target', self.params[channel].child("PID Config", "PID Auto Tune", "Target Temperature").value())
self.client_watcher.report_update.disconnect(self.autotune_tick)
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run', 'Autotuning...').setValue(0)
case PIDAutotuneState.STATE_FAILED:
self.autotuners[channel].setOff()
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run', 'Autotuning...').hide()
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run').setOpts(title="Run")
await self.client.set_param('pwm', channel, 'i_set', 0)
self.client_watcher.report_update.disconnect(self.autotune_tick)
self.params[channel].child('PID Config', 'PID Auto Tune', 'Run', 'Autotuning...').setValue(0)
@pyqtSlot(list) @pyqtSlot(list)
def update_pid(self, pid_settings): def update_pid(self, pid_settings):
for settings in pid_settings: for settings in pid_settings: