MuJoCo Solver#
SolverMuJoCo wraps mujoco_warp behind Newton’s standard
solver interface. Newton uses compatible-release pins (~=) on both mujoco
and mujoco-warp to keep the two version-aligned; see
pyproject.toml for the current pins.
Because MuJoCo has its own modeling conventions, many Newton properties are mapped differently or not at all. The sections below describe which Newton concepts the solver supports, how each is mapped to MuJoCo, how state is exchanged at every step, and where each piece of the conversion lives in the source. MuJoCo-specific behavior that has no Newton-core equivalent is exposed through the custom-attribute namespace. A code pointers section at the bottom collects the most useful anchor points.
Note
References to mjModel / mjData fields below (e.g.
mjData.contact, mjData.mocap_pos) use the canonical names
from MuJoCo’s mjModel
and mjData
reference. mujoco_warp exposes the same fields on its
GPU-resident analogues.
Joint types#
Newton type |
MuJoCo equivalent |
Notes |
|---|---|---|
|
Initial pose taken from |
|
|
Per-axis actuators mapped via |
|
|
||
|
||
Up to 3 × |
Each active linear/angular DOF becomes a separate MuJoCo joint with
a |
|
(no joint) |
The child body is nested directly under its parent. A fixed joint
connecting to the world produces a mocap body, driven via
|
|
(no joint) |
The distance constraint is dropped, but the body bookkeeping is handled like a free body (counted in MuJoCo’s free-body slots). |
|
unsupported |
Not forwarded to MuJoCo. |
Joint reference values (ref)#
MuJoCo scalar joints (hinge and slide) may carry a reference value
(MJCF ref, exposed as the mujoco.dof_ref custom attribute): the
authored body poses correspond to qpos = ref, and MuJoCo interprets
limits, position-actuator controls, and keyframes as absolute qpos
values. Newton has no reference concept — its scalar joint coordinates
are relative to the authored pose — so the two conventions are reconciled
at the solver boundary:
In Newton,
joint_q, joint limits (joint_limit_lower/joint_limit_upper), and position targets (Control.joint_target_q) are relative to the authored pose. The MJCF importer and MuJoCo-converter USD importer shift authored joint ranges by-refaccordingly.joint_qdis unaffected becauserefchanges position coordinates only.MuJoCo-side quantities keep MuJoCo’s absolute convention: the solver adds
refback when it writesqpos,jnt_range, and position-actuatorctrl, so the compiled MuJoCo model and its runtime observables (qpos, sensors) match the authored MJCF and native MuJoCo exactly.Attributes in the
mujoco.*custom-attribute namespace (for example authoredactuator_ctrlrange) are native MuJoCo data and remain in MuJoCo’s absolute units.
Changing mujoco.dof_ref at runtime (via
JOINT_REFERENCE_POSE_PROPERTIES or the broad
JOINT_DOF_PROPERTIES) shifts exported
qpos0, jnt_range, and position controls with the new reference.
Native MuJoCo attributes remain absolute and are not shifted. Core
joint_rest_q values are relative to the authored pose;
the solver exports them as qpos_spring = joint_rest_q + ref for scalar
joints.
Passive spring migration#
MuJoCo’s ref is the coordinate assigned to the authored pose;
springref is the spring equilibrium in that coordinate system.
Newton stores the relative coordinate rest_q = springref - ref,
after conversion to meters or radians. If springref is omitted,
MuJoCo defaults it to zero, giving rest_q = -ref.
Deprecated since version 1.8: Use joint_stiffness instead of
model.mujoco.dof_passive_stiffness. The old name remains a warning
alias to the same DOF-sized array for at least one minor release.
Reads and writes through this alias emit a NewtonDeprecationWarning.
In-place updates affect the core array directly.
Legacy mujoco:dof_passive_stiffness and mujoco:dof_springref
custom-attribute inputs remain accepted by registered builders but are also
deprecated since Newton 1.8. Finalization converts explicit programmatic inputs
once into the core arrays and emits a NewtonDeprecationWarning.
Ordinary MJCF and USD spring imports populate the core arrays without these
deprecation warnings. For a legacy stiffness
input without springref, the default is zero in MuJoCo coordinates
(rest_q = -ref), unless a core rest coordinate is already configured.
An explicit rest_q=0.0 also takes precedence over that default; use
rest_q=None to leave it unspecified. Conflicting explicitly configured
core rest coordinates and authored legacy rest values raise an error.
Runtime model.mujoco.dof_springref is deprecated since Newton 1.8. When the
model has no joints with more coordinates than DOFs (free, ball, distance, or
rod) and no nonzero mujoco:dof_ref at finalization, the DOF and coordinate
layouts coincide and springref equals rest_q, so the old name remains a
warning alias to joint_rest_q for at least one minor
release. The alias
tracks rest_q, so it no longer reports the absolute spring reference if
dof_ref is edited later. For other models, reads, assignments, and
deletions raise an AttributeError with migration guidance. Replace runtime
accesses with joint_rest_q, subtract ref from legacy values, and index
by joint_q_start.
To change a spring at runtime, edit joint_stiffness
or joint_rest_q and notify the solver with
JOINT_DOF_PROPERTIES. Subsequent dof_ref
changes leave the Newton rest coordinate fixed and export
qpos_spring = joint_rest_q + ref, regardless of whether the spring was
authored through core fields, legacy builder inputs, MJCF, or USD. This replaces
the legacy rule that kept the absolute MuJoCo spring reference fixed.
BALL rest quaternions are transformed from the child joint frame to MuJoCo’s
body frame. A JOINT_PROPERTIES notification refreshes
this conversion after child-frame edits, using the last published rest pose.
Use JOINT_REFERENCE_POSE_PROPERTIES to publish rest
edits separately, or JOINT_DOF_PROPERTIES for a full
joint DOF update.
Geometry types#
Newton type |
MuJoCo equivalent |
Notes |
|---|---|---|
|
||
|
||
|
||
|
||
|
||
|
Must be attached to a static body ( |
|
|
Heightfield data is stored normalized to |
|
|
MuJoCo only supports convex collision meshes. Non-convex
meshes are convex-hulled by MuJoCo’s compiler (not by Newton),
which changes the collision boundary. The mesh source’s
|
|
|
MuJoCo has no cone primitive, so Newton tessellates the cone into a
32-segment mesh at conversion time. Collision uses that convex
polyhedral approximation. Changing |
|
unsupported |
Not present in the MuJoCo geom-type map. |
Sites (shapes with the SITE flag) are converted to MuJoCo sites —
non-colliding reference frames used for sensor attachment and spatial
tendon wrap anchors. Only SPHERE, CAPSULE, CYLINDER, and
BOX are MuJoCo-native site geom types; other types silently fall
back to SPHERE.
Several Newton collision features — for example non-convex trimesh, SDF-based contacts, and hydroelastic contacts — are not part of the MuJoCo geometry model. They are only available through Newton’s collision pipeline (see Collision pipeline below).
Joint-limit stiffness and damping#
joint_limit_ke and
joint_limit_kd are force-space gains (for example,
N·m/rad and N·m·s/rad for revolute joints). MuJoCo converts
solreflimit to an effective limit response using the owning DOF’s
dof_invweight0 and the limit impedance parameter
dmax = solimplimit[1]:
To keep Newton’s force-space meaning,
SolverMuJoCo first scales the direct
stiffness/damping pair by factor = dof_invweight0 * (1 - dmax) and then
converts that pair to MuJoCo’s positive (timeconst, dampratio) convention:
The positive convention preserves the same unclamped force-space response as
the equivalent direct stiffness/damping pair while allowing MuJoCo’s
refsafe timestep clamp to soften limits that are too stiff for the step
size. This update runs after MuJoCo has compiled or refreshed
dof_invweight0. If joint_limit_ke <= 0 or joint_limit_kd <= 0, the
solver restores MuJoCo’s default solreflimit value (0.02, 1.0).
MJCF- or USD-authored solreflimit values are already native MuJoCo
parameters, so they are preserved verbatim through the
model.mujoco.solreflimit custom attribute and are not rescaled. Neither
MJCF import nor USD import through the MuJoCo schema derives generic
joint_limit_ke or joint_limit_kd values from solreflimit; those
gains retain Newton builder defaults or values supplied by a generic schema.
An authored native value wins in SolverMuJoCo, while
the generic gains remain available to other solvers. Imported joints that did
not author solreflimit keep MuJoCo’s implicit default (0.02, 1.0) until
either generic gain is configured or edited, including edits made before
constructing the solver, at which point the Newton force-space scaling above is
used. model.mujoco.solreflimit_gain_baseline records the generic gains seen
at import time so that edits made before construction can be detected.
model.mujoco.solreflimit_mode records how solreflimit should be
interpreted: Newton force-space gains, a raw authored MuJoCo value, or an
implicit MJCF default. This extra flag is needed because the two-component
solreflimit value alone cannot distinguish an unauthored value from an
authored native value such as solreflimit="0 0" or USD
mjc:solreflimit = [0, 0].
Authored raw solreflimit values are validated during solver construction
and eager JOINT_DOF_FORCE_PROPERTIES or
JOINT_DOF_PROPERTIES notifications on both backends. CUDA graph capture skips this host validation and leaves it
pending until the next eager solref update. Graph replay does not validate
values; call notify_model_changed() with
either force-update flag outside capture after reassigning raw values to
check them. Joint-transform notifications do not validate joint-limit
parameters or consume pending validation.
On the MuJoCo Warp backend, runtime joint- and tendon-limit updates are
stored in solver.mjw_model.jnt_solref, tendon_solref_lim, and
tendon_range per world. The corresponding arrays in the host template
solver.mj_model are not updated; inspect the Warp arrays for current
values. The MuJoCo CPU backend keeps the host arrays synchronized.
Note
SolverMuJoCo(..., save_to_mjcf=path) is not a fully semantic
round-trip for SOLREF_MODE_FORCE_SPACE joints. MJCF only stores
solreflimit; it has no field for “use Newton force-space
scaling with these gains”. The exporter therefore only writes
solreflimit for SOLREF_MODE_RAW joints (where the authored
value carries the full intent). joint_limit_ke /
joint_limit_kd from the original SOLREF_MODE_FORCE_SPACE /
SOLREF_MODE_MJCF_DEFAULT joints will not be preserved; reapply
them on the rebuilt model if you need those force-space gains.
Shape-material contact stiffness and damping#
shape_material_ke and
shape_material_kd are force-space stiffness and
damping (N/m and N·s/m), but their realized response depends on the
active mapping. On the force-space Newton-contacts path,
SolverMuJoCo mixes the two shapes’ gains and scales the
pair by 1 - dmax and the sum of the bodies’ translational
body_invweight0[..., 0] values before writing per-contact solref. Here
dmax = solimp[1]. This inverse-weight scaling is Newton’s implemented
force-space contract. For pyramidal contacts with condim > 1, the factor
also includes mu**2 * (1 + mu**2) / (impratio * (condim - 1)) to account
for the summed pyramid-edge normal response. Here mu is the final sliding
friction after contact overrides. Elliptic and frictionless contacts retain
the inverse-weight factor alone. The same mapping applies to positive
per-contact stiffness and damping overrides; zero per-contact damping retains
the critical-damping fallback.
This resting-contact approximation is not the full scalar contact effective mass \((J M^{-1} J^T)^{-1}\) for arbitrary articulated or off-center contacts.
model.mujoco.solref_mode (per shape) records how
shape_material_ke / shape_material_kd and mujoco.solref
combine, with the same three states as joint limits. The list describes existing
model and implementation behavior; the constants are not a public selection
API:
SOLREF_MODE_FORCE_SPACE— Newton force-space gains; the per-contact factor above applies.SOLREF_MODE_RAW— forward the authoredmujoco.solref(e.g. from an MJCF/USD import) unchanged.SOLREF_MODE_MJCF_DEFAULT— registered default; preserves MuJoCo’s compile-time contact dynamics and the legacy unit-mass numericalconvert_solref(ke, kd, 1, 1)round-trip ingeom_solref.
Contact solref conversion#
For positive numeric ke and kd, the legacy
convert_solref(ke, kd, 1, 1) mapping writes:
Under this unit-mass numerical mapping, sqrt(ke) behaves like a frequency
and holding the numerical damping ratio fixed requires kd to scale with
sqrt(ke). This is not a dimensionally physical critical-damping rule for an
arbitrary contact mass. The force-space path applies the implemented
body_invweight0 factor above before the same conversion; the formula then
describes the scaled numerical solref, not an exact Jacobian-derived contact
response. See the implementation in
newton/_src/solvers/mujoco/kernels.py and its force-space contact tests
in newton/tests/test_mujoco_solver.py.
With MuJoCo’s default refsafe guard enabled, MuJoCo-Warp evaluates positive
solref using max(timeconst, 2 * dt) for the active constraint without
rewriting the stored value. Direct-format negative solref bypasses this
clamp. Once a requested positive timeconst falls below that floor, raising
the gains at a fixed damping ratio no longer hardens the effective response;
reduce the step passed to step() instead. See
MuJoCo’s refsafe option.
These SOLREF_MODE_* names describe internal mode values; they are not
public Newton symbols. MJCF/USD import selects the appropriate authored/default
mode automatically. Do not import the constants from newton._src to change
the mode from user code.
Note
use_mujoco_contacts=True does not apply the per-contact two-body
factor — MuJoCo’s internal contact_params averages per-geom
solref, which cannot reproduce the inverse-mass sum.
SOLREF_MODE_FORCE_SPACE shapes fall back to the legacy
convert_solref(ke, kd, 1, 1) approximation on that path.
For parameter interpretation, stability tradeoffs, and task-oriented guidance, see MuJoCo-Warp Contact Tuning.
Contact friction solreffriction mapping#
For SolverMuJoCo, kf maps to MuJoCo’s per-contact
solreffriction with elliptic friction cones (cone="elliptic") and Newton
contacts (use_mujoco_contacts=False). It targets the force-space friction slope
f = -kf * v below the Coulomb limit. The mapping is exact when the sum of
MuJoCo’s translational body_invweight0 values matches the contact’s inverse
effective mass (the relevant diagonal of \(J M^{-1} J^T\)) and the contact
operates at its maximum impedance dmax. Very large kf saturates at
MuJoCo’s refsafe stability bound, where the reference time constant is clamped
to twice the timestep.
The two shapes’ kf values combine with the usual priority/solmix
weighting. A resolved kf = 0 makes the contact frictionless
(condim = 1), removing its sliding, torsional, and rolling friction rows.
If a positive kf cannot produce a positive, finite inverse-weight
denominator, solreffriction remains unset and MuJoCo inherits the normal
solref. The mapping is independent of the shape’s solref_mode above,
which only governs the normal-direction solref.
The slope is calibrated for the sliding friction rows. With condim > 3, the
torsional and rolling rows share the same per-contact solreffriction and
MuJoCo scales their regularization by the corresponding friction-coefficient
ratios, so their effective damping deviates from kf accordingly.
Actuators#
Newton’s per-DOF joint_target_mode creates MuJoCo general actuators:
Mode |
MuJoCo actuator(s) |
|---|---|
One actuator: |
|
One actuator: |
|
Two actuators — a position actuator ( |
|
No MuJoCo actuator created. |
joint_effort_limit is forwarded as actfrcrange on the joint
(prismatic, revolute, and D6) or as forcerange on the actuator (ball).
For MJCF position-only drives with dampratio and the default joint-target
control mapping, solver construction resolves damping using each world’s
initial physical inertia, authored armature, and position gain. It replaces the imported
damping-ratio placeholder with the resulting coefficient and initializes zero entries in
joint_target_kd; nonzero explicit damping is preserved.
Subsequent gain edits use the joint-target arrays and
JOINT_DOF_FORCE_PROPERTIES as usual.
The full MuJoCo general-actuator model (arbitrary gain/bias/dynamics types
and parameters, explicit transmission targets, ctrl/force/act ranges) is
only reachable through the mujoco custom-attribute namespace.
The newton.solvers.mujoco helpers
add_actuator_dcmotor, add_actuator_general, add_actuator_motor, add_actuator_position,
and add_actuator_velocity author complete
actuator rows from a typed ActuatorTarget. Scalar and D6 joints support
local or absolute DOF selection. Ball/free joints instead require an explicit
native MuJoCo gear vector: ball-joint torque is in the child body frame;
free-joint force is in the world frame at the body origin, and its torque is
in the child body frame. These are different from Newton’s parent-frame,
COM-based DOF convention. Use joint_f for forces in
Newton’s DOF convention.
Additional actuators declared this way are appended after the joint-target
actuators — see SolverMuJoCo._init_actuators.
MJCF <dcmotor> actuators follow this MuJoCo-specific path. The importer uses
MuJoCo’s native parser to resolve electrical, controller, thermal, cogging, and
LuGre parameters, including inherited defaults, into the existing actuator
parameter arrays for both the CPU and MuJoCo-Warp backends. Importing these
shortcuts requires the optional mujoco package and raises ImportError
with installation guidance when it is unavailable. Install newton[sim] to
include MuJoCo. Ordinary MJCF and compiled <general> actuator import do not
require MuJoCo; parsing DC-motor shortcuts does not require MuJoCo-Warp.
Commands use the MJCF actuator order in control.mujoco.ctrl. The supported
input signatures each consume one control value: voltage, pos, or
vel, using native MuJoCo keywords only.
MuJoCo’s ff, none, and combined multi-input signatures are not yet
supported by Newton’s one-control-per-actuator mapping. Compiled MJCF
<general> and USD MjcActuator rows preserve the low-level parameter
arrays and a supported input or mjc:ctrlSpec value, respectively.
The MJCF importer and add_actuator_dcmotor()
set DCMOTOR
to mark resolved DC-motor parameters as construction-time
properties; use the helper or importer to populate the associated parameters.
Runtime edits to actuator_gainprm,
actuator_biasprm, actuator_dynprm, and actuator_forcerange are ignored
for these rows to preserve the native compiler’s output. Compiled MJCF and USD
DC motors instead use CtrlType.GENERAL with actuator_gaintype set to DC motor:
their low-level arrays remain runtime-editable, including after saving and
reimporting compiled MJCF. Compilation preserves the dynamics, not the shortcut’s
authoring-time parameter ownership.
Actuator damping is preserved on both backends. MuJoCo-Warp 3.15 folds it into
joint and tendon damping; Newton retains that contribution when publishing
joint or tendon property updates. Actuator armature is preserved only on the
native MuJoCo CPU backend (use_mujoco_cpu=True); the Warp backend emits a
NewtonWarning when it is nonzero. This limitation applies to all actuator
types, not only DC motors. MJCF damping accepts one, two, or three coefficients:
the first is stored in mujoco:actuator_damping and the remaining two in
mujoco:actuator_dampingpoly. Partial overrides retain inherited trailing
coefficients; otherwise omitted coefficients default to zero. Compiled USD rows can author
the corresponding mjc:damping scalar and mjc:dampingPoly pair. These
passive properties are set at solver construction, must be uniform across
replicated worlds, and are not refreshed by notify_model_changed(ACTUATOR_PROPERTIES).
The solver rejects mismatched passive properties or control signatures across worlds,
including on compiled GENERAL rows. Worlds must also have matching actuator row counts.
Warp’s folded damping uses the construction-time transmission gear. For actuators
with nonzero linear or polynomial damping, actuator_gear must match the compiled
gear in every world and remain unchanged. Construction and eager property
notifications reject mismatches; captured notifications retain the compiled gear.
Recreate the solver to change these gears. Undamped Warp actuators still support
per-world and runtime gear edits. Native CPU actuator gears remain runtime-editable.
DC-motor trajectory parity with native MuJoCo is tested with integrator="euler";
MuJoCo-Warp’s approximate implicit DC-motor derivatives can produce different
trajectories with implicitfast.
When using separate_worlds=True, corresponding high-level <dcmotor>
actuators (including those created by the helper) must have identical parameters because MuJoCo-Warp replicates one
compiled template model across worlds.
This native, stateful MuJoCo actuator is distinct from
ClampingDCMotor, which is a stateless Newton
clamping stage and does not model winding current, thermal effects, cogging, or
LuGre friction.
For programmatic authoring, use the same typed targets as the other MuJoCo helpers:
from newton.solvers import mujoco
actuator = mujoco.add_actuator_dcmotor(
builder,
target=mujoco.ActuatorTarget.joint(joint),
motorconst=(0.05,),
resistance=2.0,
input="voltage",
ctrlrange=(-12.0, 12.0),
)
The helper registers MuJoCo custom attributes automatically and returns the
actuator row index for control.mujoco.ctrl. It requires native MuJoCo to
resolve shortcut parameters, but does not compile a model or import MuJoCo-Warp.
Equality constraints#
Use EqType for MuJoCo equality
constraint types.
Each row’s data[...] reference below points into MuJoCo’s
equality.data
array; slot layout depends on the constraint type.
Newton type |
MuJoCo equivalent |
Notes |
|---|---|---|
|
Anchor forwarded in |
|
|
Anchor forwarded in |
|
|
Polynomial coefficients forwarded in |
|
|
Couples two |
|
Mimic |
|
Added via |
Newton’s core API does not expose equality constraints as a dedicated
builder call. Construct them with the
newton.solvers.mujoco helpers
add_equality_connect, add_equality_weld, add_equality_joint, and
add_equality_tendon,
then read or update finalized fields via
model.mujoco.equality_constraint_*:
from newton.solvers import mujoco
mujoco.add_equality_connect(builder, body1, body2, anchor=(0.0, 0.0, 0.0))
The helpers write rows in the MuJoCo
custom-attribute namespace. The equivalent
lower-level form uses add_custom_values() with the
mujoco:equality_constraint_* keys; fields that do not apply to connect
constraints retain their registered defaults.
import newton
import warp as wp
builder.add_custom_values(
**{
"mujoco:equality_constraint_type": int(
newton.solvers.SolverMuJoCo.EqType.CONNECT
),
"mujoco:equality_constraint_body1": body1,
"mujoco:equality_constraint_body2": body2,
"mujoco:equality_constraint_anchor": wp.vec3(0.0, 0.0, 0.0),
"mujoco:equality_constraint_enabled": True,
}
)
mujoco:equality_constraint_world has references="world", so omitting
it assigns the row to builder.current_world. Pass an explicit world index,
including -1 for the global world, when that is the intended owner instead.
Loop closures#
Loop-closing joints (see Loop closure for the general authoring pattern) are not emitted as MuJoCo joints; instead the solver constrains the relative motion of the two bodies according to the joint type:
FIXED— all 6 relative DOFs constrained (relative position and orientation locked).REVOLUTE— 5 DOFs constrained; one rotational DOF about the hinge axis remains free.BALL— the 3 translational DOFs constrained; all 3 rotational DOFs remain free.
Other joint types used as loop closures
(PRISMATIC, FREE,
DISTANCE, ROD) emit a
warning and are silently skipped — the loop is not closed. A
D6 is dispatched by its degrees of freedom: one
angular axis behaves as a revolute closure and three as a ball closure;
any other configuration is skipped.
Only the kinematic coupling implied by the joint type is enforced. Any
drive (joint_target_q / joint_target_qd, PD gains,
control.joint_f), joint limits, armature, friction, and
effort/velocity limits authored on the loop-closing joint are ignored
by SolverMuJoCo. Loop-joint DOFs and coordinates
are excluded from MuJoCo’s nq / nv.
Tendons#
MuJoCo’s fixed and spatial tendons use the
custom-attribute namespace: populated
on import from MJCF/USD and parsed into MuJoCo’s tendon structures by
SolverMuJoCo._init_tendons. To author tendons programmatically, use
add_tendon_fixed and add_tendon_spatial from
newton.solvers.mujoco. Spatial tendons support site,
geom, and pulley wrap elements; any other wrap type and any
degenerate tendon definition produces a warning and is skipped rather
than raising.
These provider tendons are separate from Newton’s experimental
massless routed tendons used by XPBD and VBD. There is no
automatic conversion between native Model.tendon_* routes and
model.mujoco.tendon_* data. USD MjcTendon import and tendon-actuator
target resolution use the provider path; see
USD Parsing and Schema Resolver System for supported path attributes.
For force-based limit gains, set model.mujoco.tendon_limit_ke (stiffness
[N/m]) and tendon_limit_kd (damping [N s/m]), select force-space authoring
with tendon_solref_limit_mode = 0, then notify
TENDON_PROPERTIES. For angular tendon coordinates,
the corresponding units are [N m/rad] and [N m s/rad]. The solver converts
these gains to solreflimit using tendon inverse inertia and impedance,
and refreshes the conversion after inertia changes, as it does for joint limits.
MuJoCo impedance and timestep clamping still affect transient response.
tendon_solref_limit_mode follows the joint-limit authoring convention:
0 selects Newton force gains, 1 preserves authored MuJoCo parameters, and 2
uses MuJoCo’s implicit default. Tendons default to mode 1 and report their
equivalent force gains after solver initialization. In force-space mode,
zero stiffness disables the limit without changing the authored tendon_range.
Limit damping is independent of passive tendon_damping. Tendon limits must
already be enabled in the imported model.
model.mujoco.tendon_limit_ke.fill_(100.0)
model.mujoco.tendon_limit_kd.fill_(20.0)
model.mujoco.tendon_solref_limit_mode.zero_() # Newton force-space mode
solver.notify_model_changed(newton.ModelFlags.TENDON_PROPERTIES)
Collision pipeline#
SolverMuJoCo uses MuJoCo’s built-in collision
detection by default. Construct it with use_mujoco_contacts=False
to feed contacts computed by Newton’s own collision pipeline into
step() instead.
Newton’s pipeline supports non-convex meshes, SDF-based contacts, and
hydroelastic contacts, which are not available through MuJoCo’s collision
detection.
With SolverMuJoCo using MuJoCo Warp,
integrator="rk4" and use_mujoco_contacts=False reuse contact positions,
distances, and normals at RK4’s intermediate stages. This can reduce contact
accuracy as bodies move, and the solver warns at construction. Use
integrator="implicitfast" or use_mujoco_contacts=True to avoid this
limitation.
Collision filtering#
MuJoCo gives every geom two 32-bit masks, contype and conaffinity.
Together, these masks decide whether two geoms are allowed to collide. For a
candidate pair a, b, the mask test passes when
(contype_a & conaffinity_b) != 0 or
(contype_b & conaffinity_a) != 0. MuJoCo then applies other selection
rules, including same-body suppression and body-wide <exclude> elements;
explicit <pair> elements bypass the automatic mask test. See MuJoCo’s
collision selection documentation
and the geom mask attributes.
Importing MJCF masks.
parse_mjcf() resolves inherited contype and
conaffinity values and determines which shape pairs may collide. It stores
the same result in Newton collision groups and explicit excluded pairs. The
original 32-bit values are also retained as
model.mujoco.contype and model.mujoco.conaffinity custom attributes
for a lossless round trip back to MuJoCo.
A mask domain is the set of shapes whose mask bits were authored together.
Each parse_mjcf() call creates a new domain and records it
in the internal model.mujoco.collision_mask_domain attribute. The domain
is only a source label. It is not another collision mask and does not enable
or disable contacts. When add_builder() combines
separately built models, it gives the copied domains new IDs so they remain
distinct from domains already in the destination builder.
Choosing masks for a MuJoCo solver.
With use_mujoco_contacts=True, preserved source masks are forwarded
verbatim only when every selected collision shape has masks from the same
domain and those masks already enforce all active Newton pair filters.
Same-body filtering and imported body-wide <exclude> elements also count
as enforced. This path preserves the source MJCF exactly. For a single import,
the original masks therefore remain the source of truth even if its Newton
collision groups are later edited.
A native shape, shapes from more than one domain, or a new Newton pair filter can make the original masks unsafe to reuse. The solver then lists the shape pairs that Newton allows and creates new MuJoCo masks that reproduce that list.
Example: combining two MJCF files.
Suppose file A and file B both use bit 0. In file A, bit 0 may control contacts between its floor and spheres. File B may reuse bit 0 for its own shapes. The files were authored independently, so that shared number says nothing about how a shape from A should interact with a shape from B.
After both files are added to one builder, Newton’s collision groups and excluded pairs define those new cross-file interactions. Copying the original masks would make MuJoCo treat bit 0 as one global rule and could allow or block the wrong cross-file pairs. Because the shapes have different domains, the solver instead creates new masks from Newton’s final list of allowed pairs.
Compiling Newton filtering to MuJoCo masks.
MuJoCo provides only 32 mask bits. One bit can encode all collisions between one set of shapes and another set. In graph terminology, that rule is a complete bipartite graph, or biclique. The solver tries to reproduce Newton’s full list of allowed pairs using at most 32 such rules. It is guaranteed to find an exact result for up to 33 selected shapes and often handles much larger models whose collision groups have a regular structure.
If the rules do not fit in 32 bits, the solver uses the established legacy graph-color approximation, which may allow extra contacts. Finding an exact result requires checking every shape pair, so models above 256 selected shapes or 1,024 explicit excluded pairs skip directly to that fallback.
Margin and gap mapping#
shape_margin maps to MuJoCo
geom_margin and shape_gap maps to geom_gap;
authored contact-pair values similarly map to pair_margin and pair_gap.
The margin mapping is subject to Margin zeroing below. The solver forwards gap
values at construction and runtime property updates. MuJoCo reports surface
distances in (margin, margin + gap] as inactive contacts without contact
force. See margin and gap semantics for Newton’s contact geometry and MuJoCo’s margin and
gap model
for the three contact regimes.
MJCF and USD margin/gap values use direct MuJoCo 3.9+ semantics. Pass
legacy_margin_gap=True to add_mjcf() or
add_usd() only when reproducing Newton’s pre-3.9
import translation.
Multi-contact CCD. Constructing
SolverMuJoCo with enable_multiccd=True
allows up to four contact points per geom pair instead of one. Pairs
where either geom has non-zero MuJoCo geom_margin still fall back
to a single contact regardless of the flag (see Margin zeroing
below for how Newton’s shape_margin is forwarded
to it). MuJoCo Warp currently remains single-contact for cylinder–box;
see Geometry-Pair Contact Behavior.
Margin zeroing. mujoco_warp rejects non-zero geom margins on
box-box pairs (its default NATIVECCD path) and on any box/mesh pair
when enable_multiccd=True. To stay compatible SolverMuJoCo zeroes
geom_margin model-wide at compile time whenever a box geom exists,
or whenever enable_multiccd=True is combined with mesh geoms; geoms
with non-zero authored margins emit a warning when
use_mujoco_contacts=True. The Newton model’s shape_margin array
is left untouched, and when use_mujoco_contacts=False the authored
margins are restored at runtime through update_geom_properties_kernel.
Contact pairs#
Newton’s core API does not expose explicit MuJoCo-style <pair>
contact overrides. They are implemented through the MuJoCo
custom-attribute namespace and
parsed into MuJoCo’s geom-pair contact structures by
SolverMuJoCo._init_pairs. To author a pair programmatically, use
add_contact_pair from newton.solvers.mujoco.
Multi-world support#
Constructing SolverMuJoCo with
separate_worlds=True (the default for GPU mode with multiple
worlds) builds a shared MuJoCo topology across worlds via mujoco_warp.
Bodies, joints, equality constraints, mimic relationships, primitive geoms,
and sites must have matching layouts. With use_mujoco_cpu=False, mesh,
heightfield, and cone assets, scales, and convex-hull counts may differ across worlds. Collision
flags may also differ when Newton supplies contacts. Native MuJoCo contacts
require matching collision flags, groups, and exclusions for corresponding geom
slots. With native contacts,
per-world mesh scales are compiled into the MuJoCo assets, so changing their
shape_scale after construction raises ValueError;
recreate the solver to resize them. The solver validates
compatibility at construction and raises ValueError on a mismatch.
Bodies, joints, equality constraints, and mimic relationships cannot have
a negative world index — assigning any of them to the global world
raises ValueError. Only shapes may live in the global world (-1);
they are shared across all worlds without replication.
Runtime state synchronization#
Each call to step() goes through the
same three-phase cycle:
Push Newton → MuJoCo.
SolverMuJoCo._apply_mjc_controlandSolverMuJoCo._update_mjc_datatransfer the NewtonStateandControlinputs to MuJoCo’s working data. Whenuse_mujoco_contacts=False, Newton-side contacts are also converted before the integrator runs. The joint-state re-sync frequency can be controlled via the deprecatedupdate_data_intervalkwarg; it will be removed and the joint state will then be synchronized on every step.Integrate.
mujoco_warpsteps the MuJoCo model forward bydt.Pull MuJoCo → Newton.
SolverMuJoCo._update_newton_statepopulates the outputStatefrom the integrated MuJoCo data. Kinematic roots pass through unchanged fromstate_in(see Kinematic links and fixed roots).
Request CONTACT_F with solver.observables(..., contacts=contacts) and pass
the container to solver.step(..., observables=observables). Forces are written
to observables.contact_f; with use_mujoco_contacts=True, the step also
fills the supplied contacts with contact geometry. See Solver Observables.
Separated speculative contacts#
With use_mujoco_contacts=False, Newton’s collision pipeline can generate
separated candidates using velocity expansion. By default, MuJoCo activates
constraints only inside the authored collision margin. Generating a candidate
alone therefore does not prevent an object from crossing a thin collider in
one dynamics step.
Set use_speculative_contacts=True to add frictionless normal constraints
for separated candidates. Their target bounds closing velocity by the current
clearance divided by the physics timestep. Collision margins and the material
response of penetrating contacts retain their authored values. Friction begins
when the surfaces enter the authored margin.
Experimental
The SolverMuJoCo(use_speculative_contacts=True) mode may change without
prior notice. It requires Newton contacts on the MuJoCo Warp backend and
Euler or implicitfast integration. It does not provide continuous collision
detection or guarantee zero penetration: candidate coverage, rotation,
contact compliance, forces, and timestep still matter.
This is a runtime solver option, like the choice of contact backend. It does not add an asset-authoring attribute or change the USD collision schema.
Pass a velocity-expansion horizon to the collision pipeline before each step:
pipeline = newton.CollisionPipeline(model, speculative_contact_gap_max=0.05)
contacts = pipeline.contacts()
solver = newton.solvers.SolverMuJoCo(
model, use_mujoco_contacts=False, use_speculative_contacts=True
)
pipeline.collide(state_in, contacts, dt=dt)
solver.step(state_in, state_out, control, contacts, dt)
For scheduled collision refreshes, the expansion horizon must cover the interval until the next refresh. The solver’s velocity bound uses each individual dynamics timestep. Speculative constraints can consume additional constraint rows, so check contact and constraint capacities for the scene.
Push, pull, and contact export are implemented by
SolverMuJoCo._apply_mjc_control, SolverMuJoCo._update_newton_state,
and SolverMuJoCo._populate_contact_observables. The MuJoCo Warp path uses kernels
from newton/_src/solvers/mujoco/kernels.py — see
Code pointers for the full anchor list.
Solver options#
MuJoCo solver parameters follow a three-level resolution priority:
Constructor argument passed to
SolverMuJoCo— one value, applied to all worlds. The full list of kwargs, their types, and their defaults is documented on the class itself.Custom attribute (
model.mujoco.<option>) — supports per-world values. Typically populated automatically by USD or MJCF import.Default — if neither of the above is set, the MuJoCo default is used, with one Newton-opinionated exception:
integratordefaults toimplicitfast(MuJoCo’s default iseuler) for better stability on stiff systems.
These values are read once during SolverMuJoCo
construction. Editing model.mujoco.<option> afterwards has no
effect — the resolved value is already baked into the underlying
MuJoCo model.
See MuJoCo’s solver documentation and <option> XML reference for what each parameter does and when to tune it.
Imported option flags#
MJCF <option><flag> settings are stored as boolean ONCE custom
attributes, model.mujoco.flag_<name>, with True meaning enabled.
The same attributes can be authored on a USD PhysicsScene through
MjcSceneAPI names mjc:flag:<name>. Supported names are
constraint, equality, frictionloss, limit, contact,
spring, damper, clampctrl, warmstart,
actuation, refsafe, sensor, eulerdamp, nativeccd,
island, multiccd, energy, and invdiscrete.
enable_multiccd, disable_contacts, and disable_sensors default
to None: explicit constructor arguments take precedence over model
custom attributes, then Newton defaults. By default, multiccd,
energy, and invdiscrete are disabled; the other listed features
are enabled. sleep uses the existing model.mujoco.enable_sleeping
attribute described below and requires island to remain enabled.
Unknown flags and the Warp-unsupported
override, fwdinv, diagexact, midphase, and autoreset
flags are warned about and ignored during MJCF import. filterparent
is also warned about and ignored because imported parent-child collision
filters are not controlled by this flag.
gravity="disable" sets Newton’s builder gravity to zero, affecting
all solvers and content already added to the shared builder. Inside
begin_world() / end_world(), only that world’s gravity is changed;
outside a world, the global/default gravity is changed. A later import
with gravity="enable" does not restore the previous gravity vector.
Sleeping#
MuJoCo Warp can exclude stationary constraint islands from collision detection and the compact Newton solver. Newton keeps this optimization disabled by default. Enable it when simulating many passive objects that spend substantial time at rest. Sleeping adds island bookkeeping and uses the compact-solver path even while everything remains awake, so scenes in which most degrees of freedom remain awake can be slower than with sleeping disabled. Benchmark representative workloads before enabling it:
solver = SolverMuJoCo(
model,
enable_sleeping=True,
sleep_tolerance=0.01,
)
Sleeping is only supported by Newton’s MuJoCo Warp GPU path. It requires
solver="newton" and use_mujoco_contacts=True so MuJoCo Warp’s
collision pipeline can wake sleeping bodies, and it does not support the RK4
integrator. Unsupported combinations raise ValueError during solver
construction. When an imported MJCF contains
<option><flag sleep="enable"/></option>, leaving enable_sleeping as
None honors that setting. An explicit constructor value takes precedence.
sleep_tolerance is the scaled generalized-velocity threshold [m/s] below
which an island becomes eligible to sleep. It follows the normal
Solver options resolution order, including per-world
model.mujoco.sleep_tolerance values. The default is 0.001.
MuJoCo’s per-tree body/sleep policy is available as the body-frequency
model.mujoco.sleep_policy custom attribute and is imported from MJCF.
The supported values are AUTO,
NEVER,
ALLOWED, and
INIT. The policy must be
assigned to the moving root body of a MuJoCo kinematic tree. For a
programmatically built model, register the MuJoCo custom attributes before
adding the body:
builder = newton.ModelBuilder()
SolverMuJoCo.register_custom_attributes(builder)
root = builder.add_link(
custom_attributes={
"mujoco:sleep_policy": SolverMuJoCo.SleepPolicy.INIT,
},
)
INIT makes the tree start asleep and is the intended way to construct a
solver with compact nvmax storage. The setting applies to the shared model,
so replicated worlds receive the same initial tree policies. Their default
joint velocities must also match because MuJoCo Warp uses one shared initial
sleep state; solver construction rejects differing per-world defaults.
nvmax sizes the compact solver’s active-DOF workspace per world. If it is
None, MuJoCo Warp uses the model’s full nv. This is the safe starting
point but does not reduce compact-workspace memory. Tune a smaller value to
the maximum number of DOFs expected to be awake simultaneously. The capacity
must include every DOF that is awake in the initial MuJoCo state; Newton rejects
smaller values before allocating solver data. nvmax is rejected when
sleeping is disabled because MuJoCo Warp would otherwise allocate unused
compact-solver workspace. If more than nvmax DOFs become active later,
MuJoCo Warp sets the NVMAX bit in
solver.mjw_data.overflow; increase nvmax and recreate the solver.
MuJoCo Warp automatically wakes islands for applied forces and contacts.
Actuated trees are not allowed to sleep by default. If their sleep policy is
explicitly changed to allow sleeping, changing actuator controls alone does not
wake them; apply a force or set a nonzero velocity first. Newton-side
joint-position edits wake only the affected sleeping trees.
reset() restores the initial sleep state in
selected worlds, while
notify_model_changed() wakes all worlds
after model-property updates. The sleeping path supports whole-step CUDA graph
capture.
See MuJoCo’s sleeping-islands documentation
and MuJoCo Warp compact-solver guide for the
underlying sleep policy, wake triggers, and nvmax tuning guidance.
MuJoCo-specific parameters in USD and MJCF#
MuJoCo has parameters with no counterpart in Newton’s core API.
ModelBuilder handles them during MJCF / USD import
via two mechanisms.
Custom-attribute namespace. A dedicated mujoco custom-attribute
namespace (model.mujoco.<name>) is populated from MJCF elements
and from attributes in the OpenUSD MuJoCo schema (mjc:*). To
enable the namespace, call
register_custom_attributes() on the
ModelBuilder before adding anything to it:
import newton
from newton.solvers import SolverMuJoCo
builder = newton.ModelBuilder()
SolverMuJoCo.register_custom_attributes(builder)
# ...then add anything (e.g. import MJCF / USD, add joints, ...)
model = builder.finalize()
The authoritative list of registered attributes — names, defaults,
dtypes, MJCF / USD source names, and the category each belongs to —
is the body of
register_custom_attributes()
itself.
See Custom Attributes for how Newton’s
custom-attribute system works in general.
Direct mapping to Newton built-ins. Some MuJoCo-specific
attributes are mapped onto Newton’s built-in properties during import
(rather than the mujoco namespace). The MJCF parser handles these
inline (newton/_src/utils/import_mjcf.py); USD goes through
SchemaResolverMjc
(newton/_src/usd/schemas.py). Native MuJoCo solver parameters
such as MJCF solreflimit or USD mjc:solreflimit remain in the
mujoco namespace and do not overwrite Newton’s generic force-space
joint-limit gains.
MuJoCo joint damping maps to joint_damping;
stiffness maps to joint_stiffness, and scalar
springref - ref maps to joint_rest_q.
When importing MuJoCo-authored USD, opt into that mapping explicitly:
from newton.usd import SchemaResolverMjc, SchemaResolverNewton
builder.add_usd(
stage,
schema_resolvers=[SchemaResolverMjc(), SchemaResolverNewton()],
)
Registering MuJoCo custom attributes alone enables the model.mujoco
namespace but does not map mjc:damping to the built-in property.
Unsupported MuJoCo features#
The sections above describe what Newton forwards into MuJoCo. In the
other direction, MuJoCo has several modeling concepts that are not
imported when loading an MJCF or USD asset into Newton, and that
SolverMuJoCo does not reconstruct during conversion:
Sensors (
<sensor>— force/torque, IMU, gyro, accelerometer, rangefinder, touch, camera-based, …). Newton has its own sensor pipeline (Sensors) that is independent of the MuJoCo solver.Cameras and lights declared in MJCF/USD. Newton uses its own viewer and lighting pipeline; camera/light primitives in the source asset are ignored.
Keyframes (
<keyframe>) — MuJoCo’s saved-state / reset mechanism is not imported.Composite and flex (
<composite>,<flex>) — MuJoCo’s built-in deformables and soft bodies. Newton has dedicated solvers for cloth, MPM, and FEM; they are not part of the MuJoCo integration.Skinned meshes (
<skin>) — visualization-only, not imported.User plugins (
<plugin>) — MuJoCo’s plugin mechanism for custom passive forces or dynamics is not supported.User data and arbitrary custom elements (
<custom>,<numeric>,<text>) — not imported. Newton-specific user data should use the Newton custom-attribute system instead.Actuator transmissions —
joint,jointinparent,tendon,site,body, andslidercranktransmissions are supported (seeTrnTypefor the enum).
Smaller limitations are documented inline where they are most relevant — see Caveats below for collision-radius, convex-hull fallback, and velocity limits; and the unsupported rows in Joint types and Geometry types.
Caveats#
- shape_collision_radius is ignored.
MuJoCo computes bounding-sphere radii (
geom_rbound) internally from the geometry definition. Newton’sshape_collision_radiusis not forwarded.- Non-convex meshes are convex-hulled.
MuJoCo only supports convex collision geometry. Non-convex
MESHshapes are automatically convex-hulled at conversion time, changing the effective collision boundary.- Velocity limits are not forwarded.
Newton’s
joint_velocity_limithas no MuJoCo equivalent and is ignored.- Collision filtering has a 32-bit capacity.
The solver creates MuJoCo masks that reproduce Newton’s allowed collision pairs when they fit in 32 bits. See Collision filtering for the behavior of imported masks and the warned fallback used when the rules do not fit.
Kinematic links and fixed roots#
Newton only allows is_kinematic=True on articulation roots, so a
“kinematic link” in this section always means a kinematic root body.
Any descendants of that root can still be dynamic and are converted
normally.
At runtime, SolverMuJoCo keeps kinematic roots
user-prescribed rather than dynamically integrated:
When converting MuJoCo state back to Newton, the previous Newton
joint_qandjoint_qdvalues are passed through for kinematic roots instead of being overwritten from MuJoCo’s integratedqposandqvel.Applied body wrenches and joint forces targeting kinematic bodies are ignored on the MuJoCo side.
Kinematic bodies still participate in contacts, so they can act as moving or fixed obstacles for dynamic bodies.
During Newton-to-MuJoCo conversion (at
SolverMuJoCo construction), roots are mapped
by joint type:
Kinematic roots with non-fixed joints become ordinary MuJoCo joints with the same Newton joint type and DOFs, held by a weld constraint; see Kinematic welds.
Roots attached to world with a fixed joint become MuJoCo mocap bodies (whether kinematic or not). MuJoCo has no joint coordinates for a fixed root, so Newton drives the pose through
mjData.mocap_posandmjData.mocap_quatinstead. A D6 root with all axes locked (e.g. imported from a generic USDPhysicsJoint) is treated the same way.Massless kinematic roots also become mocap bodies and cannot be switched to dynamic. This applies when the root and the bodies attached to it by fixed joints together lack mass or inertia. Newton poses the mocap body from
joint_q, but MuJoCo treats its velocity as zero, so contacts and dynamic descendants respond to its pose but not to its prescribed velocity. Give the root mass and inertia when that coupling matters, for example for a conveyor that carries objects through friction.World-attached shapes that are not part of an articulation remain ordinary static MuJoCo geometry rather than mocap bodies.
If you edit joint_X_p or joint_X_c
for a fixed-root articulation after constructing the solver, call
notify_model_changed() with the
JOINT_PROPERTIES flag to
synchronize the updated fixed-root poses into MuJoCo.
Kinematic welds#
MuJoCo has no prescribed degrees of freedom. Its documented way to drive a
body that interacts physically is to weld it to a moving target (see
MoCap bodies).
SolverMuJoCo uses a variant of this: each kinematic
root keeps its joint and is held by a weld constraint to the world without
stiffness or damping. Before every step the weld is re-centered on the root’s
current pose, because MuJoCo’s weld adds acceleration away from its reference
that grows with the root’s velocity. The weld locks the root’s acceleration,
so through each step the root keeps the pose and velocity pushed from
joint_q and joint_qd. Constraints
and contacts treat the root as immovable, while the mass matrix stays physical
and the root keeps its authored joint_armature.
A weld keeps the root’s angular velocity, and the velocity of its joint origin,
constant through each step. For revolute, prismatic, ball, and free roots, and
for D6 roots with at most one angular axis, this is the same as keeping the
pushed joint velocities. A D6 root with two or three angular axes instead keeps
its body angular velocity, so its joint velocities drift within a step, by
about ω²·Δt for angular speed ω. Between sparse pushes (the deprecated
update_data_interval > 1), such a root coasts at constant body angular
velocity rather than at constant joint velocities. Newton still returns the
prescribed state, and each push resets the drift, but contacts and dynamic
descendants see the motion MuJoCo integrates.
The weld is resolved by MuJoCo’s constraint solver, so dynamic bodies attached
to a kinematic root by joints follow fixed-base dynamics only as closely as
the solver converges. The default Newton solver reproduces them closely. The
CG solver can stop before it resolves the weld, so dynamic descendants of a
kinematic root can drift noticeably from fixed-base motion; use
solver="newton" for kinematic roots that carry articulated dynamic bodies.
MuJoCo’s equality and constraint disable flags, set through MJCF
<flag equality="disable"/> or model.mujoco.flag_equality and
model.mujoco.flag_constraint, also turn these welds off. The solver
therefore raises ValueError for a kinematic root held by a weld while
either flag is disabled.
Switching kinematic roots at runtime#
MuJoCo cannot add constraints to a compiled model, so by default the solver
gives every movable root an inactive weld, and body_flags can switch
roots between kinematic and dynamic per world, followed by
notify_model_changed(ModelFlags.BODY_PROPERTIES). Inactive welds add no
constraint rows; roots made kinematic later share njmax with contacts.
Body-flag checks run on the host and are skipped for notifications replayed
from a CUDA graph.
With kinematic_switchable_roots=False, only roots that are kinematic in
some world at solver creation get a weld, so the compiled MuJoCo model has no
unused welds. To start such a root dynamic, mark it kinematic before creating
the solver and switch it right after:
from newton.solvers import SolverMuJoCo
builder = newton.ModelBuilder()
crate = builder.add_body(is_kinematic=True)
builder.add_shape_box(crate, hx=0.1, hy=0.1, hz=0.1)
model = builder.finalize()
solver = SolverMuJoCo(model, kinematic_switchable_roots=False)
model.body_flags.fill_(int(newton.BodyFlags.DYNAMIC))
solver.notify_model_changed(newton.ModelFlags.BODY_PROPERTIES)
# The crate can now be switched back to kinematic at any time.
Updating joint force properties#
Use JOINT_DOF_FORCE_PROPERTIES with
notify_model_changed() to publish joint
friction, damping, target gains/modes, effort limits, joint_stiffness, and
limit coefficients/bounds. This includes the MuJoCo solreffriction,
solimpfriction, limit_margin, solimplimit,
and solreflimit custom attributes. Optional attributes that are absent
retain their solver values. General MuJoCo actuator properties still use
ACTUATOR_PROPERTIES.
The force flag skips mass-constant recomputation, reference-pose updates, tendon-limit refreshes, and contact-cache invalidation. Joint-limit coefficients use the cached inverse weights. Compiled actuator length ranges are preserved, and pending tendon-limit edits are left unpublished. When sleeping is enabled, updated parameters wake all worlds. The MuJoCo Warp path supports CUDA graph capture; the MuJoCo CPU backend copies values to its host model and cannot be captured.
Use JOINT_DOF_INERTIAL_PROPERTIES for
joint_armature changes. Reference-pose changes, including
MuJoCo dof_ref and joint_rest_q, use
JOINT_REFERENCE_POSE_PROPERTIES. These paths recompute constants;
reference updates also shift limit ranges to the new reference. Both flags
are intended for reset-time or domain-randomization changes. Constant
recomputation is substantially more expensive than force updates, so avoid
using either flag every simulation step.
JOINT_PROPERTIES only publishes joint transforms and
axes, without recomputing constants or applying pending reference edits. Combine
flags with | when several categories change. The existing
JOINT_DOF_PROPERTIES flag retains its integer value
and full-update behavior, including force, armature, and reference properties.
Tendon-limit dependency: Notifications that recompute constants also refresh
tendon limits using the current model.mujoco limit modes, gains, raw
solref values, and ranges. Those pending edits are therefore published even
without TENDON_PROPERTIES. This includes joint
inertial/reference updates and the broad joint-DOF, body, body-inertial, and
actuator notifications. Publish tendon edits explicitly with
TENDON_PROPERTIES before these updates rather than
relying on them to preserve pending tendon-limit changes. Force-only joint
notifications do not recompute constants and leave tendon limits unchanged.
For example, actuator models with load-dependent friction can compute effective
budgets and publish them in the same graph as the simulation step. Given device
arrays friction_budget and damping_budget with one entry per Newton DOF:
with wp.ScopedCapture(device=model.device) as capture:
wp.copy(model.joint_friction, friction_budget)
wp.copy(model.joint_damping, damping_budget)
solver.notify_model_changed(newton.ModelFlags.JOINT_DOF_FORCE_PROPERTIES)
solver.step(state_in, state_out, control, contacts, dt)
The budget computation can precede these copies in the same graph. For an actuator controlling only some DOFs, scatter into those Newton model entries before notifying the solver; other entries retain their authored values. No MuJoCo DOF mapping or backend array access is needed.
The model arrays hold the effective total friction and damping. Publication replaces solver values rather than adding an actuator contribution to authored passive damping. Retain any authored baseline separately when combining contributions. Apply reset-time inertia and configuration changes first, then compute and publish the next step’s budgets. Full notifications also copy the current budgets. This API synchronizes existing runtime model arrays; it does not add actuator external-load feedback or authored USD properties.
Code pointers#
For readers navigating the source, the following symbols are the most useful entry points. Symbols with a leading underscore are internal entry points — stable enough to navigate to, but not part of the public API and subject to change.
register_custom_attributes()— authoritative registry of every MuJoCo-specific custom attribute and frequency.step()— per-step integration entry point.SolverMuJoCo._convert_to_mjc— NewtonModel(and optionalState) → MuJoComjModel/mjData(orchestrator).SolverMuJoCo._init_pairs/_init_actuators/_init_tendons— category-specific parsers that consume the MuJoCo custom attributes.SolverMuJoCo._apply_mjc_control,SolverMuJoCo._update_mjc_data, andSolverMuJoCo._update_newton_state— per-step control, data, and state sync between Newton and MuJoCo.SolverMuJoCo._populate_contact_observables— requested contact geometry and force export duringstep().update_contacts()— explicit geometry-only contact export.notify_model_changed()— re-synchronize MuJoCo state after editing the NewtonModel(e.g. fixed-root pose changes viajoint_X_p/joint_X_c).newton/_src/solvers/mujoco/kernels.py — Warp kernels for coordinate, contact, and state conversion (
quat_wxyz_to_xyzw,convert_mj_coords_to_warp_kernel,convert_newton_contacts_to_mjwarp_kernel,convert_solref, …).SchemaResolverMjc(newton/_src/usd/schemas.py) — USDmjc:*attribute → Newton built-in property mapping.