Adding support for more devices
There are three main device types that ImSwitch’s hardware control module supports: detectors, lasers and positioners. In order to add support for a new detector, laser or positioner, a corresponding device manager class must be implemented in ImSwitch’s code.
How device managers are implemented
Detector support is implemented in device manager classes derived from the abstract base class DetectorManager
.
The corresponding parent class for lasers is LaserManager
,
and for positioners it is PositionerManager
.
These derived classes are placed in the detectors
, lasers
and positioners
sub-modules respectively in the imswitch.imcontrol.model.managers
module.
The required constructor signature for the device managers is __init__(deviceInfo, name, **lowLevelManagers)
.
deviceInfo
is the DetectorInfo
, LaserInfo
or PositionerInfo
object which represents the device’s entry in the setup file
(see the hardware control setup page for further information).
Inside it, the managerProperties
dict field may contain manager-specific properties.
name
is a unique name that is used to identify the device,
which is defined by the key of the device’s entry in the setup file.
lowLevelManagers
is a dict containing objects that facilitate low-level device interaction,
which are documented here.
Note that super().__init__
has a different signature, depending on which base class is used.
When creating a new device manager, you will need to implement all the abstract methods and properties defined in the base class. You should avoid overriding non-abstract properties. Overriding non-abstract methods is generally fine, but you should make sure that they continue to work as expected. The device manager class must be placed in a .py file with the same name as the class, in the appropriate location as outlined above. No other action is required for the device manager to be available to use; it will automatically be managed by a multi-manager as outlined in the paper.
You can find a simple example of a positioner manager implementation here.
Base class documentation
DetectorManager
- class imswitch.imcontrol.model.managers.detectors.DetectorManager.DetectorManager(detectorInfo, name: str, fullShape: Tuple[int, int], supportedBinnings: List[int], model: str, *, parameters: Optional[Dict[str, DetectorParameter]] = None, actions: Optional[Dict[str, DetectorAction]] = None, croppable: bool = True)
Abstract base class for managers that control detectors. Each type of detector corresponds to a manager derived from this class.
- abstract __init__(detectorInfo, name: str, fullShape: Tuple[int, int], supportedBinnings: List[int], model: str, *, parameters: Optional[Dict[str, DetectorParameter]] = None, actions: Optional[Dict[str, DetectorAction]] = None, croppable: bool = True) None
- Parameters:
detectorInfo – See setup file documentation.
name – The unique name that the device is identified with in the setup file.
fullShape – Maximum image size as a tuple
(width, height)
.supportedBinnings – Supported binnings as a list.
model – Detector device model name.
parameters – Parameters to make available to the user to view/edit.
actions – Actions to make available to the user to execute.
croppable – Whether the detector image can be cropped.
- property actions: Dict[str, DetectorAction]
Dictionary of available actions.
- property binning: int
Current binning.
- abstract crop(hpos: int, vpos: int, hsize: int, vsize: int) None
Crop the frame read out by the detector.
- property croppable: bool
Whether the detector supports frame cropping.
- finalize() None
Close/cleanup detector.
- abstract flushBuffers() None
Flushes the detector buffers so that getChunk starts at the last frame captured at the time that this function was called.
- property forAcquisition: bool
Whether the detector is used for acquisition.
- property forFocusLock: bool
Whether the detector is used for focus lock.
- property frameStart: Tuple[int, int]
Position of the top left corner of the current frame as a tuple
(x, y)
.
- property fullShape: Tuple[int, int]
Maximum image size as a tuple
(width, height)
.
- abstract getChunk() ndarray
Returns the frames captured by the detector since getChunk was last called, or since the buffers were last flushed (whichever happened last). The returned object is a numpy array of shape (numFrames, height, width).
- abstract getLatestFrame() ndarray
Returns the frame that represents what the detector currently is capturing. The returned object is a numpy array of shape (height, width).
- property image: ndarray
Latest LiveView image.
- property model: str
Detector model name.
- property name: str
Unique detector name, defined in the detector’s setup info.
- property parameters: Dict[str, DetectorParameter]
Dictionary of available parameters.
- abstract property pixelSizeUm: List[int]
The pixel size in micrometers, in the format
[z, y, x]
.z
is typically set to 1.
- setBinning(binning: int) None
Sets the detector’s binning.
- setParameter(name: str, value: Any) Dict[str, DetectorParameter]
Sets a parameter value and returns the updated list of parameters. If the parameter doesn’t exist, i.e. the parameters field doesn’t contain a key with the specified parameter name, an AttributeError will be raised.
- property shape: Tuple[int, int]
Current image size as a tuple
(width, height)
.
- abstract startAcquisition() None
Starts image acquisition.
- abstract stopAcquisition() None
Stops image acquisition.
- property supportedBinnings: List[int]
Supported binnings as a list.
- class imswitch.imcontrol.model.managers.detectors.DetectorManager.DetectorAction(group: str, func: callable)
An action that is made available for the user to execute.
- func: callable
The function that is called when the action is executed.
- group: str
The group to place the action in (does not need to be pre-defined).
- class imswitch.imcontrol.model.managers.detectors.DetectorManager.DetectorParameter(group: str, value: Any, editable: bool)
Abstract base class for detector parameters that are made available for the user to view/edit.
- class imswitch.imcontrol.model.managers.detectors.DetectorManager.DetectorNumberParameter(group: str, value: float, editable: bool, valueUnits: str)
Bases:
DetectorParameter
A detector parameter with a numerical value.
- editable: bool
Whether it is possible to edit the value of the parameter.
- group: str
The group to place the parameter in (does not need to be pre-defined).
- value: float
The value of the parameter.
- valueUnits: str
Parameter value units, e.g. “nm” or “fps”.
- class imswitch.imcontrol.model.managers.detectors.DetectorManager.DetectorListParameter(group: str, value: str, editable: bool, options: List[str])
Bases:
DetectorParameter
A detector parameter with a value from a list of options.
- editable: bool
Whether it is possible to edit the value of the parameter.
- group: str
The group to place the parameter in (does not need to be pre-defined).
- options: List[str]
The available values to pick from.
- value: str
The value of the parameter.
LaserManager
- class imswitch.imcontrol.model.managers.lasers.LaserManager.LaserManager(laserInfo, name: str, isBinary: bool, valueUnits: str, valueDecimals: int)
Abstract base class for managers that control lasers. Each type of laser corresponds to a manager derived from this class.
- abstract __init__(laserInfo, name: str, isBinary: bool, valueUnits: str, valueDecimals: int) None
- Parameters:
laserInfo – See setup file documentation.
name – The unique name that the device is identified with in the setup file.
isBinary – Whether the laser can only be turned on and off, and its value cannot be changed.
valueUnits – The units of the laser value, e.g. “mW” or “V”.
valueDecimals – How many decimals are accepted in the laser value.
- finalize() None
Close/cleanup laser.
- property isBinary: bool
Whether the laser can only be turned on and off, and its value cannot be changed.
- property name: str
Unique laser name, defined in the laser’s setup info.
- abstract setEnabled(enabled: bool) None
Sets whether the laser is enabled.
- setScanModeActive(active: bool) None
Sets whether the laser should be in scan mode (if the laser supports it).
- abstract setValue(value: Union[int, float]) None
Sets the value of the laser.
- property valueDecimals
How many decimals are accepted in the laser value.
- property valueRangeMax: float
The maximum value that the laser can be set to.
- property valueRangeMin: float
The minimum value that the laser can be set to.
- property valueRangeStep: float
The default step size of the value range that the laser can be set to.
- property valueUnits: str
The units of the laser value, e.g. “mW” or “V”.
- property wavelength: int
The wavelength of the laser.
PositionerManager
- class imswitch.imcontrol.model.managers.positioners.PositionerManager.PositionerManager(positionerInfo, name: str, initialPosition: Dict[str, float])
Abstract base class for managers that control positioners. Each type of positioner corresponds to a manager derived from this class.
- abstract __init__(positionerInfo, name: str, initialPosition: Dict[str, float])
- Parameters:
positionerInfo – See setup file documentation.
name – The unique name that the device is identified with in the setup file.
initialPosition – The initial position for each axis. This is a dict in the format
{ axis: position }
.
- property axes: List[str]
The list of axes that are controlled by this positioner.
- finalize() None
Close/cleanup positioner.
- property forPositioning: bool
Whether the positioner is used for manual positioning.
- property forScanning: bool
Whether the positioner is used for scanning.
- abstract move(dist: float, axis: str)
Moves the positioner by the specified distance and returns the new position. Derived classes will update the position field manually. If the positioner controls multiple axes, the axis must be specified.
- property name: str
Unique positioner name, defined in the positioner’s setup info.
- property position: Dict[str, float]
The position of each axis. This is a dict in the format
{ axis: position }
.
- abstract setPosition(position: float, axis: str)
Adjusts the positioner to the specified position and returns the new position. Derived classes will update the position field manually. If the positioner controls multiple axes, the axis must be specified.
Available low-level managers
lowLevelManagers[‘nidaqManager’]
- class imswitch.imcontrol.model.managers.NidaqManager.NidaqManager(setupInfo)
For interaction with NI-DAQ hardware interfaces.
- setAnalog(target, voltage, min_val=-1, max_val=1)
Function to set the analog channel to a specific target to a certain voltage
- setDigital(target, enable)
Function to set the digital line to a specific target to either “high” or “low” voltage
lowLevelManagers[‘rs232sManager’]
- class imswitch.imcontrol.model.managers.RS232sManager.RS232sManager(rs232deviceInfos, **lowLevelManagers)
RS232sManager is an interface for dealing with RS232 devices. It is a MultiManager for RS232 devices.
RS232Manager instances for individual RS232 devices can be accessed by
rs232sManager['your_rs232_device_name']
.
- class imswitch.imcontrol.model.managers.rs232.RS232Manager.RS232Manager(rs232Info, name, **_lowLevelManagers)
A general-purpose RS232 manager that together with a general-purpose RS232Driver interface can handle an arbitrary RS232 communication channel, with all the standard serial communication protocol parameters as defined in the hardware control configuration.
Manager properties:
port
encoding
recv_termination
send_termination
baudrate
bytesize
parity
stopbits
rtscts
dsrdtr
xonxoff
- send(arg: str) str
Sends the specified command to the RS232 device and returns a string encoded from the received bytes.