class GenericPyroLabDevice(HardwareDevice): """ A class that passes all function calls on to the PyroLab driver. This class is used to pass all function calls and attribute requests on to a nonstandard PyroLab driver. This is useful for devices that are not implemented or described by the standard AutoGator API, such as custom, homebuilt hardware. Parameters ---------- pyroname : str The name of the PyroLab object as registered with the nameserver. ns_host : str, optional The hostname of the PyroLab nameserver (default "localhost"). ns_port : int, optional The port of the PyroLab nameserver (default "9090"). """ def __init__(self, pyroname: str = "", ns_host: str = "localhost", ns_port: int = 9090) -> None: super().__init__(pyroname) with locate_ns(host=ns_host, port=ns_port) as ns: self.driver = Proxy(ns.lookup(pyroname)) self.driver.autoconnect() def __getattr__(self, __name: str) -> Any: return self.driver.__getattr__(__name)
# -*- coding: utf-8 -*- # # Copyright © PyroLab Project Contributors # Licensed under the terms of the GNU GPLv3+ License # (see pyrolab/__init__.py for details) """ Using a lockable service ------------------------ """ from pyrolab.api import locate_ns, Proxy ns = locate_ns(host="localhost") uri = ns.lookup("test.SampleAutoconnectInstrument") # Note that proxies are not connected until the first method call is made. # This means that the following two lines set up the proxies without actually # connecting to the remote objects. service = Proxy(uri) resp = service.autoconnect() print(type(resp), resp) resp = service.do_something() print(type(resp), resp)
class Z825BLinearStage(LinearStageBase): """ A linear motor. Parameters ---------- pyroname : str The name of the PyroLab object as registered with the nameserver. ns_host : str, optional The hostname of the PyroLab nameserver (default "localhost"). ns_port : int, optional The port of the PyroLab nameserver (default "9090"). """ def __init__(self, pyroname: str = "", ns_host: str = "localhost", ns_port: int = 9090) -> None: super().__init__(pyroname) with locate_ns(host=ns_host, port=ns_port) as ns: self.driver = Proxy(ns.lookup(pyroname)) self.driver.autoconnect() self._step_size = None @property def step_size(self) -> float: """The jog step size in mm.""" return self._step_size @step_size.setter def step_size(self, step_size: float) -> None: if step_size != self._step_size: self.driver._pyroClaimOwnership() self.driver.jog_step_size = step_size self._step_size = step_size def move_to(self, position: float) -> None: """ Moves to a new position. This motor adjusts for backlash; a given position will always be approached from the "negative" direction. That may require overshooting the commanded position in order to always approach it again from a consistent direction. If stepping in short steps, it is therefore most efficient to step from negative to positive values to avoid backlash adjustments on each step. Parameters ---------- position : float The new position to move to. """ self.driver._pyroClaimOwnership() if self._requires_backlash_adjustment(position): self.driver.move_to(position - (self.driver.backlash * 1.5)) self.driver.move_to(position) def move_by(self, distance: float) -> None: """ Jogs the motor by a fixed distance. Parameters ---------- distance : float The distance to move the motor. A positive value will move the motor forward, and a negative value will move the motor backwards. """ self.driver._pyroClaimOwnership() if np.abs(distance) != self.step_size: self.step_size = np.abs(distance) if distance > 0: self.driver.jog("forward") else: self.driver.jog("backward") def move_cont(self, direction: str) -> None: """ Starts a continuous move in the specified direction. Parameters ---------- direction : str The direction to move the motor, either "forward" or "backward". """ self.driver._pyroClaimOwnership() self.driver.move_continuous(direction) def _requires_backlash_adjustment(self, position: float) -> bool: """ Determine if the new position command needs to compensate for backlash. The ThorLabs linear stages have a small backlash distance. To ensure as accurate a reposition as possible when moving to the same location multiple times, the motor will always approach the position from the same direction. This function determines whether that requires overshooting the current position before reapproaching. Parameters ---------- position : float The position to move to. Returns ------- bool Whether backlash compensation is required. """ if position < self.get_position(): return True return False def stop(self) -> None: """ Stop all motion. """ self.driver._pyroClaimOwnership() self.driver.stop() def get_position(self) -> float: """ Get the current position in millimeters. """ self.driver._pyroClaimOwnership() return self.driver.get_position() def home(self) -> None: """ Home the motor. """ self.driver._pyroClaimOwnership() self.driver.go_home() def status(self) -> int: """ Returns a nonzero value if the motor is busy. """ pass
class TSL550Laser(LaserBase): """ A laser. Parameters ---------- pyroname : str The name of the PyroLab object as registered with the nameserver. ns_host : str, optional The hostname of the PyroLab nameserver (default "localhost"). ns_port : int, optional The port of the PyroLab nameserver (default "9090"). """ def __init__(self, pyroname: str = "", ns_host: str = "localhost", ns_port: int = 9090): super().__init__(pyroname) with locate_ns(host=ns_host, port=ns_port) as ns: self.driver = Proxy(ns.lookup(pyroname)) self.driver.autoconnect() def on(self, block=False) -> None: """ Turn on the laser. If the laser diode is off, there is a warm-up time before the laser diode is ready. If block is True, this function will block until the warm-up time is complete. Parameters ---------- block : bool, optional Whether to block until the warm-up time is complete (default False). """ self.driver._pyroClaimOwnership() if self.driver.status()[0] != '-': self.driver.on() if block: while self.driver.status()[0] != '-': time.sleep(5.0) self.driver.open_shutter() def off(self, diode: bool = True) -> None: """ Turns off laser output by closing the shutter and optionally turning off the diode. Parameters ---------- diode : bool, optional Whether to turn off the diode. If False, the laser diode will be turned off. There is a warm-up period to turn the laser back on if the diode has been turned off. If True, the laser diode will be left on but the shutter will be closed. """ self.driver._pyroClaimOwnership() self.driver.close_shutter() if not diode: self.driver.off() def power(self, power: float) -> None: """ Sets the laser power in dBm. Parameters ---------- power : float The power to set the laser to. """ self.driver._pyroClaimOwnership() self.driver.power_dBm(power) def wavelength(self, wavelength: float) -> None: """ Sets the laser wavelength in nm. Parameters ---------- wavelength : float The wavelength to set the laser to. """ self.driver._pyroClaimOwnership() self.driver.wavelength(wavelength) def sweep(self, num: int = 1) -> None: """ Starts the configured wavelength sweep. Parameters ---------- num : int, optional The number of times to run the wavelength sweep (default 1). """ self.driver._pyroClaimOwnership() self.driver.sweep_start(num) def sweep_wavelength(self, wl_start: float = 1500, wl_stop: float = 1630, duration: float = 2, number: int = 1): """ Convenience function to run a continuous wavelength sweep. Parameters ---------- wl_start : float, optional The starting wavelength (default 1500). wl_stop : float, optional The ending wavelength (default 1630). duration : float, optional The duration of the sweep (default 2). number : int, optional The number of times to run the sweep (default 1). """ self.driver._pyroClaimOwnership() self.driver.sweep_wavelength(start=wl_start, stop=wl_stop, duration=duration, number=number) def sweep_set_mode(self, continuous: bool = True, twoway: bool = True, trigger: bool = False, const_freq_step: bool = False) -> None: """ Sets the sweep mode. Parameters ---------- continuous : bool Continuous (``True``, default) or stepwise (``False``). twoway : bool Two-way (``True``, default) or one-directional with reset (``False``). trigger : bool Start on external trigger (defaults to ``False``). const_freq_step : bool Constant frequency interval, requires stepwise mode (defaults to ``False``). """ self.driver._pyroClaimOwnership() self.driver.sweep_set_mode( continuous=continuous, twoway=twoway, trigger=trigger, const_freq_step=const_freq_step, ) def set_trigger(self, mode: str, step: float) -> None: """ Enables trigger output. The output trigger can be set to fire at the start of a wavelength sweep, at the end of a sweep, or at a fixed step. Valid step range is 0.004 - 160 nm with a minimum step of 0.0001 nm. Parameters ---------- mode : str The trigger mode. One of: “None”, “Stop”, “Start”, “Step”. step : float The trigger step size, in nanometers. """ self.driver._pyroClaimOwnership() self.driver.trigger_enable_output() triggerMode = self.driver.trigger_set_mode(mode) triggerStep = self.driver.trigger_step(step) return triggerMode, triggerStep def wavelength_logging(self) -> None: """ Downloads the wavelength log. Returns ------- list The last wavelength log. """ self.driver._pyroClaimOwnership() return self.driver.wavelength_logging()
# -*- coding: utf-8 -*- # # Copyright © PyroLab Project Contributors # Licensed under the terms of the GNU GPLv3+ License # (see pyrolab/__init__.py for details) """ Kinesis KCube Driver Example ============================ This example demonstrates the use of the Thorlabs KCube DC Servo controlling a Z825B translational stage using PyroLab. """ from pyrolab.api import NameServerConfiguration, Proxy, locate_ns nscfg = NameServerConfiguration(host="yourdomain.com") nscfg.update_pyro_config() # Be considerate; don't stay connected to the nameserver too long. with locate_ns() as ns: motor = Proxy(ns.lookup("Z825B_PyroName")) motor.autoconnect() print(motor.get_position()) motor.close()