A working engineer’s guide to the physics engine behind contact-rich robot simulation
You need to train a robot arm to pick and place objects, but the only hardware budget you have is a laptop. Or you are comparing simulators for a reinforcement learning project, and every option claims to be the fastest and most accurate. MuJoCo — Multi-Joint dynamics with Contact — is the physics engine behind many of the results you have seen in recent robotics papers. It is a free, open-source C library that simulates articulated bodies with a focus on fast, stable contact handling, and it ships with official Python bindings that integrate cleanly with NumPy and Gym-style environments.
The codebase is mature and compact for what it does: roughly 60,000 lines of C, actively maintained by DeepMind, with a well-documented MJCF XML model format and URDF import support. By the end of this article you will know what MuJoCo actually computes each timestep, where its contact solver differs from engines like Bullet, and how to decide whether it fits your task. You will also see the practical boundaries — what it does not do, such as deformable bodies or aerodynamics — so you can avoid the common mistake of forcing a rigid-body tool onto a problem it was never designed for.
What MuJoCo Is (and Isn’t)


MuJoCo (Multi-Joint dynamics with Contact) is a physics engine that simulates articulated bodies—robots, humanoids, manipulators—with fast and stable contact handling. It computes the dynamics of bodies connected by joints, resolving contact forces through a convex optimization solver that guarantees stability even in contact-rich scenes. The engine is written in C and exposes both a C API and official Python bindings, with a built-in OpenGL renderer that can run offscreen for headless training.
MuJoCo is not a robotics framework like ROS, nor a game engine with scripting and scene management. It does one thing—physics simulation—and does it well. You load a model, step the simulation, and read the resulting state. Everything else, from control policies to sensor processing, lives in your code.
Positioned alongside Bullet, PhysX, and ODE, MuJoCo is distinguished by its contact accuracy and simulation speed. This combination has made it the de facto standard in reinforcement learning research, particularly for locomotion and manipulation tasks where contact dynamics dominate.
Two misconceptions are worth correcting. First, MuJoCo is not research-only; industry teams use it for robot design validation and control testing, and it underpins DeepMind’s control suite. Second, the MJCF XML format is not prohibitively complex. It is well-documented, and tools exist to convert models from URDF, so the learning curve is manageable.
Architecture: From XML to Simulation Step


MuJoCo separates the physical description of a system from its runtime state. The Model is an MJCF or URDF file compiled into an immutable C data structure that defines bodies, joints, actuators, and contact properties. The Data structure (mjData) holds all mutable state—positions, velocities, and forces—and is what you read from and write to during a simulation.
| |
The Solver (mj_step) advances physics by computing accelerations and contact forces through a convex optimization formulation. This guarantees a unique, stable solution for contact-rich scenes, which is the engine’s primary design strength. The Renderer (mjvScene) is fully decoupled from physics; it consumes state from mjData and can operate offscreen via EGL or OSMesa for headless training.
The Python bindings (mujoco-py) wrap the C API and expose NumPy-compatible arrays, making integration with Gym and RL frameworks straightforward. The typical data flow is: load a model, create an MjData instance, set actuator inputs in data.ctrl, call mj_step, read sensor values, then optionally render. This loop—compile once, step many times—is the core pattern for all MuJoCo workloads.
Key Features: What Problems They Solve

MuJoCo’s contact solver is its defining strength. It computes contact forces through convex optimization, which guarantees a unique, stable solution at each timestep. This speed and stability let you simulate contact-rich robots—hands grasping objects, feet striking ground—in real time or faster, which is precisely what makes large-scale reinforcement learning training feasible.
Model definition accepts both MuJoCo’s native MJCF format and URDF imports. If your team already maintains robot models for ROS or another simulator, you can load them directly rather than rebuilding geometry, joint limits, and actuator properties from scratch. Complex URDF conversions may need manual tuning, but the path from existing assets to a working simulation is short.
The official Python bindings expose the full C API through NumPy-compatible arrays. You load a model, create an MjData instance, set control inputs, and step the solver—all from a Python REPL or a training script. This is the integration point for Gym-style environments and RL frameworks, removing the need to write C wrappers for every experiment.
Built-in rendering supports offscreen framebuffers, so you can generate pixel observations for vision-based RL or record video of rollouts on a headless server. The renderer is separate from the physics pipeline, meaning rendering cost does not slow down the simulation loop unless you explicitly request frames.
Contacts are modeled with compliance rather than hard constraints, allowing slight penetration governed by spring-damper parameters. This soft-contact formulation improves numerical stability during stacked or multi-point contact and produces more realistic force distributions than impulse-based hard contacts, at the cost of tuning stiffness and damping for your specific system.
Use Cases: Where It Shines and Where It Fails

