Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

...

This wiki describes why and how one subclasses the class Dabsdabs.Devices.Interfacesinterfaces.LinearStageController. From now on we will refer to this class or an instance of it as (an) "LSC".

...

LSC is an abstract MATLAB class. The word "abstract" indicates that, by design, the class has some missing elements (abstract methods and properties) that must be filled in in order to make the class complete and usable. To create and use an LSC, one must first create (or already have) a "concrete" subclass of LSC that fills in those missing blanks.

The reason that LSC is an abstract class is that there are a variety of stage controller devices available. On the one hand, these stage controllers all share some common elements: for example, all have a notion of the stage position. On the other hand, different stage controllers differ in the details: they have different programming interfaces, represent data in different formats, and so on. It would not be possible to create a single class that controls an arbitrary stage controller. By making LSC abstract, it can contain the elements common to all stage controllers, while " leaving blank" out device-specific details. Creating a subclass of LSC fills in those details for a particular type of device.

...

  • It has properties for the current stage position (.positionAbsolute, .positionRelative) and whether the stage is currently moving (.isMoving).
  • It performs unit conversion, and can map the stage coordinate system onto a differing external coordinate system.
  • It has methods for nonblocking and blocking stage moves (see below).
  • It maintains an origin to enable zeroing the position coordinate system (within software).
  • It has properties for device metadata, such as resolution, velocity, positionUnits, and so on.

Blocking vs nonblocking moves
The LSC interface provides two types of moves: blocking, and nonblocking. When started, a blocking move blocks MATLAB execution until the move is complete. When a nonblocking move is started, on the other hand, control is returned to MATLAB immediately after the move is initiated, so that MATLAB execution can continue. For nonblocking moves, the LSC interface allows a callback to be supplied, which fires when the move is complete.

How LSC works

LSC properties and methods are roughly split into two groups: those intended for the subclass writer (you), and those intended for the LSC user (whoever or whatever interacts with the class; most often, this will be the ScanImage application).

The properties you should focus on are the abstract properties, many of which have "Raw" in their names: positionAbsoluteRaw, velocityRaw, etc. You will implement these properties appropriately for your device, within a coordinate and unit system of your choosing.

On the other hand, users of your LSC class will interact with the "non-Raw" properties: postionAbsolute, velocity, and so on. These properties provide access to the Raw properties, but with an additional layer of code that performs unit conversion and coordinate transformations. In general, LSC users do not interact with the Raw properties.

The situation with methods is the same. As an LSC class author, you should focus on the abstract methods which have "Hook" in their names, such as moveStartHook. Meanwhile, users of your class will use the corresponding "non-Hook" methods, such as moveStartAbsolute. The code for moveStartAbsolute calls your moveStartHook method, but has an additional layer of code.

Your Device

We will assume you have a particular stage controller device you wish to control from MATLAB. To be controlled by MATLAB, the device must have an interface to your computer, such as a serial port interface. You will need the documentation for this interface (the available commands and their responses, etc). Note that your stage will often have manual input/control in addition to control via its computer interface.

...

If so, you may want to subclass from Dabsdabs.Devicesinterfaces.Interfaces.LSCSerial rather than Dabs... LinearStageController. LSCSerial is itself a subclass of LSC and provides initialization of the MATLAB serial port, along with an instance of a Dabs...an RS232DeviceBasic object which is a serial port interface with some built-in convenience functionality.

...

The LSC interface currently uses three dimensions (X, Y, and Z) for input and output of position values. Some However, some devices may only control one or two physical dimensions. In this case, your subclass will need to initialize the properties numDeviceDimensions and external2DeviceDimIdx, which specify a nondefault value of numDeviceDimensions when calling the LSC constructor. This value specifies the number of dimensions controlled by your device and the mapping between those dimensions and the three-dimensional space used by LSC.

Which dimensions of my stage are 'active'?

Depending on your application, you may want to "turn off" certain dimensions in your stage controller. For example, you might have a device that can move in three dimensions, but an experimental setup where you only want scanning in a fixed 2-D plane.

In this case, you will need to initialize the property activeDimensions to specify which dimensions are "on" and which are "off". (This property is specified with respect to the three-dimensional LSC coordinate system.)

.

Note that the users of your LSC class may set the property lsc2DeviceDims to specify how the device coordinate system is mapped to the external, three-dimensional coordinate system. This functionality is built in to LSC; you, the subclass writer, do not have to do anything to make this workBy default activeDimensions is "all on", so if you just want to use all the dimensions available for your device, you don't have to do anything.

What units of measurement does my device operate in?

In particular, what units of length are used for values of position, velocity, and acceleration (as applicable)?

When creating a subclass of LSC, you must decide on the system of units that will be used when interacting with your subclass. These units will be used when getting or specifying values for position, velocity, or acceleration. The natural unit of time will likely be seconds, so in practice you only have to decide on a unit of length. Usually, it is easiest to use whatever units are used in your device's computer interface, so that no conversion needs to be done when going between your subclass and the device.

LSC contains two unit systems. The first set of units, positionDeviceUnits, velocityDeviceUnits, and accelerationDeviceUnits, is intended for you, the class writer. You are free to specify any units you like for these properties, so long as you then provide the "raw" device quantities/properties in those units. For example, you must implement positionAbsoluteRaw to report its values in positionDeviceUnits. Typically, you would set this unit system to agree with the unit system used by the device hardware.

