TrueRig

Robot-model conversion you can trust

Move a robot between simulators without silently breaking it.

Every simulator wants a different file — ROS uses URDF, MuJoCo uses MJCF, NVIDIA Isaac uses USD. TrueRig converts between them and tells you exactly what changed, so a robot that worked in one still works in the next.

$ pip install truerig view source →
01 — IN

Point it at a robot file

A URDF or MJCF describing your robot's links, joints, masses and meshes.

02 — CONVERT

One command

truerig convert arm.urdf arm.mjcf — out comes a file the target simulator loads, no hand-fixing.

03 — REPORT

Know what changed

A fidelity report lists everything preserved, everything adjusted, and anything the target format simply can't hold.

A real conversion

What "without breaking it" means, concretely.

Take a Robotiq gripper from ROS (URDF) into MuJoCo (MJCF). Its four fingers are mechanically linked — one motor drives all of them. A naive converter drops those links, and in simulation the fingers flop independently: the gripper no longer grips. Here's TrueRig doing the same conversion:

TrueRig keeps the robot a robot — and shows its work.

In this one gripper it preserved all 5 finger-coupling constraints (so the fingers still move together) and the full inertia of all 9 links (so it swings with the right weight distribution). It also flagged the two decisions it had to make — bolting the base to the world, and filling in default contact friction — instead of hiding them.

Nothing here is silent. If something can't survive the trip, it says so, ranked by how much it matters.

Why it's needed

Existing converters fail silently. That's the bug.

Run the standard urdf2mjcf on a real robot and it corrupts the physics without stopping. Same Unitree G1 and Robotiq gripper, incumbent vs TrueRig:

robot.urdf  →  robot.mjcf
  • urdf2mjcfoff-diagonal inertia dropped on 32 linksone buried warning
  • urdf2mjcffinger coupling 5 → 0 constraintsno warning at all
  • urdf2mjcfpackage:// meshes left unresolvedwon't load
  • truerigfull inertia kept, off-diagonals intactreported
  • truerigcoupling preserved as MJCF equalitiesreported
  • truerigmeshes resolved, transcoded, loads cleanreported

Evidence

Field-tested on real robots.

Run across 12 models — humanoids, quadrupeds, arms, a dexterous hand, a dual-arm — plus the G1/Robotiq/Z1 golden set. All convert and load in MuJoCo.

12/12
robots convert & simulate (G1, H1, Go2, ANYmal, Panda, Baxter, …)
3×10⁻⁹
max inertia error, full URDF → MJCF → URDF round-trip
0.56 rad
wrist drift a dropped inertia term causes in 1 s — the cost of the bug
51 tests
green, CI on Python 3.10–3.12

How it works

A compiler for robot descriptions.

Each format parses into one lossless intermediate representation, then emits to any target. A backend drops only what its format truly can't hold — and logs it. That log is your report.

   URDF ─┐                                    ┌─ URDF
   MJCF ─┼──▶ parse ──▶ canonical IR ──▶ emit ──┼─ MJCF
   USD  ─┘          (frontend)   (lossless)   (backend)  └─ USD  (experimental)
                                │
                    ┌───────────┴───────────┐
              validate(IR)            report(loss_log)
           physics sanity checks     what changed, ranked

URDF ↔ MJCF is fully bidirectional. USD export (for NVIDIA Isaac & Newton) works and is experimental, with inertia diagonalized losslessly.

Get started

Three commands.

$ pip install truerig

# convert, with a fidelity report you can gate CI on
$ truerig convert robot.urdf robot.mjcf --report text --strict

# physics-validate a description (mass, inertia, kinematics)
$ truerig validate robot.urdf

# prove the conversion behaves the same, in simulation
$ truerig simcheck robot.urdf robot.mjcf