Skip to main content
axol migrate-dataset rewrites the Cartesian end-effector poses of a local LeRobot dataset in place. It has two migrations, selected by exactly one flag: Both migrations update every data parquet, recompute per-episode and global statistics, and record what they did in meta/axol.json so they cannot run twice. Before making changes each backs up every file it will replace under meta/migrations/<migration-id>/; if the migration fails those files are restored automatically, and a later run recovers an interrupted migration before retrying. Videos, gripper values, timestamps, and joint-space data are never altered.

URDF frame

--from-version. In v0.1.32, the URDF root gained a +90° yaw so its world frame is FLU (+x forward, +y left, +z up). Older Cartesian datasets store poses in the previous frame. The migration applies that root transform to the position and orientation of both end effectors in action and observation.state.
Only run this on Cartesian data recorded with axol v0.1.31 or earlier. A joint-space dataset does not need migration and is rejected. Legacy datasets do not record their axol version, so recording provenance is the reliable way to decide whether an unmarked dataset needs it. Fresh Cartesian datasets write their pose-frame provenance to meta/axol.json automatically, and a dataset that already carries it is refused. --from-version is required because datasets made before pose-frame metadata was added cannot distinguish pre-v0.1.32 data that needs migration from later data that is already correct. The command rejects v0.1.32 and newer values.

Mantis tracker-gripper rotation

--mantis-tcp-rotation. Mantis collection maps every tracker pose to the gripper through the rig’s tracker→gripper transform before recording it. axol ≤ 0.2.4 shipped that transform’s rotation as Rx(+90°), which was ~90° off the flat-back Vive mount: an operator holding the rig exactly like the robot’s rest gripper recorded orientations pitched 90° away, and Axol could not replay the dataset (the arms barely moved while the IK chased unreachable targets). The constant is now Ry(180°); this migration replaces the retired rotation in every recorded pose. Positions are unchanged by the rotation fix.
Add --swap-sides when the session’s trackers were bound to the opposite rigs — the tracker tracker.identify labelled left was mounted on the rig held in the right hand. The engage fit then faced the robot base backwards, so the dataset’s left_ee.* columns hold the right hand’s rig and every pose is yawed 180°. --swap-sides exchanges the two pose column groups and yaws every pose 180° about the rest-pose gripper midpoint (the pivot the engage fit uses; computed from the default rest pose with the URDF forward kinematics). Gripper columns are left as recorded: they follow the CAN channel, not the tracker.
Tell-tale signs of a swapped session: the hand the operator moved in the video is the other side in the dataset, and both recorded engage orientations are ~180° in yaw from the rest pose after the rotation fix alone. From axol 0.2.5 the engage refuses this configuration outright, so only older datasets need it. Eligibility is checked before anything is written:
  • robot_type must be axol_mantis; robot-recorded datasets never went through the tracker transform.
  • meta/axol.json must exist and be in the v0.1.32+ pose frame (run --from-version first otherwise).
  • meta/axol.json must not already carry a mantis_tcp_transform record. Datasets recorded from 0.2.5 on record the transforms they used; one recorded with the corrected constant, or already migrated, is refused. One recorded with per-unit measured transforms ("id": "measured") is refused too — this migration only knows how to undo the factory Vive constant.
Do not run it on a pre-0.2.5 dataset recorded with a per-unit override in ~/.almond/mantis/tcp_transform.json or with a Quest source: those never used the retired factory rotation. A dataset mixing Mantis and robot episodes is also out of scope (every row is transformed). After migration the marker records mantis_tcp_transform.id as vive-flat-back-ry180-v0.2.5 — the axol 0.2.5–0.2.16 factory constant, whose rotation the migration matches — so the migration refuses to run twice. That constant’s translation has since been corrected (see Vive factory values), so collect-data --mantis refuses to append new episodes to a migrated dataset, just as it does to an unrepaired one: record new episodes to a new repo_id.

Options