Skip to content

LeRobot Dataset Export

The LeRobot lane is a dataset-profile bridge, not a second runtime. It maps the canonical event rows from data and event streams into LeRobot-style records and back, so you can verify the conversion locally before any real dataset upload.

event_table_rows flattens an EventBuffer into canonical rows; to_lerobot_records assigns a per-(episode_id, stream_id) frame_index in deterministic event-time order and tucks Retriever metadata under metadata; validate_lerobot_mapping checks the frame indices are contiguous; from_lerobot_records reverses it.

from retriever_typing.data import (
    Event, EventBuffer, StreamId,
    event_table_rows, to_lerobot_records, from_lerobot_records, validate_lerobot_mapping,
)

buffer = EventBuffer((
    Event(stream_id=StreamId("joint"), event_time_ns=1_000, ingest_time_ns=1_010, seq=0, value={"q1": 0.1}, type_name="dict"),
    Event(stream_id=StreamId("joint"), event_time_ns=2_000, ingest_time_ns=2_010, seq=1, value={"q1": 0.2}, type_name="dict"),
    Event(stream_id=StreamId("joint"), event_time_ns=3_000, ingest_time_ns=3_010, seq=2, value={"q1": 0.3}, type_name="dict"),
))

rows = event_table_rows(buffer, episode_id="episode-001")
records = to_lerobot_records(rows)
validate_lerobot_mapping(records)              # raises on non-contiguous frame_index
roundtrip_rows = from_lerobot_records(records) # rows -> records -> rows
pixi run demo-robotics-lerobot-bridge

Real output — three source rows in, three records out, three rows back, and one inspectable record:

Canonical rows: 3
LeRobot records: 3
Roundtrip rows: 3
Sample record:
  {'episode_id': 'episode-001', 'stream_id': 'joint', 'frame_index': 0, 'timestamp_ns': 1000, 'type_name': 'dict', 'payload': {'q1': 0.1}, 'metadata': {'ingest_time_ns': 1010, 'seq': 0, 'frame_id': None, 'units': None, 'lineage': []}}

The LeRobot-facing fields sit at the top level; everything Retriever needs to reconstruct the original event is preserved under metadata:

Field Meaning
frame_index Dense 0-based index per (episode_id, stream_id), ordered by event time.
timestamp_ns The original event_time_ns.
payload The event value, unchanged.
metadata.ingest_time_ns, metadata.seq Enough to restore total ordering on the way back.
metadata.frame_id, metadata.units, metadata.lineage Provenance carried through the conversion.

Because ingest time, seq, and lineage survive, the round-trip is lossless for ordering and provenance — the reason Roundtrip rows equals Canonical rows.

Keep here Keep out of first-run docs
Small local conversion, verifiable offline. Heavy dataset generation.
Event-time, source, and lineage preservation. Cloud upload, private storage, credentials.
The public row/record profile contract. Robot-lab-specific capture procedures.

This bridge exists to make the export shape obvious before a large dataset pipeline grows around it.

Source: src/retriever_typing/data/lerobot_bridge.py, src/retriever_typing/data/dataset_manifest.py; demo examples/advanced/robotics_typing_standard/lerobot_bridge_demo.py.