LeRobot documentation
Robots
Robots
Every robot in LeRobot implements the Robot interface: connect, read an observation, send an action,
disconnect. Writing a policy or a recording script against that interface means it works with any supported
arm without change.
This page is the generated reference. For wiring, calibration and first-run instructions, start with the hardware guides — SO-101, LeKiwi, Hope Jr, Reachy 2, OpenArm — or Imitation Learning for Robots for the end-to-end workflow. To add a robot of your own, see Bring Your Own Hardware.
Robot
The abstract base class. Subclasses implement every method below; the contract described here is what a policy or recording loop can rely on.
class lerobot.robots.Robot
< source >( config: RobotConfig )
The base abstract class for all LeRobot-compatible robots.
This class provides a standardized interface for interacting with physical robots. Subclasses must implement all abstract methods and properties to be usable.
connect
< source >( calibrate: bool = True )
Establish communication with the robot.
Disconnect from the robot and perform any necessary cleanup.
Apply any one-time or runtime configuration to the robot. This may include setting motor parameters, control modes, or initial state.
Calibrate the robot if applicable. If not, this should be a no-op.
This method should collect any necessary data (e.g., motor offsets) and update the
:pyattr:calibration dictionary accordingly.
get_observation
< source >( ) → RobotObservation
Returns
RobotObservation
A flat dictionary representing the robot’s current sensory state. Its structure
should match :pymeth:observation_features.
Retrieve the current observation from the robot.
send_action
< source >( action: dict ) → RobotAction
Send an action command to the robot.
A dictionary describing the structure and types of the observations produced by the robot.
Its structure (keys) should match the structure of what is returned by :pymeth:get_observation.
Values for the dict should either be:
- The type of the value if it’s a simple value, e.g.
floatfor single proprioceptive value (a joint’s position/velocity) - A tuple representing the shape if it’s an array-type value, e.g.
(height, width, channel)for images
Note: this property should be able to be called regardless of whether the robot is connected or not.
A dictionary describing the structure and types of the actions expected by the robot. Its structure
(keys) should match the structure of what is passed to :pymeth:send_action. Values for the dict
should be the type of the value if it’s a simple value, e.g. float for single proprioceptive value
(a joint’s goal position/velocity)
Note: this property should be able to be called regardless of whether the robot is connected or not.
Whether the robot is currently connected or not. If False, calling :pymeth:get_observation or
:pymeth:send_action should raise an error.
Whether the robot is currently calibrated or not. Should be always True if not applicable
RobotConfig
class lerobot.robots.RobotConfig
< source >( id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
make_robot_from_config
SO-100 and SO-101 followers
SO100Follower and SO101Follower are aliases of the same SOFollower class; the two arms differ in their
configuration, not their control code. SO100FollowerConfig and SO101FollowerConfig are likewise aliases
of SOFollowerRobotConfig.
Generic SO follower base implementing common functionality for SO-100/101/10X.
Designed to be subclassed with a per-hardware-model config_class and name.
We assume that at connection time, arm is in a rest position, and torque can be safely disabled to run calibration.
send_action
< source >( action: dict ) → RobotAction
Returns
RobotAction
the action sent to the motors, potentially clipped.
Raises
RobotDeviceNotConnectedError
RobotDeviceNotConnectedError— if robot is not connected.
Command arm to move to a target joint configuration.
The relative action magnitude may be clipped depending on the configuration parameter max_relative_target. In this case, the action sent differs from original action.
Thus, this function always returns the action actually sent.
class lerobot.robots.so_follower.SOFollowerRobotConfig
< source >( port: strdisable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>use_degrees: bool = Trueposition_p_coefficient: int = 16position_i_coefficient: int = 0position_d_coefficient: int = 32num_read_retries: int = 2id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
BiSOFollower
Two SO followers driven as one bimanual robot.
Bimanual SO Follower Arms designed by TheRobotStudio
class lerobot.robots.bi_so_follower.BiSOFollowerConfig
< source >( left_arm_config: SOFollowerConfigright_arm_config: SOFollowerConfigcameras: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Configuration class for Bi SO Follower robots.
KochFollower
- Koch v1.0, with and without the wrist-to-elbow expansion, developed by Alexander Koch from Tau Robotics
- Koch v1.1 developed by Jess Moss
We assume that at connection time, arm is in a rest position, and torque can be safely disabled to run calibration.
send_action
< source >( action: dict ) → RobotAction
Command arm to move to a target joint configuration.
The relative action magnitude may be clipped depending on the configuration parameter max_relative_target. In this case, the action sent differs from original action.
Thus, this function always returns the action actually sent.
class lerobot.robots.koch_follower.KochFollowerConfig
< source >( port: strdisable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>use_degrees: bool = Falseid: str | None = Nonecalibration_dir: pathlib.Path | None = None )
LeKiwi
LeKiwi runs on the robot itself. LeKiwiClient is the host-side proxy that talks to it over the network
and presents the same Robot interface.
The robot includes a three omniwheel mobile base and a remote follower arm. The leader arm is connected locally (on the laptop) and its joint positions are recorded and then forwarded to the remote follower arm (after applying a safety clamp). In parallel, keyboard teleoperation is used to generate raw velocity commands for the wheels.
send_action
< source >( action: dict ) → RobotAction
Returns
RobotAction
the action sent to the motors, potentially clipped.
Raises
RobotDeviceNotConnectedError
RobotDeviceNotConnectedError— if robot is not connected.
Command lekiwi to move to a target joint configuration.
The relative action magnitude may be clipped depending on the configuration parameter max_relative_target. In this case, the action sent differs from original action.
Thus, this function always returns the action actually sent.
class lerobot.robots.lekiwi.LeKiwiConfig
< source >( port: str = '/dev/ttyACM0'disable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>use_degrees: bool = Truenum_read_retries: int = 2id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Establishes ZMQ sockets with the remote mobile robot
Cleans ZMQ comms
Capture observations from the remote robot: current follower arm positions, present wheel speeds (converted to body-frame velocities: x, y, theta), and a camera frame. Receives over ZMQ, translate to body-frame vel
send_action
< source >( action: dict ) → np.ndarray
Command lekiwi to move to a target joint configuration. Translates to motor space + sends over ZMQ
class lerobot.robots.lekiwi.LeKiwiClientConfig
< source >( remote_ip: strport_zmq_cmd: int = 5555port_zmq_observations: int = 5556teleop_keys: dict = <factory>cameras: dict = <factory>polling_timeout_ms: int = 15connect_timeout_s: int = 5id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
OpenArmFollower
OpenArms Follower Robot which uses CAN bus communication to control 7 DOF arm with a gripper. The arm uses Damiao motors in MIT control mode.
Run calibration procedure for OpenArms robot.
The calibration procedure:
- Disable torque
- Ask user to position arms in hanging position with grippers closed
- Set this as zero position
- Record range of motion for each joint
- Save calibration
Configure motors with appropriate settings.
Connect to the robot and optionally calibrate.
We assume that at connection time, the arms are in a safe rest position, and torque can be safely disabled to run calibration if needed.
Disconnect from robot.
Get current observation from robot including position, velocity, and torque.
Reads all motor states (pos/vel/torque) in one CAN refresh cycle instead of 3 separate reads.
send_action
< source >( action: dictcustom_kp: dict[str, float] | None = Nonecustom_kd: dict[str, float] | None = None )
Send action command to robot.
The action magnitude may be clipped based on safety limits.
class lerobot.robots.openarm_follower.OpenArmFollowerConfig
< source >( port: strside: str | None = Nonecan_interface: str = 'socketcan'use_can_fd: bool = Truecan_bitrate: int = 1000000can_data_bitrate: int = 5000000disable_torque_on_disconnect: bool = Trueuse_velocity_and_torque: bool = Falsemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>motor_config: dict = <factory>position_kp: list = <factory>position_kd: list = <factory>joint_limits: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
BiOpenArmFollower
class lerobot.robots.bi_openarm_follower.BiOpenArmFollower
< source >( config: BiOpenArmFollowerConfig )
Bimanual OpenArm Follower Arms
class lerobot.robots.bi_openarm_follower.BiOpenArmFollowerConfig
< source >( id: str | None = 'bi_openarm_follower'calibration_dir: pathlib.Path | None = Noneleft_arm_config: OpenArmFollowerConfigBaseright_arm_config: OpenArmFollowerConfigBasecameras: dict = <factory> )
Configuration class for Bi OpenArm Follower robots.
OmxFollower
For OMX robots that come pre-calibrated:
- If default calibration from package doesn’t match motors, read from motors and save
- This allows using pre-calibrated robots without manual calibration
- If no calibration file exists, use factory default values (homing_offset=0, range_min=0, range_max=4095)
send_action
< source >( action: dict ) → RobotAction
Command arm to move to a target joint configuration.
The relative action magnitude may be clipped depending on the configuration parameter max_relative_target. In this case, the action sent differs from original action.
Thus, this function always returns the action actually sent.
class lerobot.robots.omx_follower.OmxFollowerConfig
< source >( port: strdisable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>use_degrees: bool = Falseid: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Reachy2Robot
Reachy 2, by Pollen Robotics.
class lerobot.robots.reachy2.Reachy2RobotConfig
< source >( max_relative_target: float | None = Noneip_address: str | None = 'localhost'port: int = 50065disable_torque_on_disconnect: bool = Falseuse_external_commands: bool = Falsewith_mobile_base: bool = Truewith_l_arm: bool = Truewith_r_arm: bool = Truewith_neck: bool = Truewith_antennas: bool = Truewith_left_teleop_camera: bool = Falsewith_right_teleop_camera: bool = Falsewith_torso_camera: bool = Falsecamera_width: int = 640camera_height: int = 480cameras: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
UnitreeG1
class lerobot.robots.unitree_g1.UnitreeG1Config
< source >( kp: list = <factory>kd: list = <factory>default_positions: list = <factory>control_dt: float = 0.004is_simulation: bool = Truerobot_ip: str = '192.168.123.164'cameras: dict = <factory>gravity_compensation: bool = Falsecontroller: str | None = Noneid: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Hope Jr
The Hope Jr humanoid is exposed as two independent robots, an arm and a hand.
We assume that at connection time, arm is in a rest position, and torque can be safely disabled to run calibration.
class lerobot.robots.hope_jr.HopeJrArmConfig
< source >( port: strdisable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
class lerobot.robots.hope_jr.HopeJrHandConfig
< source >( port: strside: strdisable_torque_on_disconnect: bool = Truecameras: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
RebotB601Follower
class lerobot.robots.rebot_b601_follower.RebotB601Follower
< source >( config: RebotB601FollowerRobotConfig )
Seeed Studio reBot B601-DM follower arm (6-DOF + gripper, Damiao CAN motors).
Motor communication is handled by the motorbridge package over a CAN bus,
reached either through a Damiao serial bridge or a SocketCAN adapter.
Disable motor torque so the arm can be moved by hand (read-only debugging).
Command the arm to a target joint configuration.
Positions are expressed in degrees. The relative action magnitude may be
clipped depending on max_relative_target, so the action actually sent is
always returned.
class lerobot.robots.rebot_b601_follower.RebotB601FollowerRobotConfig
< source >( port: strcan_adapter: str = 'damiao'dm_serial_baud: int = 921600disable_torque_on_disconnect: bool = Truemax_relative_target: float | dict[str, float] | None = Nonecameras: dict = <factory>motor_can_ids: dict = <factory>pos_vel_velocity: float | list[float] = <factory>control_mode: str = 'mit'mit_kp: float | list[float] = <factory>mit_kd: float | list[float] = <factory>gripper_control_mode: str = 'force_pos'gripper_torque_ratio: float = 0.07gripper_mit_kp: float = 8.0gripper_mit_kd: float = 0.3joint_limits: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Registered configuration for the reBot B601-DM follower robot.
BiRebotB601Follower
class lerobot.robots.bi_rebot_b601_follower.BiRebotB601Follower
< source >( config: BiRebotB601FollowerConfig )
Bimanual Seeed Studio reBot B601-DM follower.
Composes two single-arm RebotB601Follower instances. Observation and
action keys of each arm are namespaced with a left_ / right_ prefix.
class lerobot.robots.bi_rebot_b601_follower.BiRebotB601FollowerConfig
< source >( left_arm_config: RebotB601FollowerConfigright_arm_config: RebotB601FollowerConfigcameras: dict = <factory>id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Configuration class for the bimanual reBot B601-DM follower robot.
EarthRoverMiniPlus
class lerobot.robots.earthrover_mini_plus.EarthRoverMiniPlus
< source >( config: EarthRoverMiniPlusConfig )
EarthRover Mini Plus robot controlled via Frodobots SDK HTTP API.
This robot uses cloud-based control through the Frodobots SDK instead of direct hardware connection. Cameras stream via WebRTC through Agora cloud, and control commands are sent via HTTP POST requests.
The robot supports:
- Dual cameras (front and rear) accessed via SDK HTTP endpoints
- Linear and angular velocity control
- Battery and orientation telemetry
Calibration not needed for SDK-based robot.
Configure robot (no-op for SDK-based robot).
connect
< source >( calibrate: bool = True )
Connect to robot via Frodobots SDK.
disconnect
< source >( )
Raises
DeviceNotConnectedError
DeviceNotConnectedError— If robot is not connected
Disconnect from robot.
Stops the robot and closes connection to SDK.
get_observation
< source >( ) → RobotObservation
Returns
RobotObservation
Observation containing:
- front: Front camera image (480, 640, 3) in RGB format
- rear: Rear camera image (480, 640, 3) in RGB format
- speed: float - Current speed (raw SDK value)
- battery_level: float - Battery level (0-100)
- orientation: float - Robot orientation in degrees
- gps_latitude: float - GPS latitude coordinate
- gps_longitude: float - GPS longitude coordinate
- gps_signal: float - GPS signal strength (percentage)
- signal_level: float - Network signal level (0-5)
- vibration: float - Vibration sensor reading
- lamp: float - Lamp state (0=off, 1=on)
- accelerometer_x/y/z: float - Accelerometer axes (raw SDK value)
- gyroscope_x/y/z: float - Gyroscope axes (raw SDK value)
- magnetometer_filtered_x/y/z: float - Magnetometer axes (raw SDK value)
- wheel_rpm_0/1/2/3: float - Wheel RPMs
Raises
DeviceNotConnectedError
DeviceNotConnectedError— If robot is not connected
Get current robot observation from SDK.
Camera frames are retrieved from SDK endpoints /v2/front and /v2/rear. Frames are decoded from base64 and converted from BGR to RGB format. Robot telemetry is retrieved from /data endpoint. Sensor arrays (accels, gyros, mags, rpms) each contain entries of [values…, timestamp]; the latest reading from each array is used.
Note: Camera frames are retrieved from SDK endpoints /v2/front and /v2/rear. Frames are decoded from base64 and converted from BGR to RGB format. Robot telemetry is retrieved from /data endpoint. All SDK values are normalized to appropriate ranges for dataset recording.
send_action
< source >( action: dict ) → RobotAction
Parameters
- action — Action dict with keys:
- linear_velocity: Target linear velocity (-1 to 1)
- angular_velocity: Target angular velocity (-1 to 1)
Returns
RobotAction
The action that was sent (matches action_features keys)
Raises
DeviceNotConnectedError
DeviceNotConnectedError— If robot is not connected
Send action to robot via SDK.
Note: Actions are sent to SDK via POST /control endpoint. SDK expects commands in range [-1, 1].
class lerobot.robots.earthrover_mini_plus.EarthRoverMiniPlusConfig
< source >( sdk_url: str = 'http://localhost:8000'id: str | None = Nonecalibration_dir: pathlib.Path | None = None )
Configuration for EarthRover Mini Plus robot using Frodobots SDK.
This robot uses cloud-based control via the Frodobots SDK HTTP API. Camera frames are accessed directly through SDK HTTP endpoints.