MuJoCo Dynamics – Single DOF Trace Validation
Overview
Internally, MuJoCo uses
M(q) q̈ = qfrc_actuator + qfrc_passive + qfrc_constraint − qfrc_bias
Each term is reconstructed independently and compared with MuJoCo's internal solver output.
1. System Equation
MuJoCo implements rigid-body dynamics in the form:
M(q) q̈ + C(q, q̇) = τ
| Symbol | Meaning |
|---|---|
M(q) |
Mass matrix |
C(q,q̇) |
Coriolis + centrifugal + gravity |
τ |
All external generalized forces |
In MuJoCo, τ is not just the actuator term — it is the sum of all non-inertial forces:
motors, springs/dampers, contact forces, joint limits, and equality constraints.
Rewritten in solver form:
M(q) q̈ = τ_actuator + τ_passive + τ_constraint − C(q,q̇)
| Term | Meaning |
|---|---|
M(q) |
Mass matrix |
τ_actuator |
Actuator torques |
τ_passive |
Passive joint forces |
τ_constraint |
Contact and constraint forces |
τ_bias |
Coriolis + centrifugal + gravity |
MuJoCo defines: τ_bias := C(q,q̇) — exactly the value returned by mj_rne() with q̈ = 0.
qfrc ≡ τ stands for “q-space forces” — forces in the space of generalized coordinates q.
2. RNEA – Recursive Newton-Euler Algorithm
RNEA computes inverse dynamics according to Featherstone (Newton/Euler, O(n)):
Question: Which joint torques τ are required to generate a motion (q, q̇, q̈)?
Algorithm:
- Forward pass (base → end effectors):
- propagate angular velocities
- propagate accelerations
-
accumulate forces
-
Backward pass (end effectors → base):
- accumulate forces and torques
If q̈ = 0 is set:
mujoco.mj_rne(model, data, 0, result)
Then: τ_bias = C(q, q̇) — that is, all velocity- and gravity-dependent forces (gravity, Coriolis, centrifugal).
3. Control Input – Actuator
For a position actuator:
τ = kp · (ctrl − q) − kv · q̇
MuJoCo stores this internally in affine form:
τ = gain · ctrl + b0 + b1·q + b2·q̇
MuJoCo rewrites this algebraically as:
τ = kp·ctrl − kp·q − kv·q̇
= kp·ctrl + b1·q + b2·q̇ with b1 = −kp, b2 = −kv
The actuator force is then transformed into generalized coordinates:
qfrc_actuator = J_act^T · τ
Transmission Jacobian J_act:
- Describes actuator length as a function of DOF motion: J_act ∈ R^(n_act × n_dof)
- l̇ = J_act · q̇
- J_act^T transforms force from actuator space into DOF space
For joint actuators (<position joint="...">): l = q, therefore J_act = 1
→ qfrc_actuator[dof] = τ_actuator
4. Passive Forces
Computed in mj_passive():
τ_passive = − stiffness · (q − q_ref) # Hooke: q > q_ref → Feder zieht zurück
− damping · q̇ # viscous damping, opposite to velocity
− frictionloss · sign(q̇) # Coulomb friction, always braking
Explanation:
- Stiffness: If the joint is displaced, a restoring force acts on it
- Damping: Viscous damping proportional to velocity
- Coulomb friction:
q̇ > 0→ negative torque,q̇ < 0→ positive torque
If
frictionloss ≤ 0, MuJoCo ignores the Coulomb term.
All terms are dissipative — they reduce energy.
Parameters come from the XML: <joint damping="..." stiffness="..." frictionloss="..."/>
5. Constraint Forces
Constraints (contacts, joint limits, equality constraints) generate Lagrange multipliers λ.
MuJoCo solves the KKT system:
[ M Jᵀ ] [ q̈ ] [ τ ]
[ J 0 ] [ λ ] = [ b ]
| Symbol | Meaning |
|---|---|
J |
Constraint Jacobian |
λ |
Lagrange multipliers (reaction forces) |
b |
Constraint velocity / stabilization |
The generalized constraint torque:
τ_constraint = Jᵀ · λ
qfrc_constraint contains all constraint reactions:
- contact forces (normal + friction)
- joint limits
- equality constraints (welds, tendons, closed kinematic chains)
- friction constraints at contacts
qfrc_constraintis therefore not “just contact forces,” but the projection of all constraint reaction forces into joint space.
Constraint Jacobian in Detail
A constraint is an equation: ϕ(q) = 0
The constraint Jacobian is its derivative:
J(q) = ∂ϕ(q) / ∂q
For a small DOF delta δq: δϕ = J(q) · δq
- Each row → one constraint
- Each column → one DOF
Jdescribes how DOF motion affects constraint violationJᵀdistributes the constraint force back to the DOFs:τ_constraint = Jᵀ · λ
Every constraint that prevents motion must generate a reaction force — this is projected into generalized coordinates as τ_constraint = Jᵀ λ.
5.1 Contact Forces
Each contact generates multiple constraint equations depending on the friction model:
- elliptic friction → 3 constraints
- pyramidal friction → 4–5 constraints
These generate corresponding λ entries in data.efc_force.
Cartesian contact force:
mujoco.mj_contactForce(model, data, contact_id, force_array)
Generalized contribution:
τ_contact = J_contact^T · λ_contact
5.2 Joint Limits
If a joint reaches its limit (φ(q) ≥ 0), a constraint force λ_limit is generated:
τ_limit = J_limit^T · λ_limit
It is included in τ_constraint.
5.3 Equality Constraints
Enforce φ(q) = 0. Examples: weld constraints, loop closures, tendon-length constraints.
Contribution: τ_equality = J_equality^T · λ_equality
6. Total Torque & Acceleration
τ_total = qfrc_actuator + qfrc_passive + qfrc_constraint − qfrc_bias
q̈ = M⁻¹(q) · τ_total
All generalized forces are summed → equation of motion M(q)q̈ = τ_total → the solver solves for q̈.
Validation:
- Extract mass matrix:
mj_fullM - Solve the linear system with NumPy
- Compare against
data.qacc
Expected numerical deviation: ~1e−2 to 1e−3
7. Integration
With the implicitfast-Integrator:
v_{t+1} = v_t + a_{t+1} · dt
q_{t+1} = q_t + v_{t+1} · dt
This is implicit integration, not explicit Euler.
Therefore, small deviations arise when comparing against v_t + a_t·dt.
8. Indexing Rule
| Array | Index |
|---|---|
qvel, qacc |
DOF index |
qpos |
qpos index (jnt_qposadr) |
DOF index ≠ qpos index for free joints or quaternions.
9. Expected Numerical Tolerances
| Term | Typical deviation |
|---|---|
| Actuator | ~1e−7 |
| Bias (RNEA) | ~1e−3 |
| Constraint | solver-dependent |
| Acceleration | ~1e−2 |
| Position | ~1e−4 |