devices¶
Every command in the manual, split by what it applies to:
All devices (
ElliptecDevice):get_info,refresh_calibration,get_status,save_user_data,change_address,isolate_minutes,group_address,skip_frequency_search,get_motor_info(1|2),set_forward_period/set_forward_frequency,set_backward_period/set_backward_frequency,search_frequency,scan_current_curve,get_position/get_position_pulses,forward/forward_pulses,backward/backward_pulses,get_button_status(non-blocking poll for spontaneous BS/BO messages).Rotary / linear / iris stages (
MotionMixin— not multi-position sliders):home/home_pulses,move_absolute/move_absolute_pulses,move_relative/move_relative_pulses,get_home_offset/set_home_offset(+_pulsesvariants),get_jog_step_size/set_jog_step_size(+_pulsesvariants),get_velocity/set_velocity,stop(see The stop() command).ELL15 iris (
AutoHomingMixin):set_auto_homing/set_auto_homing_pulses.ELL14/15/16/17/18/20/21/22 (
OptimizeCleanMixin):optimize_motors,clean_mechanics(not on ELL15),stop.ELL22 (
ZeroPositionMixin,ResetFactoryMixin):set_zero_position,get_zero_position_offset/get_zero_position_offset_pulses,reset_factory_default.
Capability gating (e.g. no f1/b1 tuning or button messages on
ELL16/ELL21/ELL22; no second motor on ELL6) follows the individual “THIS
MESSAGE DOES NOT APPLY TO…” notes attached to each command in the
manual, since the summary applicability tables at the end of the document
are inconsistent with those notes and with each other. Calling an
unsupported method raises ElliptecUnsupportedError
instead of sending a doomed command to the device.
Base class and capability mixins¶
Base device class and capability mixins for ELLx modules.
ElliptecDevice implements every command that is common to all ELLx
modules (identification, status, saving parameters, addressing, per-motor
tuning, isolation). Commands that only some device families support are
implemented as mixins (MotionMixin, AutoHomingMixin,
OptimizeCleanMixin, ZeroPositionMixin, ResetFactoryMixin) and are
composed onto the concrete model classes in tl_elliptec.devices.models
according to what section 3 (“applicability”) of each command in the manual
states.
- class tl_elliptec.devices.base.DeviceInfo(address, ell_type, serial_number, year, firmware_release, hardware_release, is_imperial, travel, pulses_per_unit)[source]¶
Bases:
objectParsed reply to HOSTREQ_INFORMATION “in” / DEVGET_INFORMATION “IN”.
- Parameters:
- ell_type: int¶
Decimal model number, e.g.
14for an ELL14 (decoded from the wire’s hex-ASCII field – seefrom_reply()).
- hardware_release: int¶
Hardware release number (7 bits, the thread-type bit already split out into
is_imperial).
- travel: int¶
Full travel of the stage, in mm or degrees per the model table (not corrected for any per-model quirks).
- pulses_per_unit: int¶
Raw “PULSES/M.U.” field as reported by the device. On rotary stages this is empirically pulses-per-revolution, not pulses-per-degree – see
ElliptecDevice.PULSES_FIELD_IS_PER_REVOLUTIONfor the correction applied when computingElliptecDevice.pulses_per_unit.
- classmethod from_reply(reply)[source]¶
Parse an “IN” reply into a
DeviceInfo.- Parameters:
reply (Reply) – The device’s reply to a HOSTREQ_INFORMATION “in” request.
- Returns:
The parsed device information.
- Return type:
- class tl_elliptec.devices.base.MotorInfo(loop_on, motor_on, current_amps, forward_period, backward_period)[source]¶
Bases:
objectParsed reply to HOSTREQ_MOTORxINFO “i1”/”i2”.
- Parameters:
- forward_period: int¶
Raw forward resonant “period” value (see
period_for_frequency()to convert to/from Hz).
- property forward_frequency_hz: float | None¶
Forward resonant frequency in Hz, or
Noneif undefined (period is 0 or 0xFFFF).
- class tl_elliptec.devices.base.CurrentCurveSample(period, current_amps)[source]¶
Bases:
objectOne (frequency, current) sample from
ElliptecDevice.scan_current_curve().- period: int¶
Raw resonant “period” value at this sample (see
frequency_hzto convert to Hz).
- tl_elliptec.devices.base.period_for_frequency(frequency_hz)[source]¶
Convert a target resonant frequency to the protocol’s “period” units.
- Parameters:
frequency_hz (float) – Target frequency, in Hz.
- Returns:
The equivalent raw “period” value, as used by
ElliptecDevice.set_forward_period()/set_backward_period.- Return type:
- class tl_elliptec.devices.base.ElliptecDevice(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
objectCommands common to every ELLx module.
Can be constructed two ways:
Point-to-point (one controller wired straight to one device):
stage = ELL14("COM5") # owns and opens the serial port itself
Shared multidrop bus (a hub with several addressed devices):
bus = ElliptecBus("COM5") stage = ELL14(bus, address="2") # bus is shared, not owned/closed by the device slider = ELL9(bus, address="3")
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- has_motor2: bool = True¶
Overridden by subclasses. Some families lack a second motor (ELL6), and ELL16/ELL21/ELL22 do not support tunable forward/backward periods or the hardware-button spontaneous status messages.
- DEFAULT_PULSES_PER_UNIT: float = 1.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = False¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- close()[source]¶
Close the underlying serial port, but only if this device opened it itself.
- Return type:
None
- property info: DeviceInfo | None¶
The DeviceInfo from the last successful get_info()/refresh_calibration() call.
Populated automatically at construction time (see
__init__), so it’s normally already available – e.g. right afterdiscover_devices()– without an extra round trip.Noneif the device has never successfully answered an “in” request (e.g. constructed before it was wired up; callrefresh_calibration()once it’s reachable).
- property serial_number: str | None¶
Shortcut for
info.serial_number;Noneifinfoisn’t available yet.
- refresh_calibration()[source]¶
Query the device and cache its pulses-per-unit and full-range pulse counts.
- Returns:
The freshly queried device information (also cached as
info).- Raises:
ElliptecTimeoutError – If the device doesn’t answer.
- Return type:
- property pulses_per_unit: float¶
Encoder pulses per mm/degree, from live calibration if available, else the model default.
- property pulses_per_full_range: int¶
encoder pulses across the device’s whole travel.
This is the denominator used by the “_range” methods (e.g.
get_position_range), which report position as a 0..1 fraction of full travel instead of physical units. Unlikepulses_per_unit, there’s no static per-model fallback for this – callrefresh_calibration()once the device is reachable.- Raises:
ElliptecError – If calibration has never succeeded for this device.
- Type:
Raw PULSES/M.U. value from get_info()
- get_info()[source]¶
HOSTREQ_INFORMATION “in” / DEVGET_INFORMATION “IN”.
- Returns:
The device’s identification info.
- Return type:
- get_status()[source]¶
HOSTREQ_STATUS “gs” / DEVGET_STATUS “GS”. Reading the status clears it.
- Returns:
The device’s current status/error code.
- Return type:
- save_user_data()[source]¶
HOSTREQ_SAVE_USER_DATA “us”. Persists tuned motor/user parameters to EEPROM.
- Return type:
None
- change_address(new_address)[source]¶
HOSTREQ_CHANGEADDRESS “ca”. Device replies from the new address.
- Parameters:
new_address (str) – The new single hex-digit address to assign.
- Raises:
ValueError – If
new_addressisn’t a valid single hex digit.- Return type:
None
- isolate_minutes(minutes)[source]¶
HOST_ISOLATEMINUTES “is”. Device will not reply for this many minutes.
- Parameters:
minutes (int) – How long to isolate the device for.
- Return type:
None
- group_address(temporary_address)[source]¶
HOST_GROUPADDRESS “ga”. Device listens on
temporary_addressuntil its next move.- Parameters:
temporary_address (str) – Single hex-digit address to listen on temporarily, for synchronizing moves across several devices.
- Raises:
ValueError – If
temporary_addressisn’t a valid single hex digit.- Return type:
None
- skip_frequency_search()[source]¶
HOSTREQ_SKIP_FREQUENCY “sk”. Skips the startup frequency scan; needs EEPROM reset to undo.
- Return type:
None
- get_motor_info(motor)[source]¶
HOSTREQ_MOTORxINFO “i1”/”i2”.
- Parameters:
motor (int) – Which motor to query,
1or2.- Returns:
The motor’s current state and tuning.
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If
motoris2and this device only has one motor.
- Return type:
- set_forward_period(motor, period)[source]¶
HOSTSET_FWP_MOTORx “f1”/”f2”. Pass
Noneto restore the factory default.- Parameters:
motor (int) – Which motor to tune,
1or2.period (int | None) – The raw forward “period” value to set (see
period_for_frequency()), orNoneto restore the factory default.
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If this device doesn’t support forward/backward period tuning, or lacks the requested motor.
- Return type:
None
- set_forward_frequency(motor, frequency_hz)[source]¶
Set a motor’s forward resonant frequency directly, in Hz.
- Parameters:
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If this device doesn’t support forward/backward period tuning, or lacks the requested motor.
- Return type:
None
- set_backward_period(motor, period)[source]¶
HOSTSET_BWP_MOTORx “b1”/”b2”. Pass
Noneto restore the factory default.- Parameters:
motor (int) – Which motor to tune,
1or2.period (int | None) – The raw backward “period” value to set (see
period_for_frequency()), orNoneto restore the factory default.
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If this device doesn’t support forward/backward period tuning, or lacks the requested motor.
- Return type:
None
- set_backward_frequency(motor, frequency_hz)[source]¶
Set a motor’s backward resonant frequency directly, in Hz.
- Parameters:
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If this device doesn’t support forward/backward period tuning, or lacks the requested motor.
- Return type:
None
- search_frequency(motor, timeout=30.0)[source]¶
HOSTREQ_SEARCHFREQ_MOTORx “s1”/”s2”. The moving part may move. Remember to save_user_data().
- Parameters:
- Returns:
The resulting status code.
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If
motoris2and this device only has one motor.
- Return type:
- scan_current_curve(motor, timeout=15.0)[source]¶
HOSTREQ_SCANCURRENTCURVE_MOTORx “c1”/”c2” + DEVGET_CURRENTCURVEMEASURE “C1”/”C2”.
Takes up to ~12 seconds on the device.
- Parameters:
- Returns:
Up to 87 (period, current) samples spanning ~70-120 kHz.
- Raises:
ValueError – If
motorisn’t1or2.ElliptecUnsupportedError – If
motoris2and this device only has one motor.
- Return type:
- get_position_pulses(priority=0)[source]¶
HOST_GETPOSITION “gp” / DEV_GETPOSITION “PO”. Raw encoder pulses, signed.
- Parameters:
priority (int) – Forwarded to the bus’s request broker (see
RequestPriority); leave it at the default unless this call is opportunistic background polling that shouldn’t delay other, explicitly issued commands (seepoll_position).- Returns:
The current position, in raw encoder pulses.
- Return type:
- get_position(priority=0)[source]¶
Current position in mm or degrees (see
pulses_per_unit).- Parameters:
priority (int) – Forwarded to the bus’s request broker; see
get_position_pulses().- Returns:
The current position, in mm or degrees.
- Return type:
- get_position_range(priority=0)[source]¶
Current position as a 0..1 fraction of the device’s full travel.
- Parameters:
priority (int) – Forwarded to the bus’s request broker; see
get_position_pulses().- Returns:
The current position, as a 0..1 fraction of full travel.
- Return type:
- forward_pulses(timeout=30.0)[source]¶
HOST_FORWARD “fw”. Moves by the configured jog step (or continuously, see
MotionMixin).
- get_button_status()[source]¶
Poll once, without blocking indefinitely, for a spontaneous BS/BO message.
These messages are pushed by the device when its physical FWD/BWD/JOG buttons are used; they are not solicited by a host command.
- Returns:
The spontaneous reply, or
Noneif nothing arrived within a short timeout.- Raises:
ElliptecUnsupportedError – If this device doesn’t support button status messages.
- Return type:
Reply | None
- poll_position(interval=0.15, tolerance=0.0, stop_event=None)[source]¶
Yield the position (mm/degrees), polling roughly every
intervalseconds.Only yields when the position has changed by more than
tolerancesince the last yielded value (default 0: yield on any change). Transient read errors (e.g. a busy status) are swallowed and simply retried on the next tick rather than raised.Polling requests are issued at
RequestPriority.POLL(seetl_elliptec.bus.RequestPriority), so they never delay explicitly issued commands sharing the same bus, including ones for other devices on a multidrop hub.Pass
stop_event(athreading.Event) to stop the loop cleanly from another thread – handy when this generator is being driven by a dedicated polling thread, e.g.:stop = threading.Event() t = threading.Thread(target=lambda: [on_position(p) for p in stage.poll_position(stop_event=stop)]) t.start() ... stop.set() t.join()
Without
stop_event, stop iteration the normal way (breakout of aforloop consuming it, or call.close()on the generator from the same thread that’s driving it).- Parameters:
- Yields:
The position, in mm or degrees, each time it changes by more than
tolerance.- Return type:
- poll_position_pulses(interval=0.15, tolerance=0.0, stop_event=None)[source]¶
Like
poll_position, but yields raw encoder pulses.- Parameters:
- Yields:
The position, in raw encoder pulses, each time it changes by more than
tolerance.- Return type:
- class tl_elliptec.devices.base.MotionMixin[source]¶
Bases:
objectho, ma, mr, home-offset, jog-step-size, velocity: not on multi-position sliders.
As with the base class’s position methods, the plain-named methods here (
home,move_absolute,move_relative,get_home_offset,set_home_offset,get_jog_step_size,set_jog_step_size) work in physical units (mm or degrees);_pulses-suffixed twins work in raw encoder pulses, and_range-suffixed twins (onhome,move_absolute,move_relative) work in a 0..1 fraction of the device’s full travel.- home_pulses(direction=0, timeout=30.0)[source]¶
HOSTREQ_HOME “ho”.
- Parameters:
- Returns:
The resulting position, in raw encoder pulses, or
Noneif the reply carried no position.- Return type:
int | None
- home(direction=0, timeout=30.0)[source]¶
Move to the home position.
- Parameters:
- Returns:
The resulting position, in mm or degrees, or
Noneif the reply carried no position.- Return type:
float | None
- home_range(direction=0, timeout=30.0)[source]¶
Move to the home position.
- Parameters:
- Returns:
The resulting position, as a 0..1 fraction of full travel, or
Noneif the reply carried no position.- Return type:
float | None
- move_absolute(position, timeout=30.0)[source]¶
Move to an absolute position in mm or degrees (see
pulses_per_unit).
- move_absolute_range(fraction, timeout=30.0)[source]¶
Move to an absolute position given as a 0..1 fraction of the device’s full travel.
- move_relative(delta, timeout=30.0)[source]¶
Move by a relative distance in mm or degrees (see
pulses_per_unit).
- move_relative_range(fraction, timeout=30.0)[source]¶
Move by a relative distance given as a fraction of the device’s full travel.
- get_home_offset_pulses()[source]¶
HOSTREQ_HOMEOFFSET “go” / DEVGET_HOMEOFFSET “HO”.
- Returns:
Distance of the home position from the absolute limit of travel, in raw encoder pulses.
- Return type:
- get_home_offset()[source]¶
Distance of the home position from the absolute limit of travel, in units.
- Returns:
The home offset, in mm or degrees.
- Return type:
- set_home_offset_pulses(offset)[source]¶
HOSTSET_HOMEOFFSET “so”.
- Parameters:
offset (int) – New home offset, in raw encoder pulses.
- Return type:
None
- set_home_offset(offset)[source]¶
Set the distance of the home position from the absolute limit of travel.
- Parameters:
offset (float) – New home offset, in mm or degrees.
- Return type:
None
- get_jog_step_size_pulses()[source]¶
HOSTREQ_JOGSTEPSIZE “gj” / DEVGET_JOGSTEPSIZE “GJ”.
- Returns:
The configured jog step size, in raw encoder pulses.
- Return type:
- get_jog_step_size()[source]¶
Get the configured jog step size, in mm or degrees.
- Returns:
The configured jog step size, in mm or degrees.
- Return type:
- set_jog_step_size_pulses(step)[source]¶
HOSTSET_JOGSTEPSIZE “sj”. A step of 0 enables continuous motion on ELL14 (use with stop()).
- Parameters:
step (int) – New jog step size, in raw encoder pulses.
- Return type:
None
- set_jog_step_size(step)[source]¶
Set the jog step size used by
forward()/backward().- Parameters:
step (float) – New jog step size, in mm or degrees.
- Return type:
None
- get_velocity()[source]¶
HOSTREQ_VELOCITY “gv” / DEVGET_VELOCITY “GV”.
- Returns:
The velocity compensation, as a percentage (0-100) of max velocity.
- Return type:
- set_velocity(percent)[source]¶
HOSTSET_VELOCITY “sv”. 25-45%+ typical minimum before stalling; 50% minimum on ELL16/ELL21.
- Parameters:
percent (int) – Velocity compensation, as a percentage (0-100) of max velocity.
- Raises:
ValueError – If
percentis outside 0-100.- Return type:
None
- stop()[source]¶
HOST_MOTIONSTOP “st”. Stops continuous motion (ELL14) or an optimize/clean cycle.
Confirmed on real hardware: this does not interrupt a bounded
move_absolute/move_relative/homeonce issued – the move keeps running until the physical motion completes, exactly as ifstop()was never called. It only affects continuous jog motion (jog step size 0, started viaforward/backward) or an in-progress optimize/clean cycle.Sent as an urgent, queue-bypassing write (see
ElliptecBus.send_urgent) rather than a normal request, since the whole point is interrupting a command that’s already in flight – that job’s own read loop is what’s occupying the bus, so a normal request would just queue harmlessly behind it. Doesn’t wait for a reply; callget_status()/get_position()afterward if you need to confirm the outcome.- Return type:
None
- class tl_elliptec.devices.base.AutoHomingMixin[source]¶
Bases:
objectah: ELL15 motorized iris only.
- set_auto_homing_pulses(enabled, timeout=30.0)[source]¶
HOSTSET_AUTOHOMING “ah”. Home-at-startup toggle for the ELL15.
- class tl_elliptec.devices.base.OptimizeCleanMixin[source]¶
Bases:
objectom, cm, st: ELL14/15/16/17/18/20/21/22.
supports_cleangates cm (ELL15 lacks it).- optimize_motors(timeout=300.0)[source]¶
HOST_OPTIMIZE_MOTORS “om”. Can take several minutes; occupies the whole bus.
- Parameters:
timeout (float) – Reply timeout, in seconds (default allows several minutes for the optimization cycle to complete).
- Returns:
The resulting status code.
- Return type:
- clean_mechanics(timeout=300.0)[source]¶
HOST_CLEAN_MECHANICS “cm”. Can take several minutes; occupies the whole bus.
- Parameters:
timeout (float) – Reply timeout, in seconds (default allows several minutes for the cleaning cycle to complete).
- Returns:
The resulting status code.
- Raises:
ElliptecUnsupportedError – If this device doesn’t support the cleaning cycle (e.g. the ELL15).
- Return type:
- stop()[source]¶
HOST_MOTIONSTOP “st”. Aborts an in-progress optimize/clean cycle.
Sent as an urgent, queue-bypassing write (see
ElliptecBus.send_urgent) since the optimize/clean command already in flight is what’s occupying the bus; a normal request would just queue behind it. Doesn’t wait for a reply – callget_status()afterward if you need to confirm the abort.- Return type:
None
- class tl_elliptec.devices.base.ZeroPositionMixin[source]¶
Bases:
objectsz, gz: ND filter rotator (ELL22) only.
- set_zero_position()[source]¶
HOSTSET_ZEROPOSITION “sz”. Makes the current encoder position the new logical zero.
- Returns:
The resulting status code.
- Return type:
Concrete models¶
Concrete classes for every ELLx module covered by the protocol manual.
Capability composition follows the per-command “applicability” notes in the manufacturer manual (not the summary index tables at the end of the manual, which are inconsistent with the per-command notes and with each other):
Model Travel type Motors Motion cmds Optimize/Clean Extras
ELL6 31mm slider (index) 1 -
ELL6B 31mm slider (index) 2 -
ELL9 31mm slider (index) 2 -
ELL12 19mm slider (index) 2 -
ELL14 360 deg rotary 2 yes both -
ELL15 iris 2 yes optimize only auto-homing
ELL16 360 deg rotary 2 yes both no f/b tuning, no buttons
ELL17 28mm linear 2 yes both -
ELL18 360 deg rotary 2 yes both -
ELL20 60mm linear 2 yes both -
ELL21 360 deg rotary 2 yes both no f/b tuning, no buttons
ELL22 360 deg filter rot. 2 yes both no f/b tuning, no buttons,
zero-position, factory reset
- class tl_elliptec.devices.models.ELL6(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
ElliptecDeviceBi-positional slider, 1 motor, 31mm indexed travel.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- class tl_elliptec.devices.models.ELL6B(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
ElliptecDeviceMulti-position slider, 2 motors, 31mm indexed travel.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- class tl_elliptec.devices.models.ELL9(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
ElliptecDeviceMulti-position slider, 2 motors, 31mm indexed travel.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- class tl_elliptec.devices.models.ELL12(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
ElliptecDeviceMulti-position slider, 2 motors, 19mm indexed travel.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- class tl_elliptec.devices.models.ELL14(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceRotary stage, 360 deg, 398 pulses/deg.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 398.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = True¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- class tl_elliptec.devices.models.ELL15(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
AutoHomingMixin,MotionMixin,OptimizeCleanMixin,ElliptecDeviceMotorized iris.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 1000.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- class tl_elliptec.devices.models.ELL16(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceRotary stage, 360 deg, 182 pulses/deg.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 182.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = True¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- class tl_elliptec.devices.models.ELL17(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceLinear stage, 28mm, 1024 pulses/mm.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 1024.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- class tl_elliptec.devices.models.ELL18(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceRotary stage, 360 deg, 398 pulses/deg.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 398.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = True¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- class tl_elliptec.devices.models.ELL20(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceLinear stage, 60mm, 1024 pulses/mm.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 1024.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- class tl_elliptec.devices.models.ELL21(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
MotionMixin,OptimizeCleanMixin,ElliptecDeviceRotary stage, 360 deg, 182 pulses/deg.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 182.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = True¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- class tl_elliptec.devices.models.ELL22(port_or_bus, address='0', timeout=None, **bus_kwargs)[source]¶
Bases:
ZeroPositionMixin,ResetFactoryMixin,MotionMixin,OptimizeCleanMixin,ElliptecDeviceND filter rotary stage, 360 deg, 182 pulses/deg.
- Parameters:
port_or_bus (Union[str, ElliptecBus])
address (str)
timeout (Optional[float])
- DEFAULT_PULSES_PER_UNIT: float = 182.0¶
Fallback encoder-pulses-per-unit (per mm or per degree) used by unit-based position methods (move_absolute, get_position, …) when live calibration from get_info() isn’t available. 1 is a safe identity default for devices with no natural physical unit (e.g. indexed multi-position sliders); motion-capable subclasses override this with the pulses/mm or pulses/degree value from the model table in the manual. This is always the corrected per-unit value, i.e. after the PULSES_FIELD_IS_PER_REVOLUTION adjustment below has already been applied conceptually.
- PULSES_FIELD_IS_PER_REVOLUTION: bool = True¶
On rotary stages (ELL14/16/18/21/22), the “PULSES/M.U.” field reported by get_info() is empirically the encoder count for one full revolution (e.g. 143360 for the ELL14), not pulses-per-degree as the field name suggests – dividing raw position by it directly yields a 0..1 fraction of the full travel, not degrees. The true pulses-per-degree is that field divided by the reported travel (e.g. 143360 / 360 = 398.2, matching the manual’s documented “398 pulse/deg”). Linear stages (ELL17/ELL20) and the slider/iris families do not show this: their reported field already is pulses/mm or pulses/position, so this stays False for them.
- tl_elliptec.devices.models.MODEL_REGISTRY: dict[int, type[ElliptecDevice]] = {6: <class 'tl_elliptec.devices.models.ELL6'>, 9: <class 'tl_elliptec.devices.models.ELL9'>, 12: <class 'tl_elliptec.devices.models.ELL12'>, 14: <class 'tl_elliptec.devices.models.ELL14'>, 15: <class 'tl_elliptec.devices.models.ELL15'>, 16: <class 'tl_elliptec.devices.models.ELL16'>, 17: <class 'tl_elliptec.devices.models.ELL17'>, 18: <class 'tl_elliptec.devices.models.ELL18'>, 20: <class 'tl_elliptec.devices.models.ELL20'>, 21: <class 'tl_elliptec.devices.models.ELL21'>, 22: <class 'tl_elliptec.devices.models.ELL22'>}¶
Maps the decimal model number (14 for an ELL14, etc.) reported by “in”/”IN” – decoded from the wire’s hex-ASCII “ELL type” field by
DeviceInfo.from_reply– to its class. Keyed by the plain decimal number on purpose: the hex-vs-decimal conversion belongs at that one wire boundary, not scattered through code that just wants to know “is this an ELL14”. Note: ELL6 and ELL6B both report type 6 (they differ only in motor count); the factory disambiguates them by probing for a second motor.