Source code for device.trap_cathode
import serial
from . import base
import re
import time
# TODO
# - 1. upload modified arduino code
# - 2. test and adjust calibration file ("calibrations/calib_trap.cfg")
[docs]
class TrapCathodeHeater(base.ArduinoMotorsBase):
"""Arduino based motor controller (trap experiment), which controls the
autotransformator output. Also there are two power relays.
Communication:
- serial interface to Arduino
"""
def __init__(self, calibfile, bus, limits_enabled=True, **kwargs):
super().__init__(calibfile, [bus], limits_enabled, **kwargs)
self._last = {
"switched_on": False
}
# ==== Inherited abstract methods ====
def _defaultstate(self):
self._position = {key: 0 for key in self._ardu}
self._last = {
"current": 0.0,
"trafo_on": False,
"softstart_on": False,
}
def _safestate(self):
"""Cut cathode power, stop motor and request new homing."""
self.switch_output_off()
super()._safestate()
self._homed = False
# ==== Private commands ====
# Overriding parent function - There are no sensors of position so we need
# to manage the self._position property manually.
@base.compound_command
def _move(self, motor_id, distance, check_limits=True):
super()._move(motor_id, distance, check_limits)
self._position[motor_id] += distance
# ==== Commands ====
[docs]
@base.compound_command
def homing(self):
super().homing()
self._position["zhaveni"] = 0.0
[docs]
def current(self):
"Return the current in cathode"
self._idleupdate_position("zhaveni")
self._idleupdate_other()
return self._last["current"]
[docs]
@base.compound_command
def moveto(self, position):
"""Move motor to position [mm]."""
if not self.is_output_on():
raise base.CommandError("Switch-on output first")
super().moveto("zhaveni", position)
[docs]
@base.compound_command
def set_current(self, current):
"""Set output transformator current [A] by moving the motor."""
if not self.is_output_on():
raise base.CommandError("Switch-on output first")
current = float(current)
if not (0 <= current <= 30):
raise base.CommandError("Current out of range (0-30A)")
for _ in range(3):
self.moveto(
self.position("zhaveni")
+ (current-self.current()) / (45 / 3.5) # 45A is cca 3.5mm
)
time.sleep(0.2)
if abs(self.current() - current) < 1:
break
[docs]
def is_output_on(self):
"""Return the state of relay that powers transformator."""
return self._last["trafo_on"]
[docs]
@base.base_command
def switch_output_on(self):
if not self.is_homed():
raise base.CommandError("Homing required")
if not self._last["trafo_on"]:
self._ardu["zhaveni"].write(b"t")
self._read_serial("zhaveni") # "Trafo 1\r\n"
time.sleep(1.5)
self._read_serial("zhaveni") # "Soft Start 1\r\n"
self._idleupdate_other()
[docs]
@base.base_command
def switch_output_off(self):
if self._last["trafo_on"]:
self._ardu["zhaveni"].write(b"t")
self._read_serial("zhaveni") # "Trafo 0\r\n"
time.sleep(1.5)
self._read_serial("zhaveni") # "Soft Start 0\r\n"
self._idleupdate_other()
self._homed = False
# ==== Related to DeviceClient ====
@base.idle_command
def _idleupdate_other(self):
self._ardu["zhaveni"].write(b"q")
# Ignore any left-over lines
line = ""
while "Proud" not in line:
line = self._read_serial("zhaveni")
# Then parse various states
#
# "Proud 1.23 A "
# "Trafo 1"
# "Soft Start 0"
parsed = re.search(r"Proud ([0-9]+\.[0-9]+) A", line)
self._last["current"] = float(parsed.group(1))
self._last["trafo_on"] = self._read_serial("zhaveni")[-1] == "1"
self._last["softstart_on"] = self._read_serial("zhaveni")[-1] == "1"
[docs]
def update_frontend(self, device_client):
self._idleupdate_position("zhaveni") # This serves no purpose (no position sensors)
self._idleupdate_other()
if self._last["current"] > 30:
self.log.warning("Tripped 30A current limit, stopping")
self.to_safestate()
value = self.position("zhaveni")
device_client.emit("value", {
"value": value,
"formatted": "{:.2f} mm".format(value),
"label": "Motor",
"min": min(self.limits("zhaveni")),
"max": max(self.limits("zhaveni")),
"id": "position_" + "zhaveni"
})
value = self._last["current"]
device_client.emit("value", {
"value": value,
"formatted": "{:.2f} A".format(value),
"label": "Current",
"min": 0,
"max": 100, # TODO Adjust as needed
"id": "current",
})
value = self._last["trafo_on"]
device_client.emit("value", {
"value": 1 if value else 0,
"formatted": "ON" if value else "OFF",
"label": "Trafo",
"min": 0,
"max": 1,
"id": "trafo_on",
})