play_real process subscribes to that pose, runs ONNX inference, and closes the loop by sending commands to the hand driver.
This page assumes the rig is already built and calibrated. If not, start with Hardware Setup.
You don’t need to train to deploy. Download the pretrained
policy.onnx and policy_config.json from Releases and pass the policy.onnx path as --ckpt. The released policy is what produces the demo.Pipeline
RealHandEnv subclasses mjlab’s ManagerBasedRlEnv, so the same observation and action managers as training apply verbatim — no duplicated pipelines. Inside the env’s step(), actions go to the hand driver, and observations come from a mix of joint state (via the driver) and cube pose (via ZMQ from the observer).
The ONNX policy loads through a loader that reads the sidecar JSON for control-mode parameters (action_scale, ema_alpha, warmup_time_s, control_mode, history_len, ctrl_dt) captured at export time. This keeps deploy inference identical to the sim policy that produced the ONNX.
Run the Closed Loop
After the hardware setup is complete, run each command in its own terminal, in order.home is a one-shot reset. vision and play-real both stay running, so they can’t share a terminal.
Pose-Estimation Tuning
Once the hardware is fixed,observer.yaml gives four knobs to trade noise against lag.
Two presets ship in
observer.yaml:
- Agile (fast response, more noise):
process_noise: 0.5,measurement_noise: 0.1,alpha: 0.8 - Smooth (stable, slower response):
process_noise: 0.01,measurement_noise: 2.0,alpha: 0.2
- Cube jitter when held still — switch to the smooth preset.
- Pose lag during fast reorientation — switch to the agile preset.
- Cube drops to lost repeatedly — raise
pnp.reproj_thresholdto ~8.0 px and re-check the camera intrinsics calibration. If axes look swapped, fixface_rotationsincube_tags.jsonor re-stick the offending tag.
End-to-End Smoke Test
Walk these five checkpoints in order. If any fails, jump back to the indicated setup section before continuing.Step 1 — Home the Hand
Step 2 — Start the Cube Observer
Step 3 — Verify the ZMQ Pose Stream
In another terminal (keepvision running), confirm cube poses publish on port 5555:
Step 4 — Visual Cube-Pose Check
Withvision still running:
- Axis mismatches — rotate the physical cube around one face axis and confirm the rendered cube rotates around the same axis. A mirrored or 90°-off rotation means the
face_rotationsincube_tags.jsonare wrong, or a tag was placed in the wrong orientation. - Position offset — center the cube on the palm. The rendered cube should sit on the palm geom. A > 2 cm offset usually means the hand mounting or camera intrinsics are off.
Step 5 — Run the Closed-Loop Policy
Troubleshooting
For a deeper look at the task design behind the policy, see Architecture.