# MJX spatial tendon内部sidesite导致jax.grad返回NaN

> 原文链接：https://robotics.hellobike.com/pitfalls/2026-10-19-mujoco-3696
> 频道：pitfalls | 更新日期：2026-10-19 | 标签：auto, github-issue, mujoco
> 核心摘要：MJX中spatial tendon的sidesite位于wrap geom内部时梯度为NaN，需对Newton迭代及反三角函数输入增加数值安全钳位与条件替换。

# MJX spatial tendon内部sidesite导致jax.grad返回NaN

::: v-pre
> 本文由 AI 根据公开内容整理，可能有误，请以原文为准：[[MJX] jax.grad returns NaN through a spatial tendon with an inside-sidesite geom wrap: wrap_inside's Newton iterate leaves arcsin's domain and the NaN survives the jp.where](https://github.com/google-deepmind/mujoco/issues/3696)（GitHub google-deepmind/mujoco #3696）

**状态**：有绕过办法

## 问题

在MuJoCo MJX中，当spatial tendon的geom wrap包含位于包裹几何体内部的sidesite时，`jax.grad`计算`ten_length`梯度静默返回NaN（前向值正确）。根因是`wrap_inside`的Newton迭代使`arcsin`参数超出定义域，且`support.wrap`中圆柱校正的`sqrt(0)`导数无穷大，以及退化姿态下`acos(±1)`不可微，导致自动微分失败。

## 环境

MuJoCo/MJX 3.16.0, JAX 0.11.2, macOS arm64 CPU, float32精度

## 解决办法

1. 在`support.wrap_inside`的Newton更新后添加`z_next = jp.clip(z_next, -1.0 + 1e-7, 1.0 - 1e-7)`防止`arcsin`越界。
2. 将`support.wrap`中的`jp.sqrt`替换为`math.norm`以处理零向量处的无限导数问题。
3. 在调用`jp.arccos(cosG)`前，针对float32精度定义安全掩码：`no_wrap2 = (cosG < -1 + mjMINVAL) | (cosG <= -1)`与`early_return0 = (cosG > 1 - mjMINVAL) | (cosG >= 1)`。
4. 合并所有提前退出条件`skip = no_wrap0 | no_wrap1 | no_wrap2 | early_return0`。
5. 使用`jp.where(skip, safe_val, original_val)`对`A`、`B`（替换为0.5）及`cosG`（替…

讨论原作者：@adam-hartshorne 等，版权归原作者所有。
:::

## 原始参考来源 (Sources)

- [GitHub google-deepmind/mujoco #3696：[MJX] jax.grad returns NaN through a spatial tendon with an inside-sidesite geom wrap: wrap_inside's Newton iterate leaves arcsin's domain and the NaN survives the jp.where](https://github.com/google-deepmind/mujoco/issues/3696)