Add a New Robot Embodiment#
HandUMI recordings are robot agnostic. An embodiment adapts those recordings to a robot for simulation, replay, or real teleoperation.
This guide covers fixed-base bimanual robots with one TCP and one parallel gripper per side. Start by choosing the scope of the contribution:
Scope |
Required |
|---|---|
Simulation / replay |
URDF, assets, robot YAML, tests, and replay evidence. |
Absolute-table replay |
Above, plus a |
Real hardware |
Above, plus a backend, physical calibrations, and hardware safety tests. |
Do not add vendor SDKs, local ports, credentials, or robot-specific recording requirements to the HandUMI recorder.
1. Prepare source assets#
Create this layout:
assets/<robot>/
├── README.md # vendor URL, commit/release, license, derivations
├── LICENSE.<vendor> # when redistribution requires it
├── <robot>.urdf
├── <robot>.xml # optional MuJoCo contact model
└── meshes/
configs/robots/
└── <robot>.yaml
Use official assets when possible. In assets/<robot>/README.md, record the
source repository, immutable commit or release, license, and every generated
mesh. Do not commit unlicensed assets, local calibration files, datasets, or
configs/rig.yaml.
If the vendor supplies two single-arm URDFs, build one combined bimanual URDF:
namespace every copied link and joint as
left_orright_;preserve the vendor joint origins, axes, limits, and mesh transforms;
add fixed mounts from one shared base to each arm;
add one fixed TCP link per side at the actual grasp point;
keep gripper joints actuated and give all visual mesh paths a resolvable
package://orpkg_rootpath.
The robot name and joint names are declared in YAML, so no central registry is
needed for simulation. Add assets/<robot> to the wheel force-include section
of pyproject.toml when the assets must ship with the package.
2. Add the robot YAML#
Create configs/robots/<robot>.yaml:
kind: myrobot
urdf: assets/myrobot/myrobot.urdf
pkg_root: assets/myrobot
# mjcf: assets/myrobot/myrobot.xml # only if a MuJoCo model exists
arms:
left:
ee_link: left_tcp
joint_names: [left_joint1, left_joint2]
gripper_joints:
- {name: left_finger_joint, closed: 0.0, open: 0.035}
right:
ee_link: right_tcp
joint_names: [right_joint1, right_joint2]
gripper_joints:
- {name: right_finger_joint, closed: 0.0, open: 0.035}
# One value for every actuated URDF joint, including fingers.
home_q: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
gripper_max_width_m: 0.07
ik_weights:
pos: 100.0
ori: 15.0
rest: 2.0
max_joint_delta: 0.06981317
max_reach: 0.45
replay:
max_joint_delta: 0.20
# Use physical-width when source and target grippers have different strokes.
# gripper_retarget: physical-width
closed and open are the actual URDF joint values for normalized HandUMI
opening 0 and 1. Verify them visually; URDF joint signs are not universal.
Use gripper_retarget: physical-width to preserve aperture in meters when the
target gripper has a different maximum width. The default, normalized,
preserves the source opening percentage.
Useful references are configs/robots/piper.yaml, openarmv1.yaml,
trlc_dk1.yaml, and yam.yaml.
3. Add a simulation test#
Add a focused test in tests/robots/test_registry.py that checks:
left/right arm joint order and indices;
home pose length and a symmetric FK sanity check;
gripper closed/open mapping, if present;
load_urdf(load_meshes=True)resolves every visual mesh.
Run it before attempting replay:
JAX_PLATFORMS=cpu uv run pytest -q tests/robots/test_registry.py
JAX_PLATFORMS=cpu uv run python -c \
"from handumi.robots.registry import load_embodiment; print(load_embodiment('myrobot').joint_names)"
4. Calibrate only when the scope needs it#
Table placement for absolute replay#
Add configs/calibration/<robot>_table.yaml. This is the transform from the
demonstration table frame to the target robot world; it is not a TCP offset.
schema_version: 1
kind: handumi_robot_table_calibration
robot: myrobot
source: measured_installation
verified: false
calibration:
frame_convention: pose7=[x,y,z,qx,qy,qz,qw], meters, xyzw quaternion
robot_from_table:
position: [0.0, 0.0, 0.0]
quaternion: [0.0, 0.0, 0.0, 1.0]
Use verified: false for a simulation placement. Set it to true only after
measuring the physical installation. Never compensate a wrong TCP calibration
by changing this transform.
HandUMI controller-to-TCP calibration#
This calibration belongs to the physical HandUMI assembly:
tracking controller + HandUMI mount + HandUMI gripper/tool + side
It does not automatically change because the target robot changes. A
simulation-only PR needs no new pivot capture. Reuse an identity-bound dataset
snapshot only when the physical HandUMI assembly is exactly the same; otherwise
follow HandUMI Setup and Calibration and reference the new file
from controller_tcp_calibrations and handumi_tool in the robot YAML.
5. Replay a validation episode#
For absolute-table replay, use a recorded validation episode and inspect the model in Viser:
JAX_PLATFORMS=cpu uv run handumi-replay-in-sim \
--repo-id local/myrobot_validation \
--dataset-root outputs/myrobot_validation \
--episode 0 --robot myrobot --retarget-mode absolute-table --strict-ik
Check mesh loading, home pose, TCP placement, gripper direction and aperture, table height, shared workspace, and reported IK errors. A large error usually means a bad TCP, placement, home pose, joint order, or IK limit.
6. Add real hardware support only when ready#
Replay support does not provide robot control. A hardware PR must implement
the RobotBackend contract in src/handumi/real/backends/__init__.py:
prepare, connect, home, command, hold, health check, and close. Register it
lazily in make_real_backend, declare it in the robot YAML as
real.backend, keep vendor units and SDK code inside that backend, and add
backend tests. configs/rig.yaml should only hold local transport details
such as CAN ports. Real control uses radians, meters, normalized openings, and
XYZW pose quaternions.
7. Open the pull request#
Before opening the PR, run:
JAX_PLATFORMS=cpu uv run pytest -q
uv build
.venv-docs/bin/sphinx-build -W -b html docs/source /tmp/handumi-docs
git status --short
The PR description should state:
robot model, vendor source, immutable revision, and license;
scope: simulation, absolute replay, and/or real hardware;
frame convention, TCP and gripper mapping decisions;
replay command, frame count, and position/rotation error summary;
a simulator screenshot or short recording;
physical calibration evidence only when claiming hardware support.
Completion checklist#
Assets and their provenance/license are committed.
Combined URDF and all meshes load.
TCPs, joint order, limits, home pose, and gripper mapping are tested.
Robot assets are included in the wheel.
Table calibration is present for absolute-table replay.
verified: trueis used only for a measured physical installation.Replay passes with acceptable IK and gripper aperture.
Real backend and safety tests exist if real teleoperation is claimed.
README/docs are updated and the full test, build, and docs checks pass.