Skip to content

Fix MJX NaN Issue in Tendon Moment Calculations#3028

Open
Adityakk9031 wants to merge 1 commit intogoogle-deepmind:mainfrom
Adityakk9031:#2932
Open

Fix MJX NaN Issue in Tendon Moment Calculations#3028
Adityakk9031 wants to merge 1 commit intogoogle-deepmind:mainfrom
Adityakk9031:#2932

Conversation

@Adityakk9031
Copy link

Fixes #2932

Issue
MJX produces NaNs on the very first mjx.step() for models with spatial tendons, while native MuJoCo remains stable. The issue occurs when tendon wrap points are very close or coincident at initialization, causing division by near-zero values.

Root Cause
In
mjx/mujoco/mjx/_src/smooth.py
, the
_length_moment
function computes tendon segment lengths and moments. When the distance between consecutive tendon points is extremely small:

math.safe_div(dif, length) can still produce NaN values
These NaNs propagate through the tendon Jacobian (ten_J)
The constraint solver then propagates NaNs to qacc, and subsequently to
qpos
/
qvel
Solution
Applied a multi-layered fix to
_length_moment
function (lines 910-938):

Denominator Clamping: Replace math.safe_div(dif, length) with dif / jp.maximum(length, mujoco.mjMINVAL) to ensure we never divide by values smaller than the minimum threshold

Degenerate Case Handling: Explicitly track when length < mujoco.mjMINVAL and set moment to zero for these cases

Enhanced Condition: Use jp.logical_or(is_degenerate, body0 == body1) to zero out moments for both degenerate segments and same-body segments

NaN Sanitization: Add conservative guard jp.where(jp.isnan(moment), jp.zeros(m.nv), moment) to catch any remaining numerical issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MJX with a minimal quadruped-leg model: step produces NaN while MuJoCo native is stable

1 participant