The second unit system is intended for the class user, who is interacting with an instance of your class to control a particular stage. This set of units is represented by You should specify what units your subclass uses via the properties positionUnits, velocityUnits, and accelerationUnits.. The user can set these units as is convenient for his or her application. For example, ScanImage works in units of microns; when ScanImage uses LSC objects, it makes sure to have positionUnits set to be 1e-6, and so on.

Important: Since LSC performs unit conversion when setting/reporting quantities like position or velocity, failure to properly specify the device unit system Important: Since ScanImage uses microns (1e-6 m) for its unit of length, it performs unit conversion when talking to an LSC using its positionUnits, etc. Failing to properly specify units in your LSC and then using it with ScanImage could lead to wild/unpredictable stage moves.

...

Some devices have various move-related modes. For example, the Sutter sutter.MP285 has a "coarse" resolution for faster, less accurate moves, and a "fine" resolution for slower, more accurate moves.

Wiki MarkupThe LSC interface does not include the notion of a mode. However, as the creator of a concrete LSC subclass, you are free to include in your subclass any properties and methods specific to your device. For example, you might include in your class a {{moveMode}} property which takes one of several values. You can then refer to this property when implementing LSC properties which may be mode-dependent, such as {{resolution}} or {\[velocity}}.

Does my device provide a response when a move completes?

...

If your device responds when a move is complete, then you should probably set nonblockingMoveCompletedDetectionStrategy to 'callback'. Otherwise, set it to 'poll'. Specification of this property is necessary for LSC to implement its move interface, which supports both blocking and nonblocking moves (see above).

Implementing Abstract Properties

Example: MP285

We use Dabsdabs.Devices.Suttersutter.MP285 as an example of a concrete LSC subclass. Since the Sutter MP285 device is controlled by serial port, MP285 subclasses Dabsdabs.Devicesinterfaces.Interfaces.LSCSerial.

MP285 implements LSC abstract properties in a typical way:

  • Some properties are known in advance and will not change at run-time. Examples are : positionUnits or velocityUnits, or resolutionBestfor example. These properties are implemented as regular (non-Dependent) properties, and are given default values directly in the properties block. In some cases, it may make sense to allow these properties to be optionally constructor-initialized, eg if their value depends on a firmware version which can vary from device to device. For the MP285, the positionUnits falls into this "set-it-and-forget-it" category.
  • Some properties do change at runtime, and involve read-only queries to the hardware. An example is positionAbsoluteRaw. These properties are implemented as Dependent properties, with get-methods that send the appropriate query commands to the hardware.
  • Some properties not only change at runtime, but can be set to new values, as well as queried. An example of such a property is velocity, implemented as a Dependent property with both a set-method and a get-method. The set-method sends the appropriate set-command (and value-to-be-set) to the hardware to set the value on the device.

Other

...

notes:

  • In some cases, a property "does not apply" to a device. In the same vein, ScanImage does not utilize all available LSC properties. At the current time, the abstract properties required for ScanImage operation are:
  1. nonblockingMoveCompletedDetectionStrategy
  2. positionAbsoluteRaw (get only)
  3. isMoving (get only)
  4. positionUnits (get only)
  5. resolution (get only)

...

  • accelerationRaw, for example, does not apply to the MP285. To make MP285 a concrete class, accelerationRaw must be defined somewhere in a properties block; however, this property doesn't do anything (its get-method always returns NaN, and there is no set-method). Your LSC subclass may similarly "omit" inapplicable properties. Note however that ScanImage will expect certain properties to be present and working. See #Minimal LSC Implementation for ScanImage below.
  • The MP285 has two "resolutionModes", 'fine' and 'coarse'. Each mode has its own velocity setting, so that the resolutionMode is queried when setting/getting the velocity property. The details related to resolutionMode are specific to MP285 and may not apply to your device; however they do illustrate the general pattern of having more than one mode.
  • The MP285 is a serial port device, and the MP285 class subclasses from LSCSerial. To implement its send/receive commands, it uses the LSCSerial property , which holds an hRS232 object. This object adds some convenience functionality to the MATLAB serial object. See the documentation for Dabsdabs.Devices.Interfacesinterfaces.RS232DeviceBasic for details.

...

LSC has a number of other methods with Hook in their names, such as moveCompleteHook, interruptMoveHook, etc. Concrete subclasses are encouraged to override these methods whenever possible. The default implementation of interruptMoveHook, for example, simply throws an error indicating that move-interruption is not supported. LSC subclasses representing stages that can be interrupted during moves should implement an override for this method to enable such interruption.

Minimal LSC Implementation for ScanImage

The LSC interface includes more than is absolutely required by ScanImage, because it was designed to be generally useful, independent of any single application.

That said, you are probably reading this page because you are a ScanImage user with a custom stage. At the moment, ScanImage requires the following properties and methods of LSC to be implemented/functional:

Properties

  1. nonblockingMoveCompletedDetectionStrategy
  2. isMoving (get only)
  3. positionAbsoluteRaw (get only)
  4. positionDeviceUnits (get only)

Methods

  1. moveStartHook
  2. getResolutionBestHook (This method has a default implementation in LSC, but if the default method doesn't apply to your device then you should provide an override.)

Testing

When your subclass is complete, it is critical to test its operation with real hardware in a "safe" setting before live use. Implementing an LSC subclass involves a fair amount of complexity and some amount of testing/debugging time will likely be necessary to ensure reliable operation. Using an LSC without proper testing could lead to wild stage moves and damage to your rig.