Getting Started¶
To control a device with Microscope one needs to find the Python class
that supports it. These are listed on Supported Devices. Each
device has its own class which typically have their own module. Note
that many devices have the same class, for example, all Ximea cameras
use XimeaCamera
and
all Andor CMOS cameras use AndorSDK3
.
Connecting to the Device¶
Once the class is known its documentation will state the arguments
required to construct the device instance and connect to it. For
devices controlled over a serial channel the argument is typically the
port name of its address, e.g., /dev/ttyS0
on GNU/Linux or
COM1
on Windows. For other devices the argument is typically the
serial number (this is typically printed on a label on the physical
device).
from microscope.lights.sapphire import SapphireLaser
laser = SapphireLaser(com="/dev/ttyS0")
from microscope.mirror.alpao import AlpaoDeformableMirror
dm = AlpaoDeformableMirror(serial_number="BIL103")
Controlling the Device¶
The construction of the device is the only device specific code. Beyond this ABCs force a defined interface on the device classes ensuring that all devices have the same methods and properties. The following ABCs, one per device type, are currently supported:
microscope.abc.Camera
microscope.abc.Controller
microscope.abc.DeformableMirror
microscope.abc.FilterWheel
microscope.abc.LightSource
microscope.abc.Stage
LightSource¶
A light source emits light when enabled and its power can be read and
set via the power
property:
laser.power = .7 # set power to 70%
laser.enable() # only start emitting light now
laser.power = laser.power /3 # set power to 1/3
laser.disable() # stop emitting light
Filter Wheel¶
A filter wheel changes its position by setting the position
property:
print("Number of positions is %d" % filterwheel.n_positions)
print("Current position is %d" % filterwheel.position)
filterwheel.position = 3 # move in filter at position 3
Stage¶
A stage device can have any number of axes and dimensions. For a
single StageDevice
instance each axis has a name that uniquely
identifies it. The names of the individual axes are hardware
dependent and will be part of the concrete class documentation. They
are typically strings such as “x” or “y”.
stage.enable() # may trigger a stage move
# move operations
stage.move_to({"x": 42.0, "y": -5.1})
stage.move_by({"x": -5.3, "y": 14.6})
# Individual StageAxis can be controlled directly.
x_axis = stage.axes["x"]
y_axis = stage.axes["y"]
x_axis.move_to(42.0)
y_axis.move_by(-5.3)
Camera¶
Cameras when triggered will put an image on their client which is a queue-like object. These queue-like objects must first be created and set on the camera:
buffer = queue.Queue()
camera.set_client(buffer)
camera.enable()
camera.trigger() # acquire image
img = buffer.get() # retrieve image
Deformable Mirror¶
A deformable mirror applies a NumpPy array with the values for each of its actuators in the range of [0 1]:
# Set all actuators to their mid-point
dm.apply_pattern(np.full(dm.n_actuators, 0.5))
Alternatively, a series of patterns can be first queued and applied when a trigger is received:
# `patterns` is a NumPy array of shape (K, N) where K is the number of
# patterns and N is the number of actuators.
dm.queue_patterns(patterns)
for i in range(patterns.shape[0]):
dm.trigger()
Controller¶
A controller is a device that controls a series of other devices. For
example, a multi laser engine is a controller of many light sources.
A controller instance only has as devices
property which is a map
of names to instances of other device classes.
cyan_led = controller.devices["CYAN"]
red_laser = controller.devices["RED"]
The class documentation will include details on the names of the controller device.
Shutdown the Device¶
When all is done, it’s a good idea to disable and cleanly shutdown the device:
camera.disable()
camera.shutdown()