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.0.tar.gz (41.0 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.0-py3-none-any.whl (34.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: tl_elliptec-1.0.0.tar.gz
  • Upload date:
  • Size: 41.0 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.0.tar.gz
Algorithm Hash digest
SHA256 f9f52f5d7fe84f42b2b44c3662f434665ff4e2c89a5ea8b3d269241a78e0f3c6
MD5 fa3904c9cbc8bd426e942998ab71a1dd
BLAKE2b-256 c3a8011c48e3b4d309574b653f9a78f44006774bccb0c6f8954008dd37f9b743

See more details on using hashes here.

Provenance

The following attestation bundles were made for tl_elliptec-1.0.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: tl_elliptec-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 34.5 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 74e9ad4be29a6f334fceb91b651a6e7805b615f4f8137045f1a89d06c506ce4f
MD5 40c93b65ebd050b80303994e8184b528
BLAKE2b-256 919f4a5c45ef3ad37fdba1745411630b25d22e4b98c324e074b43f7a2e4636f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for tl_elliptec-1.0.0-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