MuJoCo is a strong fit for contact-rich manipulation and locomotion tasks. Training a robotic arm for pick-and-place with reinforcement learning works well because the solver handles object grasping contacts with speed and stability. Simulating a humanoid walking on uneven terrain is equally safe; the contact solver manages complex foot-ground interactions robustly, and the engine’s speed makes iterative policy training practical.
Some applications require caution. Drone simulation is risky because MuJoCo has no built-in aerodynamics model. You would need to implement custom force models for lift, drag, and rotor effects, which adds complexity and risks introducing instabilities that the engine’s rigid-body solver was not designed to handle.
MuJoCo is a poor choice for deformable objects. Cloth, soft tissue, and fluids have only limited support; the engine is fundamentally built around rigid bodies connected by joints. For these workloads, engines like Bullet or dedicated soft-body simulators are more appropriate.
The key distinction is that MuJoCo is a physics core, not a full simulator. It provides the dynamics and contact solving, but you supply the control logic, sensor models, task logic, and any environment-specific physics. If your project needs aerodynamics, fluid dynamics, or deformable materials as first-class features, plan for significant custom extension or choose a different engine.
Interface and Usage: A Minimal Simulation Loop


MuJoCo exposes two interfaces: a C API for embedding in native applications and an official Python binding built on NumPy. For most robotics and reinforcement learning work, the Python API is the practical choice—it integrates directly with Gym environments and research tooling.
The workflow follows a consistent pattern: load a model, create a data structure, then step the simulation. The model is compiled once from an MJCF or URDF file; the data object holds all mutable state—positions, velocities, forces, and actuator inputs—and is what you read from and write to each step.
| |
MjModel.from_xml_path parses the XML and compiles it into the internal model structure. MjData(model) allocates the runtime state arrays sized to that model. Inside the loop, data.ctrl[:] = 0.0 zeroes all actuator inputs—in a real controller you would set joint torques or target positions here. mj_step then advances the simulation by one timestep, integrating dynamics and solving contact constraints. After the step, data.qpos holds the updated generalized positions; reading it gives you joint angles or the body’s Cartesian position, depending on the model.
The distinction between mj_step and mj_forward matters. mj_step advances time and integrates the state forward. mj_forward computes forward dynamics—accelerations and contact forces—without advancing time. Use mj_forward when you need sensor readings or forces at the current state, for instance after setting new controls but before committing to a step.
Comparison with Alternatives

