mabuchilab / Instrumental

Python-based instrumentation library from the Mabuchi Lab.
http://instrumental-lib.readthedocs.org/
GNU General Public License v3.0
117 stars 77 forks source link

Choosing device by serial number? #130

Open FilipDominec opened 3 years ago

FilipDominec commented 3 years ago

In my experiment, I use X-Y positioning with two Thorlabs TDC001 servo controllers. Of course, it is essential to identify X and Y axes correctly by controller serial number, so that the program never swaps them at startup. This could lead to crashes.

But I cannot find out how to achieve this with instrumental.

In [1]: from instrumental import instrument, list_instruments

In [2]: paramsets = list_instruments()
/home/dominecf/p/210124_getting_Thorlabs_work/instrumental/instrumental/drivers/motion/ecc100.py:26: UserWarning: Driver 'instrumental.drivers.motion.ecc100' is out of date and incompatible with the current Instrumental core. Pull requests fixing this are welcome.
  "Pull requests fixing this are welcome.".format(__name__)

In [3]: paramsets
Out[3]: 
[<ParamSet[TDC001_APT] port='/dev/ttyUSB1'>,
 <ParamSet[TDC001_APT] port='/dev/ttyUSB0'>]

In [4]: dict(paramsets[0])
Out[4]: {'classname': 'TDC001_APT', 'module': 'motion.apt', 'port': '/dev/ttyUSB1'}

Apparently, there is no access to the serial numbers. Should I dig into the code and try to reimplement similar functionality regarding serial numbers as found e.g. in https://github.com/felix92/thorpy (though that module imports usb.core to read the serial number contained in the USB device descriptor)?

FilipDominec commented 3 years ago

Actually there is a field called serial in the header file https://github.com/mabuchilab/Instrumental/blob/86bec2496d5ad87a5a90e16a0c53611ad497a010/instrumental/drivers/motion/_tdc_001/tdc_001.h#L127 But it seems that this is only used on Windows, through the module tdc_001.py. On Linux, the apt.py module is used instead, and there is no access to the serial number. (Should not this be documented?)

Another confusing attribute is this, which obviously relates to the virtual serial port over USB:

In [5]: i = instrument(list_instruments()[0])

In [5]: i._ser
Out[4]: Serial<id=0x7f8bad4b67b8, open=True>(port='/dev/ttyUSB2', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0.2, xonxoff=False, rtscts=False, dsrdtr=False)

But the "id" number changes upon each re-connection of the device.

What I expect is the access to the 8-digit number recorded permanently into, and printed on, each Thorlabs' controller.

FilipDominec commented 3 years ago

OK, I can see in the APT_Communication_Protocol_Rev_16.pdf that the MGMSG_HW_REQ_INFO message should provide also serial number.

But issuing a command that explicitly calls it,

i.get_info()

only gives the following result: b'\x06\x00T\x00\x80\x00\x01\x00\x00\x83TDC001\x00\x00\x10\x00\x0b\x00\x01\x00APT DC Motor Controller \x08\x00\x01\x00\x00\x00\x01\x00'

These bytes contain no unique serial number. Both my controllers report exactly the same.

A solution for Linux: Until a fix is issued, apparently the only reliable source of serial number is in the USB descriptor. This can be filtered as such:

def list_instruments_filter(filter_serial_number=None):
    print("DEBUG: filter_serial_number = ", filter_serial_number)
    return [ParamSet(TDC001_APT, port=p.device) for p in comports() if ((p.vid, p.pid) == (0x0403, 0xfaf0) and
        (filter_serial_number is None or p.serial_number==filter_serial_number)]
FilipDominec commented 3 years ago

The above PR fixes this simply by exposing the serial number to the end user. If the PR is merged, this issue will be solved.