wip(temperature_controller)
This commit is contained in:
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"""
|
||||
|
||||
|
||||
Reference in new issue
Block a user