wip(temperature_controller)
CI for debye_bec / test (pull_request) Failing after 43s
CI for debye_bec / test (push) Failing after 47s

This commit is contained in:
hitz_s committed 2026-10-26 15:29:39 +01:00
1 parent 7bb9f6300c
commit cff6b9d695
2 files changed
+101 -9

No files matched your search

@@ -18,25 +18,28 @@ from bec_widgets.widgets.plots.waveform.waveform import Waveform
# pylint: disable=E0611
from qtpy.QtCore import QTimer
from qtpy.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QWidget
from qtpy.QtWidgets import QApplication, QHBoxLayout, QLabel, QVBoxLayout, QWidget
from ....devices.univ_temp_cont.univ_temp_cont_enums import (
POWER_MAP,
RAMP_RATE_MAP,
THERMOCOUPLE_MAP,
UnivTempContAutoTune,
UnivTempContHeaterTcFault,
UnivTempContOpMode,
UnivTempContPower,
UnivTempContRampRateUnit,
UnivTempContSensorBreak,
)
from .qt_widgets import ComboBox, Group, InputNumberField, NumberIndicator, TextIndicator
from .qt_widgets import Button, ComboBox, Group, InputNumberField, NumberIndicator, TextIndicator
logger = bec_logger.logger
DEVICE_NAME = "univ_temp_cont"
DEFAULT_WINDOW_S = 600
REFRESH_MS = 200
MAX_WINDOW_S = 36000
REFRESH_MS = 500
PLOT_SIGNALS = ["temperature", "setpoint", "output_power"]
READ_CONFIG_SIGNAL_MS = 1000
@@ -108,14 +111,54 @@ class TemperatureController(BECWidget, QWidget):
],
)
self.pid_pb = InputNumberField("pb", "PB", decimals=0, single_step=1, ll=1, hl=9999)
self.pid_ti = InputNumberField(
"ti", "TI", decimals=0, single_step=1, ll=0, hl=9999, unit="s"
)
self.pid_td = InputNumberField(
"td", "TD", decimals=0, single_step=1, ll=0, hl=9999, unit="s"
)
self.autotune = Button("Autotune", "Start", enabled=True, color="success")
self.autotune_status = TextIndicator("Autotune Status")
pid_loop_group = Group(
"PID loop", [self.pid_pb, self.pid_ti, self.pid_td, self.autotune, self.autotune_status]
)
self.tc_info = QLabel("Controller will restart when changing value")
self.thermocouple = ComboBox("thermocouple", "Thermocouple", THERMOCOUPLE_MAP.keys())
configuration_group = Group("Configuration", [self.tc_info, self.thermocouple])
control_layout.addWidget(status_group)
control_layout.addWidget(control_group)
control_layout.addWidget(pid_loop_group)
control_layout.addWidget(configuration_group)
control_layout.addStretch()
root_layout.addLayout(control_layout)
waveform_layout = QVBoxLayout()
self.waveform = Waveform(parent=self, client=self.client, popups=True)
root_layout.addWidget(self.waveform, stretch=1)
waveform_layout.addWidget(self.waveform, stretch=1)
self.user_window_s = InputNumberField(
"",
"Plot range",
"s",
init=DEFAULT_WINDOW_S,
decimals=0,
single_step=60,
ll=1,
hl=MAX_WINDOW_S,
)
waveform_layout.addWidget(self.user_window_s)
root_layout.addLayout(waveform_layout, stretch=1)
self.waveform.set(title="", x_label="Time")
self.waveform.enable_toolbar = False
@@ -146,6 +189,11 @@ class TemperatureController(BECWidget, QWidget):
self.target_setpoint.editing_finished_connect(self._on_value_changed)
self.ramp_rate.editing_finished_connect(self._on_value_changed)
self.ramp_rate_unit.activated_connect(self._on_value_changed)
self.pid_pb.editing_finished_connect(self._on_value_changed)
self.pid_ti.editing_finished_connect(self._on_value_changed)
self.pid_td.editing_finished_connect(self._on_value_changed)
self.autotune.clicked_connect(self._start_stop_autotune)
self.thermocouple.activated_connect(self._on_value_changed)
self.plot_init = True
@@ -158,6 +206,12 @@ class TemperatureController(BECWidget, QWidget):
signal = getattr(self.dev.univ_temp_cont, kwargs["identifier"])
signal.put(value)
@SafeSlot()
def _start_stop_autotune(self, *_):
signal = getattr(self.dev.univ_temp_cont, "autotune")
val = signal.read()["autotune"]["value"]
signal.put(not val)
@SafeSlot(dict, dict)
def _on_readback(self, msg: dict, *_):
signals = msg.get("signals", {})
@@ -229,25 +283,57 @@ class TemperatureController(BECWidget, QWidget):
self.ramp_rate.set_number(value)
def _config_signal_read(self):
# Ramp rate unit
value = self.dev.univ_temp_cont.ramp_rate_unit.read()
if value is None:
raise TemperatureControllerError("Reading ramp rate unit returned None!")
index = value[DEVICE_NAME + "_ramp_rate_unit"]["value"]
self.ramp_rate_unit.setCurrentIndex(index)
self.ramp_rate.setUnit(
list(RAMP_RATE_MAP.keys())[list(RAMP_RATE_MAP.values()).index(index)]
)
# PB
value = self.dev.univ_temp_cont.pb.read()[DEVICE_NAME + "_pb"]["value"]
self.pid_pb.set_number(value)
# TI
value = self.dev.univ_temp_cont.ti.read()[DEVICE_NAME + "_ti"]["value"]
self.pid_ti.set_number(value)
# TD
value = self.dev.univ_temp_cont.td.read()[DEVICE_NAME + "_td"]["value"]
self.pid_td.set_number(value)
# Autotune
value = self.dev.univ_temp_cont.autotune.read()
index = value[DEVICE_NAME + "_autotune"]["value"]
match index:
case UnivTempContAutoTune.NOTUNE:
self.autotune.setText("Start")
self.autotune.setColor("success")
self.autotune_status.setText("Not active")
self.autotune_status.setColor("default")
case UnivTempContAutoTune.TUNE:
self.autotune.setText("Stop")
self.autotune.setColor("emergency")
self.autotune_status.setText("Active")
self.autotune_status.setColor("warning")
case _:
raise TemperatureControllerError(f"Not implemented autotune value {index}")
# Thermocouple
value = self.dev.univ_temp_cont.thermocouple.read()
index = value[DEVICE_NAME + "_thermocouple"]["value"]
self.thermocouple.setCurrentIndex(index)
def _redraw(self):
now = time.time()
cutoff = now - self._window_s
cutoff = now - MAX_WINDOW_S
view_cutoff = now - min(self.user_window_s.value(), MAX_WINDOW_S)
for key, buf in self._buffers.items():
while buf and buf[0][0] < cutoff:
buf.popleft()
if not buf:
continue
t, v = zip(*buf)
self._curves[key].set_data(np.asarray(t), np.asarray(v))
t, v = map(np.asarray, zip(*buf))
i = np.searchsorted(t, view_cutoff, side="left")
self._curves[key].set_data(t[i:], v[i:])
if len(self._buffers[PLOT_SIGNALS[0]]) > 0 and self.plot_init:
self.plot_init = False
self.waveform.plot_item.enableAutoRange(axis=pg.ViewBox.XYAxes, enable=True)
@@ -54,6 +54,12 @@ class UnivTempContThermocouple(int, Enum):
Type_K = 1
THERMOCOUPLE_MAP = {
"Type J": UnivTempContThermocouple.TYPE_J,
"Type K": UnivTempContThermocouple.Type_K,
}
class UnivTempContPower(int, Enum):
"""Class for power mode"""