Skip to main content

Python library for Thorlabs Elliptec (ELLx) resonant piezo motor modules

Project description

tl_elliptec

Docs License: MIT Buy Me A Coffee

Python library for Thorlabs Elliptec (ELLx) resonant piezo motor modules — rotary stages, linear stages, multi-position sliders, filter wheels, and the motorized iris. Implements the ASCII-hex serial protocol from Thorlabs' own protocol manual, including a priority-based request broker so background position polling never delays a move you're waiting on.

Full documentation: tl-elliptec.readthedocs.io

This is an unofficial, community-maintained library. It is not affiliated with, endorsed by, or sponsored by Thorlabs, Inc. "Thorlabs" and "Elliptec" are trademarks of Thorlabs, Inc., used here only to identify the hardware this library talks to.

Supported devices

ELL6, ELL6B, ELL9, ELL12, ELL14, ELL15, ELL16, ELL17, ELL18, ELL20, ELL21, ELL22.

Install

pip install tl_elliptec

Or for local development:

git clone https://github.com/TapyrLabs/tl_elliptec
pip install -e ".[test]"

Quick start

One device wired straight to its controller (no hub) — construct the model class directly from the serial port; it opens and owns the port itself (Make sure to use the correct COM port for your setup):

from tl_elliptec import ELL20

with ELL20("COM5") as stage:      # "/dev/ttyUSB0" on Linux/macOS
    stage.home()
    stage.move_absolute(10)       # 10 mm — physical units, not raw pulses
    stage.move_relative(-2.5)     # -2.5 mm from wherever it now is
    print(stage.get_position())   # 7.5

Several devices on a shared bus

Create one ElliptecBus and hand it to each device — reading and moving works exactly the same as above, just addressed:

from tl_elliptec import ElliptecBus, discover_devices

with ElliptecBus("COM5") as bus:
    devices = discover_devices(bus)   # probes addresses 0-F, builds the right class for each
    for address, device in devices.items():
        print(address, type(device).__name__, device.serial_number)

    stage = devices["0"]
    stage.home()
    stage.move_absolute(45)           # 45 degrees, if it's an ELL14

First-time address setup

Every ELLx module ships from the factory at address "0". Wire two or more onto the same bus before giving them unique addresses and they all answer to "0" at once — their replies collide on the wire, so neither scan() nor discover_devices() finds anything. This has to be fixed once, per device, before they share the bus. Either let the library walk you through it, always connect one device at a time:

from tl_elliptec import ElliptecBus, setup_devices

with ElliptecBus("COM5") as bus:
    # Connect ONE new, unaddressed device at a time when prompted.
    assigned = setup_devices(bus, count=2)   # e.g. ["1", "2"]

...or do it by hand, one device connected at a time:

from tl_elliptec import ElliptecBus, ELL14

with ElliptecBus("COM5") as bus:
    stage = ELL14(bus, address="0")   # factory default, must be the only device on the bus
    stage.change_address("2")         # non-volatile -- a one-time step

Addresses persist across power cycles, so this only needs to happen once per device — after that, discover_devices() finds everything normally, every session.

Broker-handled communication and live position streaming

Normally, when many devices are connected to a single serial port, and with incessent polling, the communicaiton might go into conflict and brake. tl_elliptec implements a serial communication broker in the ElliptecBus class, the broker implements a read/write priority queue for safe command serialization. Explicitly issued commands (moves, reads, ...) always jump ahead of background polling, so polling a device's position never delays a move you're waiting on:

for position in stage.poll_position():   # a generator -- only work while it's iterated
    print(position)                       # yields only when the position actually changes

This scales to several devices on one bus without extra locking — run one poll_position() per device on its own thread, and issue moves from another thread (or the main one) whenever you like.

Full command reference are all in the docs: tl-elliptec.readthedocs.io

Running the tests

pip install -e ".[test]"
pytest

No hardware required — tests run against a scripted fake bus and check values against the manual's own worked examples.

License

MIT © Matteo Michiardi


If this library saved you some time, consider buying me a coffee ☕

Buy Me A Coffee

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tl_elliptec-1.0.1.tar.gz (40.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tl_elliptec-1.0.1-py3-none-any.whl (34.4 kB view details)

Uploaded Python 3

File details

Details for the file tl_elliptec-1.0.1.tar.gz.

File metadata

  • Download URL: tl_elliptec-1.0.1.tar.gz
  • Upload date:
  • Size: 40.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tl_elliptec-1.0.1.tar.gz
Algorithm Hash digest
SHA256 d49e3e1d456fa53b2b1b6bf4a031d92a2478767487c0430fbbb92a6bf479e04a
MD5 f70b9e402cd2fe319a66049954211b20
BLAKE2b-256 0083e9e77c5e7432e75dd95d86ae4b643071cfe7f3255076de544aa79b705de8

See more details on using hashes here.

Provenance

The following attestation bundles were made for tl_elliptec-1.0.1.tar.gz:

Publisher: publish.yml on TapyrLabs/tl_elliptec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tl_elliptec-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: tl_elliptec-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 34.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tl_elliptec-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e552d8c7dec537ca5d4525ad0dbe9cfa2db0cdbf327440afc9437c68225d61d1
MD5 c1ebbc0317434a8be74b12709e4459ec
BLAKE2b-256 524482dcc3bf179c6a233d0bc9e9ab17cdadba7ec937ee0e670c5f174c885118

See more details on using hashes here.

Provenance

The following attestation bundles were made for tl_elliptec-1.0.1-py3-none-any.whl:

Publisher: publish.yml on TapyrLabs/tl_elliptec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page