A python library/GUI to access and control motors via the APT protocol.
Project description
pyThorlabsAPT
pyThorlabsAPT is a Python library/GUI interface to control any motor compatible with the Thorlabs APT communication protocol. The package is composed of two parts, a
low-level driver to perform basic operations, and a high-level GUI, written with PyQt5, which can be easily embedded into other GUIs. The low-level driver is essentially a wrapper of the excellent
package thorlabs_apt, with a few tweaks to speed up loading time and error handling.
Since thorlabs_apt is not available via pip, its code has been embedded in the code of this package, here.
A virtual (software-simulated) backend is also included, so the driver and the GUI can be used and tested without any real hardware, APT.dll, or the Thorlabs APT software installed.
The interface can work either as a stand-alone application, or as a module of ergastirio.
Table of Contents
- Installation
- Usage via the low-level driver
- Usage as a stand-alone GUI interface
- Embed the GUI within another GUI
Installation
The package uses the Thorlabs APT.dll shared library, and therefore the low-level driver and the real (non-virtual) GUI only work under Windows. The virtual backend, however, works on any platform. To install, follow these steps:
- Install the script via the package manager pip,
pip install pyThorlabsAPT==0.12
Important: due to a bug of pypi, if you run just '''pip install pyThorlabsAPT''' it might default to a stale version 0.21, which was wrongly uploaded on pypi in the past and it does not work. Make sure you specify the version.
-
Install the APT software from here (clik on the tab 'Archive'). The version of the software (32 or 64 bit) must match the one of your python installation.
-
Locate the file APT.dll which has been installed on your computer by the APT software. This file will typically be in the folder "[APT Installation Folder]\APT Server", where [APT Installation Folder] is the installation folder of the APT software (typically [APT Installation Folder] = C:\Program Files\Thorlabs\APT). Copy the APT.dll into one of these locations:
- C:\Windows\System32.
- The folder of your python application.
- Inside the "[Python packages folder]\pyThorlabsAPT horlabs_apt". Most of the times [Python packages folder] = "[Python folder]\Lib\site-packages".
Steps 2 and 3 are only needed to talk to real hardware; they can be skipped entirely if you only intend to use the virtual driver (see Virtual mode below).
These steps are enough to run the low-level driver of pyThorlabsAPT. In order to use the GUI, it is necessary to install additional libraries,
specified in the requirements.txt file,
pip install abstract_instrument_interface>=0.10
pip install "PyQt5>=5.15.6"
pip install pyqtgraph
pip install numpy
Usage via the low-level driver
pyThorlabsAPT can be used to control a device from the command line or from your Python script.
The class pyThorlabsAPT wraps the connected device's low-level Motor object (defined in thorlabs_apt for real hardware, or in
pyThorlabsAPT.thorlabs_apt_virtual for the simulated backend) and exposes the subset of its properties and methods needed to find, connect to, and operate a stage. A
full list of properties, attributes, and methods is available below. Note: the documentation below was partially compiled with the help of Claude - mistakes are possible.
Creating a driver instance
pyThorlabsAPT(virtual=False)
| Parameter | Type | Description |
|---|---|---|
virtual |
bool, optional | If True, use the virtual backend (pyThorlabsAPT.thorlabs_apt_virtual) instead of real hardware (see Virtual mode below). Default is False. |
Virtual mode (no hardware needed)
Passing virtual=True makes the driver simulate APT motors instead of talking to the real APT.dll. Two virtual motors with different specs are available. This is useful for testing or demoing the package without a physical
instrument, and works even if the Thorlabs APT software is not installed.
from pyThorlabsAPT.driver import pyThorlabsAPT
instrument = pyThorlabsAPT(virtual=True)
available_devices = instrument.list_devices()
print(available_devices)
instrument.connect_device(device_addr=available_devices[0][1])
instrument.move_home()
print(instrument.position) # returns a simulated, time-varying position while homing
instrument.disconnect_device()
Properties
The following are implemented as Python @property. Reading or setting either of these requires a device to be connected; otherwise, accessing them raises an AttributeError (no underlying Motor object has been created yet).
| Property | Type | Description | Can be set? |
Notes |
|---|---|---|---|---|
position |
float | Current position of the motor. | Yes | Setting it starts a non-blocking absolute move. Poll is_in_motion (or call instrument.motor.position again) to know when the move has finished. |
is_in_motion |
bool | Whether the motor is currently moving. | No |
Other attributes
| Attribute | Type | Description |
|---|---|---|
connected |
bool | True if a device is currently connected, False otherwise. |
motor |
Motor instance |
The underlying real or virtual Motor object, created by connect_device() upon a successful connection. Does not exist until a device has been connected. |
list_valid_devices |
list | List of devices found by the most recent call to list_devices(). |
Methods
| Method | Returns | Description |
|---|---|---|
list_devices() |
list | Returns a list of all available devices. Each element is a 2-element tuple (identity, address), where identity is an integer hardware-type code and address is the integer serial number to pass to connect_device(). |
connect_device(device_addr) |
(str or int, int) | Attempts to connect to the device identified by device_addr (its serial number, as returned by list_devices()). Returns (Msg, ID): Msg is device_addr on success, or an error message on failure; ID is 1 if connection was successful, 0 otherwise. Raises ValueError if device_addr does not match any device returned by the most recent call to list_devices(). |
disconnect_device() |
(str, int) | Attempts to disconnect the currently connected device. Returns (Msg, ID), analogous to connect_device(). Raises RuntimeError if no device is currently connected. |
move_home(blocking=False) |
None | Moves the motor to its home position (position 0). |
move_jog(direction, blocking=False) |
None | Jogs the motor by the currently configured jog step size (see get_jog_parameters/set_jog_parameters), in the given direction (see Direction and units constants below). |
stop_profiled() |
None | Stops any ongoing movement (profiled stop). |
get_stage_axis_info() |
(float, float, int, float) | Returns (min_pos, max_pos, units, pitch) for the connected stage. units is an integer code (see Direction and units constants below). |
set_stage_axis_info(min_pos, max_pos, units, pitch) |
None | Sets the stage axis parameters. |
get_jog_parameters() |
(int, int, float, float, float, float) | Returns (Mode, StopMode, StepSize, MinVel, Accn, MaxVel). |
set_jog_parameters(Mode, StopMode, StepSize, MinVel, Accn, MaxVel) |
None | Sets the jog parameters. |
Note: unlike earlier versions of this package, pyThorlabsAPT no longer subclasses the underlying Motor object, so properties/methods of Motor that are not listed above (e.g. hardware_info, move_by(), move_to(), enable()/disable(), velocity/PID parameters, etc.) are not directly exposed on the driver. After connecting, you can still reach them via the motor attribute, e.g. instrument.motor.hardware_info.
Direction and units constants
move_jog() and get_stage_axis_info()/set_stage_axis_info() use a few integer constants. These are defined on the backend module in use, not on the pyThorlabsAPT class itself:
from pyThorlabsAPT.thorlabs_apt import MOVE_FWD, MOVE_REV, STAGE_UNITS_MM, STAGE_UNITS_DEG
# or, when using the virtual driver:
from pyThorlabsAPT.thorlabs_apt_virtual import MOVE_FWD, MOVE_REV, STAGE_UNITS_MM, STAGE_UNITS_DEG
| Constant | Value | Meaning |
|---|---|---|
MOVE_FWD |
1 | Move/jog in the forward direction. |
MOVE_REV |
2 | Move/jog in the reverse direction. |
STAGE_UNITS_MM |
1 | Stage units in millimeters. |
STAGE_UNITS_DEG |
2 | Stage units in degrees. |
Examples
from pyThorlabsAPT.driver import pyThorlabsAPT
from pyThorlabsAPT.thorlabs_apt import MOVE_FWD
import time
instrument = pyThorlabsAPT()
available_devices = instrument.list_devices() # Check which devices are available
print(available_devices)
device_addr = available_devices[0][1] # The address is the 2nd element of each tuple
instrument.connect_device(device_addr=device_addr) # Connect to the first available device
instrument.move_home() # Start homing
while instrument.is_in_motion: # Poll until homing is done
time.sleep(0.1)
instrument.position = 10 # Start a non-blocking absolute move to position 10
while instrument.is_in_motion:
time.sleep(0.1)
print(instrument.position)
instrument.move_jog(MOVE_FWD) # Jog forward by one jog step
print(instrument.get_stage_axis_info()) # (min_pos, max_pos, units, pitch)
instrument.disconnect_device() # Disconnect the device
Usage as a stand-alone GUI interface
The installation sets up an entry point for the GUI. Just typing
pyThorlabsAPT
in the command prompt will start the GUI. Pass -virtual to start it with the simulated driver instead of real hardware (useful for testing without a physical motor):
pyThorlabsAPT -virtual
Embed the GUI within another GUI
The GUI controller can also be easily integrated within a larger graphical interface, as shown in the example below.
import PyQt5.QtWidgets as Qt # QApplication, QWidget, QGridLayout, QLabel, QVBoxLayout
import pyThorlabsAPT
app = Qt.QApplication([])
window = Qt.QWidget()
# The GUI needs to be contained inside a widget object
widget_containing_interface_GUI = Qt.QWidget()
widget_containing_interface_GUI.setStyleSheet(
".QWidget {
"
"border: 1px solid black;
"
"border-radius: 4px;
"
"}"
)
# Create the interface object for the motor (pass virtual=True to use the simulated driver instead of real hardware)
Interface = pyThorlabsAPT.interface(app=app, virtual=False)
Interface.verbose = False # set the verbosity of the interface logger to False
# At any time during the software execution, the position read by the instrument can be accessed via Interface.output['Position']
# Moreover, one could also set up a signal to automatically call another function whenever the position is updated, by
#
# Interface.sig_update_position.connect(foo)
#
# Every time the position is read from the instrument, the function foo is called and the new position is passed as argument
# Create the GUI for the motor
view = pyThorlabsAPT.gui(interface=Interface, parent=widget_containing_interface_GUI)
# Create additional GUI
gridlayoutwidget = Qt.QWidget()
gridlayout = Qt.QGridLayout()
gridlayout.addWidget(Qt.QLabel("Additional GUI 1"), 0, 0)
gridlayout.addWidget(Qt.QLabel("Additional GUI 2"), 1, 0)
gridlayout.addWidget(Qt.QLabel("Additional GUI 3"), 0, 1)
gridlayout.addWidget(Qt.QLabel("Additional GUI 4"), 1, 1)
gridlayoutwidget.setLayout(gridlayout)
layout = Qt.QVBoxLayout()
layout.addWidget(widget_containing_interface_GUI)
layout.addWidget(gridlayoutwidget)
layout.addStretch(1)
window.setLayout(layout)
window.show()
app.exec() # Start the event loop.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pythorlabsapt-0.13.tar.gz.
File metadata
- Download URL: pythorlabsapt-0.13.tar.gz
- Upload date:
- Size: 201.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7a5648720ffc5df6cb39a07bf7e7dbec9a40df35d53f0e79124135c98535bf2
|
|
| MD5 |
66f3c64bb4765de3db9c4c390b1ea6de
|
|
| BLAKE2b-256 |
e304c443c251006bf9577bb440648326c1d957452511a120f1fa3fe1d04e4d89
|
File details
Details for the file pythorlabsapt-0.13-py3-none-any.whl.
File metadata
- Download URL: pythorlabsapt-0.13-py3-none-any.whl
- Upload date:
- Size: 198.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d332628ee3743eb823f90de33349503d77aa12a1e6d10f4eb3c08b396df815a
|
|
| MD5 |
ac64b422295346bb4611ca16f69abdc6
|
|
| BLAKE2b-256 |
4c164d46e3ff02d4d3bb293de1219e23eb74e302534861c47799aeb6a6893a3b
|