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.
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.
--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.
robot_typemust beaxol_mantis; robot-recorded datasets never went through the tracker transform.meta/axol.jsonmust exist and be in the v0.1.32+ pose frame (run--from-versionfirst otherwise).meta/axol.jsonmust not already carry amantis_tcp_transformrecord. 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.
~/.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.
