MABEL exists twice. One copy is aluminium and 59 motors; the other is a 2 ms MuJoCo timestep, and both answer to the same controller through the same wire contract. Every trajectory, every policy and every bug is cheaper to find on the second one — so that is where the work starts.
There is one file. simulation/mabel_mujoco/models/mabel_full.xml
is the canonical MABEL — 67 generalized coordinates, 59 actuators, 9 cameras,
370 sensors — and the ROS URDF, the web GLB you have been orbiting, the headset rigs
and the controller’s tip-over constants are all generated from it. Nothing on
this site was modelled twice.
Geometry, inertia, joint limits — one file, one place.
MJCF → URDF → GLB → app rigs → mirror, in order. Each step eats the last step’s output.
A hand-edited URDF survives until the next regeneration, then silently does not.
On the robot, hardware_bridge is the only thing that opens a
device. In simulation, simulation_bridge is the only thing that calls
mj_step. Same rule, same seam — which is why the teleop server, ROS,
the cameras and every viewer are clients either way, and why the launch flag
use_sim:=true is the whole difference.
| What | Real robot | Simulation |
|---|---|---|
| Owns the hardware | hardware_bridge | simulation_bridge |
| Steps at | the motors’ own loops | 2 ms — 500 Hz |
| Publishes joint state | 50 Hz | 50 Hz |
| Command contract | RobotCommand | RobotCommand |
| Clients are told | kind = "real" | kind = "sim" |
| Base velocity caps | 1.0 m/s · 2.0 rad/s | 1.0 m/s · 2.0 rad/s |
A robot that only works in an empty room works in an empty room. The scene
library is 35 released worlds that <include> the canonical model —
homes, kitchens, cafes, warehouses, streets — each a registry entry in
scenes.json with its own XML, thumbnail and category. The gallery below is
the 34 of them that ship a render — each tile orbiting live, with its physics
running. Sixteen have scripted actors moving in them.
Three simulators live in the tree, and they are not competing. MuJoCo owns time and contact; the other two change what the cameras see, or what steps the world, without changing a single byte of the contract the apps and ROS speak.
Headless, 500 Hz, elliptic friction cone with 3 noslip iterations. This is the plant every number on this site was measured against.
simulation/mabel_mujoco/
MuJoCo still steps the world; Unity (URP, Metal) renders it and simulates the cameras and lidar. The prime directive is that ROS, the teleop apps and a policy cannot tell — same topics, rates, intrinsics and TF.
simulation/mabel_unity_sim/
Swaps MuJoCo out for the Genesis engine while keeping every client-facing wire contract byte-compatible, so the iOS, web and Vision Pro clients connect unchanged.
simulation/mabel_gensis_world/
Teleoperate the twin and the collector writes exactly the file it writes on hardware: one HDF5 per episode, axis 0 = frame at 15 Hz. Because the format is identical, a dataset can mix simulated and real episodes, and the trainer never learns which is which.
In every episode_XXXX.h5 | What it holds |
|---|---|
| cameras | JPEG blobs, one group per camera |
| planar lidar | the same scan the RPLIDAR produces |
| per-actuator | joint_pos / vel / torque, all 59 |
| generalized state | qpos / qvel, plus body poses and base twist |
action/ctrl | the training label — a 59-vector of absolute joint targets, not deltas |
schema_json | actuator names and order, camera list, units — so nothing downstream hard-codes them |
Drive the twin from a headset, a phone or the browser studio. Every frame is logged.
The curation studio scores quality and drift, then exports a LeRobot v2.1 dataset — the contract between curation and training.
ACT, Diffusion Policy, Pi0 and Pi0.5, scoped to a camera subset and a joint group.