exports.create, no archive download) and writes a LeRobot dataset on disk, optionally pushing it to the Hub.
One Avala sequence becomes one LeRobot episode. Each camera maps to an observation.images.<cam> feature; timestamp/frame_index/episode_index are derived from --fps.
Prerequisites
Install either writer:avala.converters.lerobot_v3) needs only pyarrow, numpy, pillow and, for video features, PyAV. It writes the same LeRobot v3 layout as the lerobot library (meta/info.json, meta/stats.json, meta/tasks.parquet, meta/episodes/…, data/chunk-…/file-….parquet, videos/<camera>/chunk-…/file-….mp4); its output loads in LeRobotDataset. By default (--backend auto) the exporter uses the lerobot library when it is installed and the torch-free writer otherwise. --push needs the lerobot library.
Convert from the CLI
my-org/my-dataset, writes a LeRobot v3 dataset to ./lerobot-out, and finalizes it (so the parquet footers are written and the dataset is readable).
Convert from Python
StreamingLeRobotDataset (train directly from the Hub with no full download) once pushed. When you --push, the dataset card is tagged LeRobot + robotics (by lerobot) and avala, so it shows up in the LeRobot dataset viewer and filters.
Perception vs. policy datasets (read this)
Avala sequence datasets are annotation-centric: they reliably provide camera frames and calibration, but not robot proprioception. By default this converter therefore produces a perception / vision-language dataset (cameras + timestamps + a task string) and prints a warning saying so. That is a valid LeRobot dataset, but it is not a policy-training dataset — it has noaction/observation.state.
To produce robot observation.state / action, the source frames must actually carry that data, and you point the converter at it:
Who was driving: control_source
When the raw frames record who was in control — policy, teleop, intervention or hold — point --control-source-key at that field. It is written verbatim as a per-frame string column, annotation.avala.control_source by default:
Round-tripping LeRobot data through Avala
A LeRobot v3 dataset imported withavala import lerobot keeps every per-frame column in its MCAP episodes (see the CLI reference), including a control_source column on the /lerobot/control_source topic. To write such MCAP episodes back to LeRobot v3 without torch:
fps and robot_type are restored from the metadata the importer stores in each MCAP. Numeric and text columns, timestamps and episode boundaries come back exactly; camera frames are re-encoded, so pixels are close but not identical. Other MCAP files are converted too, including robot recordings:
- Cameras:
foxglove.CompressedVideoandfoxglove.CompressedImagetopics become video features (/camera/high/video→observation.images.high). H.264 is copied into the LeRobot mp4 without re-encoding when each LeRobot frame maps to one packet, the episode starts on a keyframe and there are no B-frames; otherwise that camera is decoded and re-encoded, with a warning that says why. - Joints:
sensor_msgs/JointStateon/joint_statesbecomesobservation.state(positions, with joint names), plusobservation.velocity/observation.effortwhen populated. A command topic (/joint_commands, or any joint topic whose name containscommand,cmd,action,targetorgoal) becomesaction. Without one there is noaction: it is never derived from the state. - Task: a
foxglove.Lognamedtaskbecomes the LeRobottaskof every frame. - Timing: frames follow the first camera’s recorded times; other topics contribute their latest value at or before each frame, and frames before every topic has published are dropped. LeRobot timestamps are
frame_index / fps, so the largest deviation from the recorded times is reported (a warning past half a frame) and written, with each camera’s pass-through/re-encode mode, tometa/avala_export_report.json.
Next Steps
- Avala + PyTorch — stream Avala data into PyTorch with no export step
- Python SDK reference
- LeRobot — the robot-learning library and dataset format