MuJoCo competes with Bullet, PyBullet, and Gazebo in the robotics simulation space. The table below summarizes how these engines compare across the axes that matter most for simulation work. This reflects general knowledge and may be out of date; treat specific capabilities as approximate and verify against current documentation.
| Axis | MuJoCo | Bullet | PyBullet | Gazebo |
|---|---|---|---|---|
| Contact accuracy | High | Medium | Medium | Medium |
| Speed | Fast | Medium | Medium | Slow |
| Model definition | MJCF, URDF | URDF | URDF | URDF |
| Python API | Official | PyBullet | PyBullet | ROS |
| Soft bodies | Limited | Yes | Yes | Yes |
| ROS integration | Via plugins | Limited | Limited | Native |
| Community | Growing | Large | Large | Large |
MuJoCo leads on contact accuracy and simulation speed. Its convex optimization solver produces stable, physically consistent contact forces, which is why it has become the default choice for contact-rich reinforcement learning. The speed advantage is significant for training loops that require millions of simulation steps.
Where MuJoCo lags is soft-body support and native ROS integration. Bullet and PyBullet handle deformable objects and cloth, which MuJoCo does not model well. Gazebo offers native ROS integration and sensor plugins, making it the standard for full-stack robot development, but at the cost of slower simulation and a heavier setup.
Bullet and PyBullet offer broader feature sets than MuJoCo, including vehicle dynamics and soft bodies, but their general-purpose solvers are typically slower and less stable for contact-rich scenarios. For rigid-body contact simulation, MuJoCo’s specialization is an advantage; for everything else, the alternatives may be a better fit.
Under the Hood: The Convex Contact Solver
MuJoCo models contacts with a soft contact model: a spring-damper system that permits slight interpenetration between bodies. Rather than enforcing hard non-penetration constraints, the solver allows small amounts of overlap and computes restoring forces proportional to penetration depth and approach velocity. This compliance is what makes contact-rich simulations numerically stable at practical timestep sizes.
At each simulation step, the engine formulates contact force computation as a convex optimization problem. The solver minimizes a quadratic cost subject to linear constraints derived from the contact geometry and friction cone. Because the problem is convex, it has a unique global solution that can be found reliably and quickly, eliminating the chatter and jitter that plague engines using iterative constraint projection methods.
This formulation is the reason MuJoCo delivers stable, fast simulation for tasks like manipulation and locomotion, where contacts dominate the dynamics. The solver’s determinism and smoothness are particularly valuable for reinforcement learning, where noisy or inconsistent contact forces can destabilize policy training.
The trade-off is specialization. The solver is built for rigid bodies with well-defined contact geometry; it does not handle deformable objects such as cloth, soft tissue, or fluids. Users needing those capabilities must look to engines like Bullet or dedicated soft-body simulators. Within its rigid-body domain, however, the convex solver is what makes MuJoCo the default choice for contact-rich RL research.
Practical Gotchas and Tips
MuJoCo is not designed for deformable objects. If your task involves cloth, fluids, or soft tissue, use a dedicated engine such as Bullet or SOFA instead; MuJoCo’s solver assumes rigid bodies with compliant contacts, not material deformation.
Model conversion between URDF and MJCF is not lossless. Complex URDF models with nested links, non-standard joint limits, or custom collision geometries often require manual tweaking after conversion. Budget time for inspecting and adjusting the generated MJCF, particularly for mass properties and actuator definitions.
Simulation speed scales with model complexity. A humanoid with dozens of bodies and contacts runs slower than a single pendulum; high-frequency control loops (1 kHz or above) may fall below real-time on commodity hardware. Profile your model early and reduce contact pairs or use lower control rates if needed.
Rendering requires OpenGL context. On headless servers, use offscreen rendering with EGL or OSMesa rather than the default windowed viewer. Configure the EGL platform before importing MuJoCo to avoid context-creation failures.
Start with the Python bindings and an existing model from the MuJoCo model zoo. This gets you a working simulation loop in minutes and lets you learn the API against a known-good model before authoring your own MJCF.
What to take away
MuJoCo is the right tool when your problem is contact-rich rigid-body simulation and you need speed and stability. For reinforcement learning on manipulation, locomotion, or any task where bodies interact through surfaces, it is a defensible default choice. The Python bindings are official, the model format is well-documented, and the convex contact solver gives you deterministic, stable stepping that most alternatives do not match.
Start with an existing MJCF model rather than writing one from scratch. The format is precise but has a learning curve; adapting a known-good model teaches you the semantics faster than reading the specification. If you already have a URDF, import it, but expect to hand-tune contact parameters and joint limits after conversion.
Be clear about boundaries. MuJoCo does not model aerodynamics, fluids, or deformable bodies beyond limited soft contacts. If your task involves cloth, granular media, or aerodynamic effects, you will spend more time fighting the engine than building your control policy. For those cases, Bullet or a domain-specific simulator is the honest choice.
Performance claims vary by model and hardware. The engine is fast for typical articulated robots, but very high-frequency control loops or scenes with hundreds of bodies may fall below real time. Benchmark your specific model before committing.
The source code and documentation live at github.com/google-deepmind/mujoco.
Further diagrams



