Skip to main content
MuJoCo is great when you want a fast, scriptable, headless-friendly simulator: robotics research, contact-rich tasks, RL training, pure dynamics work. Drift treats MuJoCo as a first-class target — you describe what you want, Drift writes the MJCF, runs the sim, and reads the result back.
Make sure MuJoCo is installed (pip install mujoco) and you’ve completed the Quickstart basics.

The prompt

This guide uses a from-scratch mobile robot to walk through MJCF concepts step by step. If you want to use a famous open robot model instead, see the Robot Showcase — every showcase guide composes the scene around a MuJoCo Menagerie model (Unitree Go2, Trossen Aloha, Unitree H1, …) rather than authoring the robot itself. From this single prompt, Drift:
  • Authors an MJCF scene with a chassis, 4 wheels (correct cylinder axis vs hinge axis), an IMU site, sensors, actuators, and the floor + obstacles
  • Picks chassis-z so the wheel bottoms rest exactly at z=0 (no spawn-bounce)
  • Picks damping / armature / friction values that won’t oscillate when commands drop to zero
  • Validates the MJCF (loads the model, asserts nbody/njnt/nu/nsensor, checks for NaN in qacc)
  • Writes a run_sim.py headless loop with the requested controls and CSV logging
  • Runs the sim, prints the final chassis pose and contact count
  • (Optional) opens the MuJoCo passive viewer afterwards

What you get on disk

After the prompt completes, your workspace looks like:
Open robot_scene.xml and you’ll find the MJCF clean and well-named:
Everything is named — no joint1, body3, geom_2. Real names you can grep.

Iterating on the scene

Each follow-up triggers only what’s needed:
Drift edits the MJCF, re-validates, and re-runs the sim — no manual XML editing, no terminal switching.

Opening the viewer

For interactive inspection:
Drift launches a background MuJoCo passive viewer. Use /ps to see it running. Press q in the viewer window (or /exit in Drift) when you’re done — Drift cleans up the process.

Debugging common MuJoCo failures

Describe the symptom, Drift figures it out:
→ Drift checks the chassis-z spawn vs wheel radius and updates the position.
→ Drift walks: missing inertial blocks, too-coarse timestep, free joint without damping, near-zero mass.
→ Drift checks: cylinder axis vs hinge axis (mismatch = no traction), friction values, contact dimensions (condim=1 is frictionless; need condim=3 or 6), chassis-wheel embedding.
→ Drift tunes wheel damping/armature until the stop is clean.

Cost-tracking note

Long multi-step builds (write MJCF → validate → fix → run → tune → repeat) are exactly what Drift’s caching and planning are optimized for. The agent keeps context across steps, so you’re paying input cost on incremental changes — not the full prompt re-paid on every call.

Mixing MuJoCo and ROS2

You can use MuJoCo without ROS2 in the loop — most users do. But if you want a ROS2 bridge for cmd_vel / odometry / sensor topics, Drift can scaffold that:
This produces a Python ROS2 node that loads the MJCF, exposes a tick callback, and bridges the sensors and actuators to standard topic types. You can then ros2 launch it like any other node.

Next steps

Your First Simulation (Gazebo)

The Gazebo / ROS2-first path for comparison

Manipulator in RViz

A single-prompt build of a 3-joint manipulator

Project Context

Capture MuJoCo conventions for your team in DRIFT.md

Custom Skills

Write your team’s MJCF practices as a skill