LeRobot documentation
Motors
Motors
MotorsBus is the low-level interface to a chain of servos on a serial bus. Robots use it to read positions
and write goal positions; you rarely touch it directly unless you are adding hardware.
See Bring Your Own Hardware for adding a new bus, and Updating Feetech Firmware and Damiao Motors and CAN Bus for device-specific notes.
MotorsBus
class lerobot.motors.motors_bus.SerialMotorsBus
< source >( port: strmotors: dict[str, Motor]calibration: dict[str, MotorCalibration] | None = None )
A SerialMotorsBus allows to efficiently read and write to motors connected via serial communication. It represents several motors daisy-chained together and connected through a serial port. There are currently two implementations of this class:
- DynamixelMotorsBus
- FeetechMotorsBus
This class is specifically for serial-based motor protocols (Dynamixel, Feetech, etc.).
A MotorsBus subclass instance requires a port (e.g. FeetechMotorsBus(port="/dev/tty.usbmodem575E0031751")).
To find the port, you can run our utility script:
lerobot-find-port.py
>>> Finding all available ports for the MotorsBus.
>>> ["/dev/tty.usbmodem575E0032081", "/dev/tty.usbmodem575E0031751"]
>>> Remove the usb cable from your MotorsBus and press Enter when done.
>>> The port of this MotorsBus is /dev/tty.usbmodem575E0031751.
>>> Reconnect the usb cable.Example of usage for 1 Feetech sts3215 motor connected to the bus:
bus = FeetechMotorsBus(
port="/dev/tty.usbmodem575E0031751",
motors={"my_motor": (1, "sts3215")},
)
bus.connect()
position = bus.read("Present_Position", "my_motor", normalize=False)
# Move from a few motor steps as an example
few_steps = 30
bus.write("Goal_Position", "my_motor", position + few_steps, normalize=False)
# When done, properly disconnect the port using
bus.disconnect()broadcast_ping
< source >( num_retry: int = 0raise_on_error: bool = False ) → dict[int, int] | None
Ping every ID on the bus using the broadcast address.
Write implementation-specific recommended settings to every motor.
Typical changes include shortening the return delay, increasing acceleration limits or disabling safety locks.
connect
< source >( handshake: bool = True )
Parameters
- handshake (bool, optional) — Pings every expected motor and performs additional
integrity checks specific to the implementation. Defaults to
True.
Raises
DeviceAlreadyConnectedError or ConnectionError
DeviceAlreadyConnectedError— The port is already open.ConnectionError— The underlying SDK failed to open the port or the handshake did not succeed.
Open the serial port and initialise communication.
disable_torque
< source >( motors: str | list[str] | None = Nonenum_retry: int = 0 )
Disable torque on selected motors.
Disabling Torque allows to write to the motors’ permanent memory area (EPROM/EEPROM).
disconnect
< source >( disable_torque: bool = True )
Close the serial port (optionally disabling torque first).
enable_torque
< source >( motors: int | str | list[str] | None = Nonenum_retry: int = 0 )
Enable torque on selected motors.
Return the current baud-rate configured on the port.
ping
< source >( motor: NameOrIDnum_retry: int = 0raise_on_error: bool = False ) → int | None
Parameters
- motor (NameOrID) — Target motor (name or ID).
- num_retry (int, optional) — Extra attempts before giving up. Defaults to
0. - raise_on_error (bool, optional) — If
Truecommunication errors raise exceptions instead of returningNone. Defaults toFalse.
Returns
int | None
Motor model number or None on failure.
Ping a single motor and return its model number.
read
< source >( data_name: strmotor: strnormalize: bool = Truenum_retry: int = 0 ) → Value
Parameters
- data_name (str) — Control-table key (e.g.
"Present_Position"). - motor (str) — Motor name.
- normalize (bool, optional) — When
True(default) scale the value to a user-friendly range as defined by the calibration. - num_retry (int, optional) — Retry attempts. Defaults to
0.
Returns
Value
Raw or normalised value depending on normalize.
Read a register from a motor.
read_calibration
< source >( ) → dict[str, MotorCalibration]
Returns
dict[str, MotorCalibration]
Mapping motor name → calibration.
Read calibration parameters from the motors.
record_ranges_of_motion
< source >( motors: NameOrID | Sequence[NameOrID] | None = Nonedisplay_values: bool = True ) → tuple[dict[str, Value], dict[str, Value]]
Parameters
- motors (NameOrID | list[NameOrID] | None, optional) — Motors to record.
Defaults to every motor (
None). - display_values (bool, optional) — When
True(default) a live table is printed to the console.
Returns
tuple[dict[str, Value], dict[str, Value]]
Two dictionaries mins and maxes with the extreme values observed for each motor.
Interactively record the min/max encoder values of each motor.
Move the joints by hand (with torque disabled) while the method streams live positions. Press
:kbd:Enter to finish.
reset_calibration
< source >( motors: NameOrID | Sequence[NameOrID] | None = None )
Restore factory calibration for the selected motors.
Homing offset is set to 0 and min/max position limits are set to the full usable range.
The in-memory :pyattr:calibration is cleared.
scan_port
< source >( port: str*args**kwargs ) → dict[int, list[int]]
Probe port at every supported baud-rate and list responding IDs.
set_baudrate
< source >( baudrate: int )
Set a new UART baud-rate on the port.
set_half_turn_homings
< source >( motors: NameOrID | Sequence[NameOrID] | None = None ) → dict[str, Value]
Centre each motor range around its current position.
The function computes and writes a homing offset such that the present position becomes exactly one
half-turn (e.g. 2047 on a 12-bit encoder).
set_timeout
< source >( timeout_ms: int | None = None )
Change the packet timeout used by the SDK.
setup_motor
< source >( motor: strinitial_baudrate: int | None = Noneinitial_id: int | None = None )
Parameters
- motor (str) — Key of the motor in :pyattr:
motors. - initial_baudrate (int | None, optional) — Current baud-rate (skips scanning when provided). Defaults to None.
- initial_id (int | None, optional) — Current ID (skips scanning when provided). Defaults to None.
Raises
RuntimeError or ConnectionError
RuntimeError— The motor could not be found or its model number does not match the expected one.ConnectionError— Communication with the motor failed.
Assign the correct ID and baud-rate to a single motor.
This helper temporarily switches to the motor’s current settings, disables torque, sets the desired ID, and finally programs the bus’ default baud-rate.
sync_read
< source >( data_name: strmotors: NameOrID | Sequence[NameOrID] | None = Nonenormalize: bool = Truenum_retry: int = 0 ) → dict[str, Value]
Parameters
- data_name (str) — Register name.
- motors (NameOrID | Sequence[NameOrID] | None, optional) — Motors to query.
None(default) reads every motor. - normalize (bool, optional) — Normalisation flag. Defaults to
True. - num_retry (int, optional) — Retry attempts. Defaults to
0.
Returns
dict[str, Value]
Mapping motor name → value.
Read the same register from several motors at once.
sync_write
< source >( data_name: strvalues: Value | dict[str, Value]normalize: bool = Truenum_retry: int = 0 )
Parameters
- data_name (str) — Register name.
- values (Value | dict[str, Value]) — Either a single value (applied to every motor) or a mapping motor name → value.
- normalize (bool, optional) — If
True(default) convert values from the user range to raw units. - num_retry (int, optional) — Retry attempts. Defaults to
0.
Write the same register on multiple motors.
Contrary to :pymeth:write, this does not expects a response status packet emitted by the motor, which
can allow for lost packets. It is faster than :pymeth:write and should typically be used when
frequency matters and losing some packets is acceptable (e.g. teleoperation loops).
Context-manager that guarantees torque is re-enabled.
This helper is useful to temporarily disable torque when configuring motors.
Examples:
with bus.torque_disabled(): … # Safe operations here … pass
write
< source >( data_name: strmotor: strvalue: Valuenormalize: bool = Truenum_retry: int = 0 )
Parameters
Write a value to a single motor’s register.
Contrary to :pymeth:sync_write, this expects a response status packet emitted by the motor, which
provides a guarantee that the value was written to the register successfully. In consequence, it is
slower than :pymeth:sync_write but it is more reliable. It should typically be used when configuring
motors.
write_calibration
< source >( calibration_dict: dict[str, MotorCalibration]cache: bool = True )
Write calibration parameters to the motors and optionally cache them.
Motor
class lerobot.motors.Motor
< source >( id: intmodel: strnorm_mode: MotorNormModemotor_type_str: str | None = Nonerecv_id: int | None = None )
MotorCalibration
class lerobot.motors.MotorCalibration
< source >( id: intdrive_mode: inthoming_offset: intrange_min: intrange_max: int )