Skip to content

st10_controller

frog.hardware.plugins.stepper_motor.st10_controller ¤

Code for interfacing with the ST10-Q-NN stepper motor controller.

Applied Motions have their own bespoke programming language ("Q") for interfacing with their devices, of which we're only using a small portion here.

The specification is available online

https://appliedmotion.s3.amazonaws.com/Host-Command-Reference_920-0002W_0.pdf

Attributes¤

Classes¤

ST10AlarmCode ¤

Bases: IntFlag

The set of possible alarm codes for the ST10 motor controller.

These values are taken from the manual. Note that the alarm code is a bit mask, so several of these may be set at once (if you're especially unlucky!).

Functions¤
__str__() ¤

Convert the set alarm code bits to a string.

Source code in frog/hardware/plugins/stepper_motor/st10_controller.py
48
49
50
51
def __str__(self) -> str:
    """Convert the set alarm code bits to a string."""
    error_str = ", ".join(code.name for code in self)  # type: ignore[misc]
    return f"Alarm code 0x{self:04X}: {error_str}"

ST10Controller(port, baudrate=9600, timeout=5.0) ¤

Bases: SerialDevice, StepperMotorBase

An interface for the ST10-Q-NN stepper motor controller.

This class allows for moving the mirror to arbitrary positions and retrieving its current position.

Create a new ST10Controller.

Parameters:

Name Type Description Default
port str

Description of USB port (vendor ID + product ID)

required
baudrate int

Baud rate of port

9600
timeout float

Connection timeout

5.0

Raises:

Type Description
SerialException

Error communicating with device

SerialTimeoutException

Timed out waiting for response from device

ST10ControllerError

Malformed message received from device

Source code in frog/hardware/plugins/stepper_motor/st10_controller.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
def __init__(self, port: str, baudrate: int = 9600, timeout: float = 5.0) -> None:
    """Create a new ST10Controller.

    Args:
        port: Description of USB port (vendor ID + product ID)
        baudrate: Baud rate of port
        timeout: Connection timeout

    Raises:
        SerialException: Error communicating with device
        SerialTimeoutException: Timed out waiting for response from device
        ST10ControllerError: Malformed message received from device
    """
    SerialDevice.__init__(self, port, baudrate)

    self._reader = _SerialReader(self.serial, timeout)
    self._reader.async_read_completed.connect(self._on_initial_move_end)
    self._reader.read_error.connect(self.send_error_message)
    self._reader.start()

    self._init_error_timer = QTimer()
    """A timer to raise an error if the motor takes too long to move."""
    self._init_error_timer.setInterval(round(STEPPER_MOTOR_HOMING_TIMEOUT * 1000))
    self._init_error_timer.setSingleShot(True)
    self._init_error_timer.timeout.connect(
        lambda: self.send_error_message(
            RuntimeError("Timed out waiting for motor to move")
        )
    )

    # Check that we are connecting to an ST10
    self._check_device_id()

    self._disable_limit_switches()

    # Move mirror to home position
    self._home_and_reset()

    StepperMotorBase.__init__(self)
Attributes¤
ST10_MODEL_ID = '107F024' class-attribute instance-attribute ¤

The model and revision number for the ST10 controller we are using.

STEPS_PER_ROTATION = 50800 class-attribute instance-attribute ¤

The total number of steps in one full rotation of the mirror.

alarm_code property ¤

Get the current alarm code for the controller, if any.

is_moving property ¤

Whether the motor is moving.

This is done by checking whether the status code has the moving bit set.

status_code property ¤

The status code of the device.

For a complete list of status codes and their meanings, consult the manual.

step property writable ¤

The current state of the device's step counter.

This makes use of the "IP" command, which estimates the immediate position of the motor. If the motor is moving, this is an estimated (calculated trajectory) position. If the motor is stationary, this is the actual position.

Raises:

Type Description
SerialException

Error communicating with device

SerialTimeoutException

Timed out waiting for response from device

ST10ControllerError

Malformed message received from device

steps_per_rotation property ¤

Get the number of steps that correspond to a full rotation.

Functions¤
close() ¤

Close device and leave mirror facing downwards.

This prevents dust accumulating.

Source code in frog/hardware/plugins/stepper_motor/st10_controller.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def close(self) -> None:
    """Close device and leave mirror facing downwards.

    This prevents dust accumulating.
    """
    StepperMotorBase.close(self)

    if not self.serial.is_open:
        return

    # Don't handle move end events because they will likely happen after the device
    # is disconnected
    self._reader.async_read_completed.disconnect()

    try:
        self.move_to("nadir")
    except Exception as e:
        logging.error(f"Failed to reset mirror to downward position: {e}")

    # Set flag that indicates the thread should quit
    self._reader.quit()

    # If _reader is blocking on a read (which is likely), we could end up waiting
    # forever, so close the socket so that the read operation will terminate
    SerialDevice.close(self)
stop_moving() ¤

Immediately stop moving the motor.

Source code in frog/hardware/plugins/stepper_motor/st10_controller.py
557
558
559
def stop_moving(self) -> None:
    """Immediately stop moving the motor."""
    self._write_check("ST")

ST10ControllerError ¤

Bases: SerialException

Indicates that an error has occurred with the ST10 controller.