Skip to content

LeRobot Feature Schema

SUMMARY

Define stable feature keys and compatible data types, shapes, and dimension names for every frame in a LeRobot dataset.

What Is a Feature Schema?

A feature schema defines the structure of the data recorded in each frame of a LeRobot dataset.

python
features = {
    "<feature_a>": {
        "dtype": "<data_type>",
        "shape": [...],
        "names": [...],
    },
    "<feature_b>": {
        "dtype": "<data_type>",
        "shape": [...],
        "names": [...],
    },
}

Each feature is identified by a feature key, such as <feature_a>, <feature_b> and so on.

Feature Definition

Each feature has the following structure:

python
"<feature_key>": {
    "dtype": "<data_type>",
    "shape": [...],
    "names": [...],
}

dtype

Defines how the feature is represented and stored.

Supported dtypes

dtypeMeaning
"video"Visual frames that LeRobot stores and encodes as video.
"image"Visual frames stored as individual images.
"float32"Numeric tensor or array values stored as 32-bit floats.
"bool"Boolean values.
"string"Text or string values.

shape

Defines the expected shape of the value recorded for that feature.

python
"shape": [7]

This represents a seven-element vector.

python
"shape": [3, 480, 640]

This represents a three-channel image with a height of 480 and width of 640.

names

Describes the dimensions or individual elements of the feature.

For a vector:

python
"shape": [3],
"names": ["x", "y", "z"],

For an image:

python
"shape": [3, 480, 640],
"names": ["channel", "height", "width"],

The names must match the meaning and ordering of the corresponding dimensions or elements.

Example Feature Schema

The following example describes a robot with two cameras, robot state, force/torque sensing, and a seven-dimensional action.

CUSTOMIZE THE SCHEMA

The feature schema is application-specific.

You can add or remove observations, change camera names and resolutions, change robot-state dimensions, add sensors, and define the action representation required by your robot.

Every feature must still provide a compatible dtype, shape, and names definition.

python
features = {
    "observation.images.front": {
        "dtype": "video",
        "shape": [3, 480, 640],
        "names": ["channel", "height", "width"],
    },
    "observation.images.wrist": {
        "dtype": "video",
        "shape": [3, 480, 640],
        "names": ["channel", "height", "width"],
    },
    "observation.state": {
        "dtype": "float32",
        "shape": [7],
        "names": [
            "shoulder_pan",
            "shoulder_lift",
            "elbow",
            "wrist_1",
            "wrist_2",
            "wrist_3",
            "gripper",
        ],
    },
    "observation.force": {
        "dtype": "float32",
        "shape": [6],
        "names": [
            "force_x",
            "force_y",
            "force_z",
            "torque_x",
            "torque_y",
            "torque_z",
        ],
    },
    "action": {
        "dtype": "float32",
        "shape": [7],
        "names": [
            "shoulder_pan",
            "shoulder_lift",
            "elbow",
            "wrist_1",
            "wrist_2",
            "wrist_3",
            "gripper",
        ],
    },
}

Feature Naming Best Practices

  • Use stable, descriptive, dot-separated feature names.
  • Keep sensor and state inputs under the observation. namespace.
  • Use the canonical top-level action key for robot commands.
  • Avoid encoding episode numbers, timestamps, or changing runtime values in feature names.
  • Use the schema's names list to label dimensions within a vector feature; it does not replace the feature key.
  • LeRobot standardizes common policy-facing keys such as observation.image, observation.images.<camera_name>, observation.state, and action, but does not define a universal grammar for every custom feature.
DataRecommended feature nameExamples
Single cameraobservation.imageobservation.image
Multiple camerasobservation.images.<camera_name>observation.images.front, observation.images.wrist
Primary robot stateobservation.stateJoint positions and gripper state packed into one vector
Additional observationobservation.<name>observation.force, observation.end_effector_pose
ActionactionJoint targets, Cartesian commands, or gripper commands
Task descriptiontask"Pick up the blue cube"

Next Steps