Source code for device.langmuir_hotprobe

import time
from types import SimpleNamespace

from . import base


[docs] class LangmuirHotProbe(base.ArduinoProbeBase): """Arduino controller that handles heating of a langmuir probe and sweeped measurments of its I-V characteristic. Communication: - serial interface to Arduino """ SWEEP_CMD = "q" def __init__(self, bus, **kwargs): """Constructor :param str bus: Name of serial bus where Arduino is connected, e.g. '/dev/ttyUSB0' """ super().__init__(bus=bus, **kwargs) self._last = SimpleNamespace( power_on=False, # Main power relay (turn on once) heating_on=False, # On/off heating voltage_byte=0, # Heating voltage, 8bit integer heating_power=0, # Heating power [W] heating_timeout=None, # ... see update_frontend() ) # ==== Inherited abstract methods ==== def _safestate(self): self.switch_heating_off() def _defaultstate(self): # Turn on main power relay self._power_on() def _clear_defaultstate(self): # Turn off main power relay self._power_off() # ==== Private commands ==== @base.base_command def _power_on(self): if not self._last.power_on: self._write("r") self._last.power_on = True @base.base_command def _power_off(self): if self._last.power_on: self._write("r") self._last.power_on = False @base.base_command def _set_voltage(self, byte): """Set voltage, byte needs to be 0-255 (8-bit integer).""" # Using XOR to determine which bits need to be swapped to_swap = byte ^ self._last.voltage_byte for i, cmd in enumerate(["a", "s", "d", "f", "g", "h", "j", "k"]): if (to_swap & (0x80 >> i)) != 0: self._write(cmd) self._last.voltage_byte = byte # ==== Commands ====
[docs] def is_heating_on(self): """Status of the probe heater.""" return self._last.heating_on
[docs] @base.base_command def switch_heating_on(self, percent): """Activate heating, apply 10-100% voltage to the heater element. :param float percent: Percentage in range 10-100. """ percent = float(percent) if not (10.0 <= percent <= 100.0): raise base.CommandError("Value percent must be between 10-100") if self.is_heating_on(): self.switch_heating_off() self._set_voltage(round(255 * (percent - 10) / 90)) self._write("m") self._last.heating_on = True
[docs] @base.base_command def switch_heating_off(self): """Stop heating, no voltage is applied to the heater element.""" if self.is_heating_on(): self._write("m") self._last.heating_on = False
[docs] @base.base_command def heating_power(self, device_client=None): """Measure heating power [W], it takes 1s (averaging).""" self._write("i") volts = 1.8 + self._last.voltage_byte / 255 * (20 - 1.8) # Expected format: "Proud: 1.2 A\r\n" line = self._readline() while line == "": time.sleep(0.1) # We wait for arduino to finish the measurement line = self._readline() amps = float(line.split(" ")[-2]) self._last.heating_power = volts * amps if device_client: device_client.emit("value", { "value": self._last.heating_power, "formatted": f"{self._last.heating_power:.1f} W", "label": "Heating", "min": 0, "max": 60, "id": "heating", }) self._last.heating_timeout = time.time() + 10 # 10 sec. timeout return self._last.heating_power
# ==== Related to DeviceClient ====
[docs] def update_frontend(self, device_client): # Because heating_power() is a slow measurment (~ 1 sec.) it is better # let user refresh it manually. The value disappears after a short # timeout to indicate that it should be refreshed again. if self._last.heating_timeout and self._last.heating_timeout >= time.time(): self._last.heating_timeout = None device_client.emit("value", { "value": 0, "formatted": f"n/a", "label": "Heating", "min": 0, "max": 60, "id": "heating", })