Summary
39e44588 ("Update USD support in MuJoCo to Newton USD schemas v0.4.0", unreleased — it sits above the Version 3.11.0 heading in doc/changelog.rst) introduces four defects in the new newton: read paths. Two are angle-unit conversions that are simply missing; the third maps a distance-valued attribute onto a force-valued field; the fourth silently ignores an attribute that controls whether a constraint is active at all.
I wrote the original adoption in #3156, so some of this is my mess to begin with — flagging it now while the change is still unreleased and cheap to correct.
Schema references below are newton-usd-schemas v0.4.0, the version src/experimental/usd/CMakeLists.txt now pins.
1. newton:mimicCoef0 is authored in degrees, read as radians
The schema declares angle-valued units:
newton:mimicCoef0 — "Offset added after scaling the leader joint's position/angle. […] Units: distance or degrees (matches the joint type for single-DOF joints)"
plugin/usd_decoder/usd_decoder.cc:2166-2172 assigns it straight into mjEQ_JOINT data[0], which is radians for hinge and ball joints:
if (newton_coef0 && newton_coef0.HasAuthoredValue()) {
float val;
newton_coef0.Get(&val);
eq->data[0] = val; // no degrees -> radians conversion
}
For an angular follower the offset is therefore wrong by a factor of 180/π ≈ 57.3.
Two details make this bite harder than the others:
- The
newton: attribute takes precedence over mjc:coef0 here, so authoring the deprecated attribute is not a workaround.
mujoco-usd-converter writes newton:mimicCoef0 with an explicit np.degrees() for hinge/ball followers and does not author mjc:coef0 at all, so there is no fallback path for assets it produces.
Newton hit the identical bug on its own importer and fixed it in newton-physics/newton#3728.
newton:mimicCoef1 is declared dimensionless and is correctly read as-is.
2. newton:damping is authored per-degree, read per-radian
newton:damping — "Units: effort * seconds / degrees (angular DOFs) or effort * seconds / distance (linear DOFs)"
usd_decoder.cc:1832-1836:
} else if (newton_damping_authored) {
float damping;
newton_damping_attr.Get(&damping);
mj_joint->damping[0] = damping; // per-degree value into a per-radian field
}
mjsJoint::damping is per-radian for angular DOFs, so this needs a ×180/π on hinge and ball joints.
This one is currently masked: precedence in ParseMjcPhysicsJointAPI is the opposite of the mimic case — mjc:damping wins when both are authored — so producers that write both (as the converter does) still get correct behaviour today, with a deprecation warning. It becomes a silent 57.3× under-damping the moment mjc:damping is removed, which the changelog states is the plan.
newton:armature (mass · distance²) and newton:friction (effort) carry no per-angle term and are correctly read as-is.
3. newton:contactAdhesion is a distance, geom.adhesion is a force
These are different physical quantities:
|
definition |
units |
newton:contactAdhesion |
"Contact adhesion distance. When two surfaces are within this distance, an attractive force pulls them together." |
distance |
mjsGeom::adhesion (XMLreference) |
"Adhesive force of contacts with this geom, in units of force." |
force |
usd_decoder.cc:1920-1929 assigns one to the other:
// Contact adhesion: newton:contactAdhesion -> geom->adhesion
if (val >= 0.0f) {
geom->adhesion = val;
}
Newton's own implementation agrees with its schema — Model.shape_material_ka is documented as "Shape contact adhesion distance [m]". So a value authored as metres of interaction range is consumed as newtons of pull-off force, and no scalar conversion can reconcile the two.
Notably, MuJoCo already documents the correct target for the distance concept, in the adhesion entry itself:
"To let adhesion act across a small separation (attraction at a distance), set gap to the desired interaction range. This can be used to model magnets."
which suggests newton:contactAdhesion → geom.gap, and that MJCF's force-valued adhesion has no generic equivalent in the Newton schema at all.
4. newton:mimicEnabled is never read, and physics:jointEnabled is not a substitute
NewtonMimicAPI has four members. Three are read; newton:mimicEnabled does not appear in plugin/usd_decoder/newton_tokens.h at all, and is not referenced anywhere under plugin/ or src/.
eq->active is instead derived from a different attribute entirely (usd_decoder.cc:2094-2097):
void ParseJointEnabled(mjsEquality* eq, const pxr::UsdPhysicsJoint& joint) {
bool jointEnabled = true;
joint.GetJointEnabledAttr().Get(&jointEnabled);
eq->active = jointEnabled ? 1 : 0;
}
These control different things:
physics:jointEnabled (UsdPhysics) — whether the joint is enabled.
newton:mimicEnabled — whether the mimic constraint is active. Per the schema: "When disabled, the follower joint moves independently, as though the mimic constraint was not applied."
So the natural authoring of "an ordinary, enabled joint whose mimic coupling is switched off" — physics:jointEnabled = true with newton:mimicEnabled = false — yields an active equality constraint in MuJoCo, silently coupling two joints the author explicitly decoupled. There is no diagnostic, since the attribute is never inspected.
This currently goes unnoticed for mujoco-usd-converter output only because that producer happens to author both attributes from the same source flag; any producer writing NewtonMimicAPI alone hits it.
Secondary: inconsistent mjc: vs newton: precedence
Where both spellings exist, the two code paths disagree about which wins:
ParseMjcPhysicsJointAPI (usd_decoder.cc:1812-1849) — deprecated mjc: wins, newton: is the fallback.
- The mimic path (
usd_decoder.cc:2166-2178) — newton: wins, deprecated mjc: is the fallback.
Whichever is intended, having both makes migration behaviour hard to reason about: for joint gains a producer must drop mjc: to get the new path, and for mimic coefficients it must drop newton: to avoid it.
Environment
Observed by reading gdm/main at 4929f2cd; 39e44588 is not in a tagged release. Cross-checked against mujoco-usd-converter 0.5.0 (pinned mujoco>=3.11.0,<3.12) and newton-usd-schemas v0.4.0.
Summary
39e44588("Update USD support in MuJoCo to Newton USD schemas v0.4.0", unreleased — it sits above theVersion 3.11.0heading indoc/changelog.rst) introduces four defects in the newnewton:read paths. Two are angle-unit conversions that are simply missing; the third maps a distance-valued attribute onto a force-valued field; the fourth silently ignores an attribute that controls whether a constraint is active at all.I wrote the original adoption in #3156, so some of this is my mess to begin with — flagging it now while the change is still unreleased and cheap to correct.
Schema references below are newton-usd-schemas v0.4.0, the version
src/experimental/usd/CMakeLists.txtnow pins.1.
newton:mimicCoef0is authored in degrees, read as radiansThe schema declares angle-valued units:
plugin/usd_decoder/usd_decoder.cc:2166-2172assigns it straight intomjEQ_JOINTdata[0], which is radians for hinge and ball joints:For an angular follower the offset is therefore wrong by a factor of 180/π ≈ 57.3.
Two details make this bite harder than the others:
newton:attribute takes precedence overmjc:coef0here, so authoring the deprecated attribute is not a workaround.mujoco-usd-converterwritesnewton:mimicCoef0with an explicitnp.degrees()for hinge/ball followers and does not authormjc:coef0at all, so there is no fallback path for assets it produces.Newton hit the identical bug on its own importer and fixed it in newton-physics/newton#3728.
newton:mimicCoef1is declared dimensionless and is correctly read as-is.2.
newton:dampingis authored per-degree, read per-radianusd_decoder.cc:1832-1836:mjsJoint::dampingis per-radian for angular DOFs, so this needs a ×180/π on hinge and ball joints.This one is currently masked: precedence in
ParseMjcPhysicsJointAPIis the opposite of the mimic case —mjc:dampingwins when both are authored — so producers that write both (as the converter does) still get correct behaviour today, with a deprecation warning. It becomes a silent 57.3× under-damping the momentmjc:dampingis removed, which the changelog states is the plan.newton:armature(mass · distance²) andnewton:friction(effort) carry no per-angle term and are correctly read as-is.3.
newton:contactAdhesionis a distance,geom.adhesionis a forceThese are different physical quantities:
newton:contactAdhesionmjsGeom::adhesion(XMLreference)usd_decoder.cc:1920-1929assigns one to the other:Newton's own implementation agrees with its schema —
Model.shape_material_kais documented as "Shape contact adhesion distance [m]". So a value authored as metres of interaction range is consumed as newtons of pull-off force, and no scalar conversion can reconcile the two.Notably, MuJoCo already documents the correct target for the distance concept, in the
adhesionentry itself:which suggests
newton:contactAdhesion→geom.gap, and that MJCF's force-valuedadhesionhas no generic equivalent in the Newton schema at all.4.
newton:mimicEnabledis never read, andphysics:jointEnabledis not a substituteNewtonMimicAPIhas four members. Three are read;newton:mimicEnableddoes not appear inplugin/usd_decoder/newton_tokens.hat all, and is not referenced anywhere underplugin/orsrc/.eq->activeis instead derived from a different attribute entirely (usd_decoder.cc:2094-2097):These control different things:
physics:jointEnabled(UsdPhysics) — whether the joint is enabled.newton:mimicEnabled— whether the mimic constraint is active. Per the schema: "When disabled, the follower joint moves independently, as though the mimic constraint was not applied."So the natural authoring of "an ordinary, enabled joint whose mimic coupling is switched off" —
physics:jointEnabled = truewithnewton:mimicEnabled = false— yields an active equality constraint in MuJoCo, silently coupling two joints the author explicitly decoupled. There is no diagnostic, since the attribute is never inspected.This currently goes unnoticed for
mujoco-usd-converteroutput only because that producer happens to author both attributes from the same source flag; any producer writingNewtonMimicAPIalone hits it.Secondary: inconsistent
mjc:vsnewton:precedenceWhere both spellings exist, the two code paths disagree about which wins:
ParseMjcPhysicsJointAPI(usd_decoder.cc:1812-1849) — deprecatedmjc:wins,newton:is the fallback.usd_decoder.cc:2166-2178) —newton:wins, deprecatedmjc:is the fallback.Whichever is intended, having both makes migration behaviour hard to reason about: for joint gains a producer must drop
mjc:to get the new path, and for mimic coefficients it must dropnewton:to avoid it.Environment
Observed by reading
gdm/mainat4929f2cd;39e44588is not in a tagged release. Cross-checked againstmujoco-usd-converter0.5.0 (pinnedmujoco>=3.11.0,<3.12) and newton-usd-schemas v0.4.0.