Source code for dlab.hardware.wrappers.zaber_controller

from __future__ import annotations
from typing import Optional

from zaber_motion import Library, Units
from zaber_motion.binary import Connection, Device


[docs] class ZaberNotActivatedError(RuntimeError): """Error Management"""
[docs] class ZaberBinaryController: def __init__(self, port: str, baud_rate: int = 9600, range_min: float = 0.0, range_max: float = 50.0): self.port = port self.baud_rate = baud_rate self.conn: Optional[Connection] = None self.device: Optional[Device] = None self.range_min = range_min self.range_max = range_max def _ensure(self) -> Device: if self.device is None: raise ZaberNotActivatedError("Stage not activated. Call activate() first.") return self.device
[docs] def activate(self, homing: bool = True) -> None: Library.enable_device_db_store() self.conn = Connection.open_serial_port(self.port, baud_rate=self.baud_rate) devices = self.conn.detect_devices() if not devices: self.disable() raise ZaberNotActivatedError(f"No Zaber devices found on {self.port}@{self.baud_rate}") self.device = devices[0] if homing: self.home()
[docs] def home(self, blocking: bool = True) -> None: dev = self._ensure() dev.home() if blocking: dev.wait_until_idle()
[docs] def move_to(self, position: float, blocking: bool = True) -> None: dev = self._ensure() pos = max(self.range_min, min(self.range_max, float(position))) dev.move_absolute(pos, Units.LENGTH_MILLIMETRES) if blocking: dev.wait_until_idle()
[docs] def get_position(self) -> Optional[float]: if self.device is None: return None return float(self.device.get_position(Units.LENGTH_MILLIMETRES))
[docs] def identify(self) -> None: self._ensure().identify()
[docs] def disable(self) -> None: try: if self.device is not None: self.device.stop() finally: if self.conn is not None: self.conn.close() self.device = None self.conn = None