pystage-apt
is a library to communicate with various Thorlabs’ APT single-channel controllers and control different types of Thorlabs’ actuator motors. It contains a large collection of motor control messages obtained from Thorlabs APT Controllers Host-Controller Communications Protocol. This document describes the low-level communications protocol and commands used between the host PC and controller units within the APT family. Those messages are included in a series of python files and are stored in a folder named ctrl_msg.
After you connect Thorlabs APT controllers (with stages connected) to your PC or a Raspberry Pi through USB ports, type and run the code below in, for example, Terminal, to get the controllers discovered by pystage-apt
.
>>> from stage.motor_ini.core import find_stages
>>> s = list(find_stages())
Success: Stage MTS25-Z8 is detected and a controller with serial number 83845481 is connected via
port /dev/ttyUSB1
Success: Stage Z812 is detected and a controller with serial number 83844171 is connected via
port /dev/ttyUSB0
Once you see the success messages like these, congratulations, the controllers along with the stages are 'constructed' and are ready to be manipulated through recognised commands! Ta-da!
>>> s1 = s[1]
>>> s2 = s[0]
>>> s1.status
>>> s2.status
pystage-apt
works on Linux and Raspbian, in any console or in a GUI, and is also friendly with IPython/Jupyter notebooks.
Table of contents
pip install pystage-apt
Pull and install in the current directory:
pip install -e git+https://github.com/kzhao1228/pystage_apt.git@master#egg=pystage_apt
The list of all changes is available on GitHub's Releases:
pystage-apt
supports computationally constructing Thorlabs APT controllers on Linux and Raspbian. It may work on MacOS too only if you can find a way to create a /dev
entry for raw access to USB devices. Because currently there is no way to access them as tty
devices. For Windows, you can try thorlabs_apt.
Note that, before you try to implement this library, you should first configure the /etc/udev/rules.d/99-com.rules
file to avoid potential access permission error on USB device. To do this, open a Terminal window, type and run the command:
sudo nano /etc/udev/rules.d/99-com.rules
Adding to this file with contents like this:
SUBSYSTEM=="usb", ATTR{idVendor}=="HEX1", ATTR{idProduct}=="HEX2", MODE="0666"
where HEX1 and HEX2 are replaced with the vendor and product id respectively. For example, this content could be:
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="faf0", MODE="0666"
However, if you don't know the information, you could try typing and running the command lsusb
in Terminal which should give you:
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 0403:faf0 Future Technology Devices International, Ltd
Bus 001 Device 003: ID 0403:faf0 Future Technology Devices International, Ltd
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
where idVendor:idProduct
contains the information you need. After finishing editing the file, hit Ctrl+O
to write out and hit enter
to confirm the file name. To exit the file editing mode, simply hit Ctrl+X
.
Function find_stages
[1] scans all connected USB devices and searches for Thorlabs APT controllers. If no controllers are found, function list(find_stages())
returns an empty list. However, if one or more are found, list(find_stages())
returns success messages along with a list of elements in type stage.motor_ctrl.MotorCtrl
. These elements, which read SingleControllerPort('PORT_ENTRY',SERIAL_NO)
, store information as to created serial port entry and controller serial number in the arguments of Class SingleControllerPort
[2] respectively. This class contains a method named get_stages
that calls class MotorCtrl
[3], stores it in a dictionary as a value of a key and returns the dictionary. This value is extracted by functions p = Port.create('PORT_ENTRY',SERIAL_NO)
and p.get_stages().values()
[4] when find_stages
[1] is being implemented.
Port.create('PORT_ENTRY',SERIAL_NO)
[4] calls method create
[5] of class Port
[6] which then calls SingleControllerPort
[2] and returns it. Therefore, list(find_stages())
basically returns a list of callable MotorCtrl
[3], each of which is dependent of a detected stage. Upon calling instances, properties and methods included in MotorCtrl
[3], their corresponding control messages [5] are invoked to structure a series of instructions to be delivered to the controllers and these instructions are decoded to strings of hexadecimal characters that can be understood by the controllers before they are sent out.