Skip to content

Fix ball joint conversion for SolverMuJoCo - #2981

Merged
camevor merged 14 commits into
newton-physics:mainfrom
camevor:fix-ball-conversion-mj
Jun 8, 2026
Merged

Fix ball joint conversion for SolverMuJoCo#2981
camevor merged 14 commits into
newton-physics:mainfrom
camevor:fix-ball-conversion-mj

Conversation

@camevor

@camevor camevor commented May 28, 2026

Copy link
Copy Markdown
Member

Description

Fix SolverMuJoCo ball-joint conversion under non-identity child_xform rotation. MuJoCo's ball qvel/qfrc live in the post-qpos child body frame, not the rest-body frame, so the four bridge kernels (convert_{mj_coords_to_warp,warp_coords_to_mj}_kernel, apply_mjc_qfrc_kernel, convert_qfrc_actuator_from_mj_kernel) now compose joint_X_c.q with the current ball joint_q (r = X_cj.q^{-1} * qpos * X_cj.q and duals). Newton's body_q/body_qd and applied/actuator torques now round-trip through MuJoCo for arbitrary ball poses.

Folded in while touching these kernels:

  • apply_mjc_qfrc_kernel was reading joint_type / joint_dof_dim at the per-world template index instead of the global joint index — silent on homogeneous worlds, wrong on heterogeneous multi-world models.
  • Added the KINEMATIC-child early-return to convert_qfrc_actuator_from_mj_kernel BALL to match apply_mjc_qfrc_kernel.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes
  • CHANGELOG.md has been updated

Test plan

uv run --extra dev -m newton.tests -k test_mujoco_solver

New tests in TestMuJoCoArticulationConversion covering FK, qvel, applied torque (identity and non-identity joint_q), and the actuator readback branch. Each fails without the corresponding fix. Full suite: 202 pass / 7 skipped.

Bug fix

Steps to reproduce:

  1. Build a SolverMuJoCo model with a ball joint whose child_xform has a non-identity rotation.
  2. Set non-identity joint_qd (and optionally joint_q), step, or call eval_fk.
  3. Compare Newton's body_qd against mujoco.mj_objectVelocity — they diverge for any rotation that does not commute with child_xform.q.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed ball-joint conversions so position, velocity, and applied/actuator torques are correctly transformed when a joint’s child anchor has a non‑identity rotation; actuator targets are now rotated into the solver’s expected child-frame.
  • Tests

    • Added tests validating ball-joint kinematics, applied-torque behavior, actuator readback, and controller targets for rotated child anchors.

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Ball-joint MuJoCo↔Newton conversions and actuator mappings were fixed to use per-joint child-frame quaternion conjugation: kernels now accept joint child transforms, solver export/wiring threads per-actuator child-anchor bases, and tests were added for rotated child_xform cases.

Changes

MuJoCo ball-joint frame-rotation alignment

Layer / File(s) Summary
Changelog entry
CHANGELOG.md
Adds an Unreleased → Fixed bullet documenting the SolverMuJoCo ball-joint frame-conversion fix for non-identity child_xform and non-rest ball poses.
MuJoCo→Newton coordinate conversion
newton/_src/solvers/mujoco/kernels.py
convert_mj_coords_to_warp_kernel accepts joint_X_c and rewrites BALL position/velocity mappings to conjugate MuJoCo child quaternion into Newton anchor-frame (joint_q) and rotate angular velocity accordingly.
Newton→MuJoCo coordinate conversion
newton/_src/solvers/mujoco/kernels.py
convert_warp_coords_to_mj_kernel accepts joint_X_c and updates BALL inverse mapping to reconstruct MuJoCo child quaternion and rotate Newton angular velocity into MuJoCo child-frame qvel.
Control target handling (BALL)
newton/_src/solvers/mujoco/kernels.py, newton/_src/solvers/mujoco/solver_mujoco.py
apply_mjc_control_kernel gains per-actuator BALL-joint indexing, joint_X_c, and joint_q; position targets are converted to axis-angle and rotated by per-joint q_cj, velocity targets are rotated via q_cj * r^{-1} before writing to MuJoCo controls.
Applied torque mapping
newton/_src/solvers/mujoco/kernels.py
apply_mjc_qfrc_kernel signature adds joint_q and joint_X_c; per-joint bookkeeping updated and BALL branch now conjugates Newton-side torques into MuJoCo child-frame qfrc_applied.
Actuator force conversion
newton/_src/solvers/mujoco/kernels.py
convert_qfrc_actuator_from_mj_kernel adds joint_X_c; BALL actuator branch maps MuJoCo qpos to Newton representation and rotates MuJoCo child-frame actuator torques into Newton parent-anchor DOFs.
Solver wiring & actuator export
newton/_src/solvers/mujoco/solver_mujoco.py
Solver and export logic updated to pass state.joint_q, model.joint_q_start, model.joint_X_c, model.body_flags, compute coords_per_world, and build self.mjc_actuator_to_newton_ball_jnt per-actuator mapping (or None when unused).
Tests
newton/tests/*
Adds rotated-child-anchor tests: FK correctness, applied-torque mapping, actuator readback for qfrc_actuator, and a rotated-anchor coord-layout joint-controller test; adds import math.

Sequence Diagram(s)

sequenceDiagram
  participant SolverMuJoCo
  participant convert_mj_coords_to_warp_kernel
  participant apply_mjc_control_kernel
  participant apply_mjc_qfrc_kernel
  participant convert_qfrc_actuator_from_mj_kernel
  participant NewtonState

  SolverMuJoCo->>convert_mj_coords_to_warp_kernel: mj state, joint_X_c -> joint_q/joint_qd (conjugated)
  SolverMuJoCo->>apply_mjc_control_kernel: actuator targets, mjc_actuator_to_newton_ball_jnt, joint_X_c, joint_q -> mj child-frame targets
  apply_mjc_control_kernel->>apply_mjc_qfrc_kernel: joint_q, joint_X_c, qfrc_applied
  apply_mjc_qfrc_kernel->>convert_qfrc_actuator_from_mj_kernel: mj_data.qfrc_actuator, joint_X_c
  convert_qfrc_actuator_from_mj_kernel->>NewtonState: qfrc_actuator (rotated into Newton DOFs)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • newton-physics/newton#2474: Modifies convert_qfrc_actuator_from_mj_kernel and joint/indexing logic; related to actuator/force mapping edits in this PR.
  • newton-physics/newton#2332: Touches convert_warp_coords_to_mj_kernel joint lookup/indexing logic; related kernel-level changes.

Suggested reviewers

  • adenzler-nvidia
  • eric-heiden
  • vreutskyy
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix ball joint conversion for SolverMuJoCo' clearly and accurately summarizes the main objective of the changeset: fixing ball-joint coordinate and force conversions in the SolverMuJoCo component for cases with non-identity child transforms.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
newton/_src/solvers/mujoco/kernels.py (1)

226-226: ⚡ Quick win

Use inline code literals for private _src symbols.

These :func: references point at private helper/kernel symbols in _src, so they can become unresolved Sphinx targets. Prefer inline code literals here instead of cross-references.

Based on learnings, avoid Sphinx cross-references (:func:) to private helpers that are not re-exported as public API; use inline code literals instead.

Also applies to: 2715-2717

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/kernels.py` at line 226, Update the docstring to
avoid Sphinx cross-reference to a private helper by replacing the
:func:`ball_rotate_mj_to_newton` cross-reference with an inline code literal
``ball_rotate_mj_to_newton`` (and similarly change any other occurrences around
lines referenced, e.g., the other two places at 2715-2717) so the docstring
reads like: "Inverse of ``ball_rotate_mj_to_newton``; ``r`` is the Newton-side
ball joint quaternion." Ensure you only change the docstring text and keep the
existing backticks for inline code.
newton/tests/test_mujoco_solver.py (1)

7496-7586: ⚡ Quick win

Cover the kinematic-child BALL readback branch too.

This new regression only exercises dynamic children, but the PR also changes convert_qfrc_actuator_from_mj_kernel to early-return for kinematic children. Add one is_kinematic=True variant here and assert the Newton-side mujoco:qfrc_actuator stays zero so that branch cannot regress untested.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/tests/test_mujoco_solver.py` around lines 7496 - 7586, Add a subcase
that makes the child link kinematic and verifies kinematic readback stays zero:
when building the model, add a second child link with is_kinematic=True (use the
same call site of builder.add_link that created "child") or set the existing
child to is_kinematic=True for that subtest; then run the same sync/update
sequence (solver._update_mjc_data and solver._update_newton_state) and assert
that state.mujoco.qfrc_actuator[qd_start:qd_start+3] is all zeros for that
kinematic case so the early-return in convert_qfrc_actuator_from_mj_kernel is
exercised and cannot regress.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@newton/_src/solvers/mujoco/kernels.py`:
- Line 226: Update the docstring to avoid Sphinx cross-reference to a private
helper by replacing the :func:`ball_rotate_mj_to_newton` cross-reference with an
inline code literal ``ball_rotate_mj_to_newton`` (and similarly change any other
occurrences around lines referenced, e.g., the other two places at 2715-2717) so
the docstring reads like: "Inverse of ``ball_rotate_mj_to_newton``; ``r`` is the
Newton-side ball joint quaternion." Ensure you only change the docstring text
and keep the existing backticks for inline code.

In `@newton/tests/test_mujoco_solver.py`:
- Around line 7496-7586: Add a subcase that makes the child link kinematic and
verifies kinematic readback stays zero: when building the model, add a second
child link with is_kinematic=True (use the same call site of builder.add_link
that created "child") or set the existing child to is_kinematic=True for that
subtest; then run the same sync/update sequence (solver._update_mjc_data and
solver._update_newton_state) and assert that
state.mujoco.qfrc_actuator[qd_start:qd_start+3] is all zeros for that kinematic
case so the early-return in convert_qfrc_actuator_from_mj_kernel is exercised
and cannot regress.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: fd361b7c-d1c2-4429-8cbf-66f857ec4bb0

📥 Commits

Reviewing files that changed from the base of the PR and between 636da30 and 5f5a203.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_mujoco_solver.py

@codecov

codecov Bot commented May 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@adenzler-nvidia

Copy link
Copy Markdown
Member

Comment verbosity

Each BALL branch in kernels.py independently re-derives the same two facts — r = X_cj⁻¹ · q_mj · X_cj and "MuJoCo qvel/qfrc live in the post-qpos child body frame" — that the new ball_rotate_* helpers already encode in their names. Suggest hosting the derivation once in the helper docstrings and trimming each call site to a one-liner that names the frame.

Spots that read as restatement rather than load-bearing context:

  • convert_mj_coords_to_warp_kernel BALL qpos (the "Other joint types (D6/REVOLUTE/PRISMATIC) absorb X_cj.rot..." paragraph): this is about _convert_to_mjc axis pre-rotation, not the BALL branch itself. It belongs over there, with one line here: # BALL has no axis hook to absorb X_cj.rot, so we conjugate explicitly.
  • Both qvel comment blocks (mj→warp and warp→mj): the mju_quatIntegrate citation is load-bearing (justifies "current child body frame"). The "simplifies to..." sentence is restatement — the named q_inv_cj_q_mj local and the ball_rotate_newton_to_mj call already carry it.
  • apply_mjc_qfrc_kernel BALL and convert_qfrc_actuator_from_mj_kernel BALL: keep "forces are dual to velocities" (load-bearing), drop the frame preamble.

The test docstrings have the same pattern. The non-_with_joint_q tests re-narrate the full bridge math, but their actual purpose is regression coverage for the common identity-joint_q path — that's worth saying in one sentence. The _with_joint_q variants are the ones that earn their length because they carry the "this test exists because the simpler variant cannot detect a missing r⁻¹" rationale.

Ambiguous notation

Two of the comments use X_cj.rot⁻¹ * q_mj where the code is wp.quat_rotate(q_inv_cj_q_mj, vec), i.e. a rotation acting on a vector — not a quaternion product. Reads as ambiguous since the surrounding text mixes quaternion products and rotated-vector results.

  • convert_mj_coords_to_warp_kernel BALL qvel: "Equating world omegas gives w = X_cj.rot⁻¹ * qpos * qvel, which simplifies to X_cj.rot⁻¹ * q_mj since..." → suggest w = R(X_cj.rot⁻¹ · q_mj) · omega_mj.
  • convert_qfrc_actuator_from_mj_kernel BALL: "The Newton-side rotation is r * X_cj.rot⁻¹, which simplifies to X_cj.rot⁻¹ * q_mj..." → suggest tau = R(X_cj.rot⁻¹ · q_mj) · tau_mj (dual of apply_mjc_qfrc_kernel BALL).

The other two blocks already use the R(·) · v convention.

@camevor
camevor marked this pull request as ready for review June 1, 2026 16:54
Comment thread newton/_src/solvers/mujoco/kernels.py
@camevor
camevor force-pushed the fix-ball-conversion-mj branch from 1d22ed9 to e957a0f Compare June 2, 2026 18:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
newton/_src/solvers/mujoco/solver_mujoco.py (3)

5218-5225: ⚡ Quick win

Fail fast on parented free joints instead of warning and continuing.

This configuration is already known to be invalid for MuJoCo, so letting it reach spec.compile() just moves the error farther from the source joint.

Suggested change
-                if parent != -1:
-                    warnings.warn(
-                        f"Free joint '{model.joint_label[j]}' has parent body {parent} instead of the world (-1). "
-                        "SolverMuJoCo requires free joints to attach directly to the world; "
-                        "MuJoCo will reject this model at compile time.",
-                        UserWarning,
-                        stacklevel=2,
-                    )
+                if parent != -1:
+                    raise ValueError(
+                        f"Free joint '{model.joint_label[j]}' must attach directly to the world (-1); "
+                        f"got parent body {parent}."
+                    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 5218 - 5225, The
current code in SolverMuJoCo emits a warning when a free joint (checked where
model.joint_label[j] is accessed) has parent != -1, but MuJoCo treats that as
invalid and will fail at spec.compile(); change this to fail fast by raising a
clear exception (e.g., ValueError or RuntimeError) instead of warnings.warn so
the invalid joint configuration is reported immediately (include the joint label
and parent in the exception message) in the same location where parent != -1 is
checked.

2818-2828: ⚡ Quick win

Sync _init_actuators()'s Args: block with the new signature.

The docstring still skips the newly added target-q lookup and child-anchor quaternion parameters, so it no longer matches the callable surface.

As per coding guidelines, "Follow Google-style docstrings. Types in annotations, not docstrings. Use Args: with name: description format".

Also applies to: 2841-2854

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 2818 - 2828, Update
the _init_actuators() docstring Args: section to match the current function
signature by adding entries (name: brief description) for
mjc_actuator_to_target_q_idx_list, mjc_actuator_to_target_q_axis_idx_list, and
mjc_actuator_q_cj_list (child-anchor quaternion tuple), and ensure existing
entries reflect the annotated types (mjc_actuator_ctrl_source_list,
mjc_actuator_to_newton_idx_list, dof_to_mjc_joint, mjc_joint_names,
selected_tendons, mjc_tendon_names, body_name_mapping, site_mapping). Make the
changes in both the Args block starting at the _init_actuators() docstring and
the duplicate block referenced around lines 2841-2854 so the docstring fully
matches the callable surface and follows the "name: description" Google-style
format.

358-360: ⚡ Quick win

Use explicit public Sphinx targets here.

These references are less robust than the surrounding ~newton... style and are likely to render as unresolved or ambiguous in generated docs. Prefer explicit public paths such as :attr:\~newton.Model.use_coord_layout_targets`, :attr:`~newton.Control.joint_target_q`, and :attr:`~newton.Model.joint_target_q_start``.

As per coding guidelines, "Use Sphinx cross-references (:class:, :meth:) with shortest possible targets. Prefer public API paths; never use newton._src in docstring references".

Also applies to: 3245-3250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 358 - 360, Update
the docstring references to use explicit public Sphinx targets: replace
ambiguous references in the JOINT_TARGET paragraph to use
:attr:`~newton.Model.use_coord_layout_targets`,
:attr:`~newton.Control.joint_target_q`, :attr:`~newton.Control.joint_target_qd`
(and the deprecated aliases as
:attr:`~newton.Control.joint_target_pos`/:attr:`~newton.Control.joint_target_vel`
if needed), and any start/index constants such as
:attr:`~newton.Model.joint_target_q_start`; ensure all cross-references use the
shortest public API paths (no _src) and mirror the surrounding `~newton...`
style so Sphinx resolves them reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 700-730: This change introduces new user-facing attributes
mujoco.solref and mujoco.solref_mode (created via ModelBuilder.CustomAttribute
with name="solref" and name="solref_mode"), so add a dedicated entry under the
[Unreleased] section of CHANGELOG.md recording the new shape-level controls (use
an "Added" or "Changed" heading), mention the attribute names and default
behavior (SOLREF_MODE_MJCF_DEFAULT and the wp.vec2 default), and reference the
USD/MJCF mapping (mjc:solref / solref) so users know how to opt into force-space
scaling.

---

Nitpick comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 5218-5225: The current code in SolverMuJoCo emits a warning when a
free joint (checked where model.joint_label[j] is accessed) has parent != -1,
but MuJoCo treats that as invalid and will fail at spec.compile(); change this
to fail fast by raising a clear exception (e.g., ValueError or RuntimeError)
instead of warnings.warn so the invalid joint configuration is reported
immediately (include the joint label and parent in the exception message) in the
same location where parent != -1 is checked.
- Around line 2818-2828: Update the _init_actuators() docstring Args: section to
match the current function signature by adding entries (name: brief description)
for mjc_actuator_to_target_q_idx_list, mjc_actuator_to_target_q_axis_idx_list,
and mjc_actuator_q_cj_list (child-anchor quaternion tuple), and ensure existing
entries reflect the annotated types (mjc_actuator_ctrl_source_list,
mjc_actuator_to_newton_idx_list, dof_to_mjc_joint, mjc_joint_names,
selected_tendons, mjc_tendon_names, body_name_mapping, site_mapping). Make the
changes in both the Args block starting at the _init_actuators() docstring and
the duplicate block referenced around lines 2841-2854 so the docstring fully
matches the callable surface and follows the "name: description" Google-style
format.
- Around line 358-360: Update the docstring references to use explicit public
Sphinx targets: replace ambiguous references in the JOINT_TARGET paragraph to
use :attr:`~newton.Model.use_coord_layout_targets`,
:attr:`~newton.Control.joint_target_q`, :attr:`~newton.Control.joint_target_qd`
(and the deprecated aliases as
:attr:`~newton.Control.joint_target_pos`/:attr:`~newton.Control.joint_target_vel`
if needed), and any start/index constants such as
:attr:`~newton.Model.joint_target_q_start`; ensure all cross-references use the
shortest public API paths (no _src) and mirror the surrounding `~newton...`
style so Sphinx resolves them reliably.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 67895d15-ebe7-4779-aae4-3a7cf6f28efd

📥 Commits

Reviewing files that changed from the base of the PR and between 1d22ed9 and e957a0f.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • CHANGELOG.md
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/kernels.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🧹 Nitpick comments (3)
newton/_src/solvers/mujoco/solver_mujoco.py (3)

5218-5225: ⚡ Quick win

Fail fast on parented free joints instead of warning and continuing.

This configuration is already known to be invalid for MuJoCo, so letting it reach spec.compile() just moves the error farther from the source joint.

Suggested change
-                if parent != -1:
-                    warnings.warn(
-                        f"Free joint '{model.joint_label[j]}' has parent body {parent} instead of the world (-1). "
-                        "SolverMuJoCo requires free joints to attach directly to the world; "
-                        "MuJoCo will reject this model at compile time.",
-                        UserWarning,
-                        stacklevel=2,
-                    )
+                if parent != -1:
+                    raise ValueError(
+                        f"Free joint '{model.joint_label[j]}' must attach directly to the world (-1); "
+                        f"got parent body {parent}."
+                    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 5218 - 5225, The
current code in SolverMuJoCo emits a warning when a free joint (checked where
model.joint_label[j] is accessed) has parent != -1, but MuJoCo treats that as
invalid and will fail at spec.compile(); change this to fail fast by raising a
clear exception (e.g., ValueError or RuntimeError) instead of warnings.warn so
the invalid joint configuration is reported immediately (include the joint label
and parent in the exception message) in the same location where parent != -1 is
checked.

2818-2828: ⚡ Quick win

Sync _init_actuators()'s Args: block with the new signature.

The docstring still skips the newly added target-q lookup and child-anchor quaternion parameters, so it no longer matches the callable surface.

As per coding guidelines, "Follow Google-style docstrings. Types in annotations, not docstrings. Use Args: with name: description format".

Also applies to: 2841-2854

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 2818 - 2828, Update
the _init_actuators() docstring Args: section to match the current function
signature by adding entries (name: brief description) for
mjc_actuator_to_target_q_idx_list, mjc_actuator_to_target_q_axis_idx_list, and
mjc_actuator_q_cj_list (child-anchor quaternion tuple), and ensure existing
entries reflect the annotated types (mjc_actuator_ctrl_source_list,
mjc_actuator_to_newton_idx_list, dof_to_mjc_joint, mjc_joint_names,
selected_tendons, mjc_tendon_names, body_name_mapping, site_mapping). Make the
changes in both the Args block starting at the _init_actuators() docstring and
the duplicate block referenced around lines 2841-2854 so the docstring fully
matches the callable surface and follows the "name: description" Google-style
format.

358-360: ⚡ Quick win

Use explicit public Sphinx targets here.

These references are less robust than the surrounding ~newton... style and are likely to render as unresolved or ambiguous in generated docs. Prefer explicit public paths such as :attr:\~newton.Model.use_coord_layout_targets`, :attr:`~newton.Control.joint_target_q`, and :attr:`~newton.Model.joint_target_q_start``.

As per coding guidelines, "Use Sphinx cross-references (:class:, :meth:) with shortest possible targets. Prefer public API paths; never use newton._src in docstring references".

Also applies to: 3245-3250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 358 - 360, Update
the docstring references to use explicit public Sphinx targets: replace
ambiguous references in the JOINT_TARGET paragraph to use
:attr:`~newton.Model.use_coord_layout_targets`,
:attr:`~newton.Control.joint_target_q`, :attr:`~newton.Control.joint_target_qd`
(and the deprecated aliases as
:attr:`~newton.Control.joint_target_pos`/:attr:`~newton.Control.joint_target_vel`
if needed), and any start/index constants such as
:attr:`~newton.Model.joint_target_q_start`; ensure all cross-references use the
shortest public API paths (no _src) and mirror the surrounding `~newton...`
style so Sphinx resolves them reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 700-730: This change introduces new user-facing attributes
mujoco.solref and mujoco.solref_mode (created via ModelBuilder.CustomAttribute
with name="solref" and name="solref_mode"), so add a dedicated entry under the
[Unreleased] section of CHANGELOG.md recording the new shape-level controls (use
an "Added" or "Changed" heading), mention the attribute names and default
behavior (SOLREF_MODE_MJCF_DEFAULT and the wp.vec2 default), and reference the
USD/MJCF mapping (mjc:solref / solref) so users know how to opt into force-space
scaling.

---

Nitpick comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 5218-5225: The current code in SolverMuJoCo emits a warning when a
free joint (checked where model.joint_label[j] is accessed) has parent != -1,
but MuJoCo treats that as invalid and will fail at spec.compile(); change this
to fail fast by raising a clear exception (e.g., ValueError or RuntimeError)
instead of warnings.warn so the invalid joint configuration is reported
immediately (include the joint label and parent in the exception message) in the
same location where parent != -1 is checked.
- Around line 2818-2828: Update the _init_actuators() docstring Args: section to
match the current function signature by adding entries (name: brief description)
for mjc_actuator_to_target_q_idx_list, mjc_actuator_to_target_q_axis_idx_list,
and mjc_actuator_q_cj_list (child-anchor quaternion tuple), and ensure existing
entries reflect the annotated types (mjc_actuator_ctrl_source_list,
mjc_actuator_to_newton_idx_list, dof_to_mjc_joint, mjc_joint_names,
selected_tendons, mjc_tendon_names, body_name_mapping, site_mapping). Make the
changes in both the Args block starting at the _init_actuators() docstring and
the duplicate block referenced around lines 2841-2854 so the docstring fully
matches the callable surface and follows the "name: description" Google-style
format.
- Around line 358-360: Update the docstring references to use explicit public
Sphinx targets: replace ambiguous references in the JOINT_TARGET paragraph to
use :attr:`~newton.Model.use_coord_layout_targets`,
:attr:`~newton.Control.joint_target_q`, :attr:`~newton.Control.joint_target_qd`
(and the deprecated aliases as
:attr:`~newton.Control.joint_target_pos`/:attr:`~newton.Control.joint_target_vel`
if needed), and any start/index constants such as
:attr:`~newton.Model.joint_target_q_start`; ensure all cross-references use the
shortest public API paths (no _src) and mirror the surrounding `~newton...`
style so Sphinx resolves them reliably.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 67895d15-ebe7-4779-aae4-3a7cf6f28efd

📥 Commits

Reviewing files that changed from the base of the PR and between 1d22ed9 and e957a0f.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • CHANGELOG.md
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/kernels.py
🛑 Comments failed to post (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)

700-730: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a separate [Unreleased] changelog entry for the new shape contact attributes.

This introduces user-facing mujoco.solref / mujoco.solref_mode behavior, but the referenced changelog content only covers the ball-joint frame-conversion fix. Please add a dedicated Added or Changed entry for these shape-level controls.

As per coding guidelines, "**: Check that any user-facing change includes a corresponding entry in CHANGELOG.md under the [Unreleased] section."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 700 - 730, This
change introduces new user-facing attributes mujoco.solref and
mujoco.solref_mode (created via ModelBuilder.CustomAttribute with name="solref"
and name="solref_mode"), so add a dedicated entry under the [Unreleased] section
of CHANGELOG.md recording the new shape-level controls (use an "Added" or
"Changed" heading), mention the attribute names and default behavior
(SOLREF_MODE_MJCF_DEFAULT and the wp.vec2 default), and reference the USD/MJCF
mapping (mjc:solref / solref) so users know how to opt into force-space scaling.

@camevor camevor added this to the 1.3 Release milestone Jun 4, 2026
Comment thread newton/_src/solvers/mujoco/kernels.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 133-140: The code uses 0.0 as a sentinel for "unset" which makes
an explicit Model.joint_damping[dof] = 0.0 get overwritten by
mujoco.dof_passive_damping; change the logic to track authored/unset state
instead of numeric sentinel: ensure the producer of canonical_value returns None
(or expose an authored flag) when the canonical joint damping was not explicitly
set, then replace the check "if canonical_value != 0.0 and not
math.isclose(canonical_value, alias_value...)" with "if canonical_value is not
None and not math.isclose(...)" (or check the authored flag) so explicit zeros
are treated as real values; keep the rest of the flow that initializes
updated_joint_damping and assigns updated_joint_damping[damping_index] =
alias_value only when canonical_value is None (unset), and preserve use of
builder.joint_damping and variables damping_index, alias_value,
updated_joint_damping, canonical_value, Model.mujoco.dof_passive_damping, and
Model.joint_damping to locate where to change this behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bf7def88-cef3-44aa-938b-c2f072a64eff

📥 Commits

Reviewing files that changed from the base of the PR and between e957a0f and 35e8bd8.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/kernels.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 133-140: The code uses 0.0 as a sentinel for "unset" which makes
an explicit Model.joint_damping[dof] = 0.0 get overwritten by
mujoco.dof_passive_damping; change the logic to track authored/unset state
instead of numeric sentinel: ensure the producer of canonical_value returns None
(or expose an authored flag) when the canonical joint damping was not explicitly
set, then replace the check "if canonical_value != 0.0 and not
math.isclose(canonical_value, alias_value...)" with "if canonical_value is not
None and not math.isclose(...)" (or check the authored flag) so explicit zeros
are treated as real values; keep the rest of the flow that initializes
updated_joint_damping and assigns updated_joint_damping[damping_index] =
alias_value only when canonical_value is None (unset), and preserve use of
builder.joint_damping and variables damping_index, alias_value,
updated_joint_damping, canonical_value, Model.mujoco.dof_passive_damping, and
Model.joint_damping to locate where to change this behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bf7def88-cef3-44aa-938b-c2f072a64eff

📥 Commits

Reviewing files that changed from the base of the PR and between e957a0f and 35e8bd8.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • newton/tests/test_joint_controllers.py
  • newton/tests/test_mujoco_solver.py
  • newton/_src/solvers/mujoco/kernels.py
🛑 Comments failed to post (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)

133-140: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't use 0.0 as the “canonical unset” sentinel.

An explicit Model.joint_damping[dof] = 0.0 currently loses to a conflicting deprecated mujoco.dof_passive_damping value, because the conflict branch only runs when canonical_value != 0.0. That silently exports the alias value instead of the user's canonical setting. This needs authored/assigned-state tracking rather than a numeric sentinel.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 133 - 140, The code
uses 0.0 as a sentinel for "unset" which makes an explicit
Model.joint_damping[dof] = 0.0 get overwritten by mujoco.dof_passive_damping;
change the logic to track authored/unset state instead of numeric sentinel:
ensure the producer of canonical_value returns None (or expose an authored flag)
when the canonical joint damping was not explicitly set, then replace the check
"if canonical_value != 0.0 and not math.isclose(canonical_value,
alias_value...)" with "if canonical_value is not None and not math.isclose(...)"
(or check the authored flag) so explicit zeros are treated as real values; keep
the rest of the flow that initializes updated_joint_damping and assigns
updated_joint_damping[damping_index] = alias_value only when canonical_value is
None (unset), and preserve use of builder.joint_damping and variables
damping_index, alias_value, updated_joint_damping, canonical_value,
Model.mujoco.dof_passive_damping, and Model.joint_damping to locate where to
change this behavior.

Comment thread newton/_src/solvers/mujoco/solver_mujoco.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
newton/_src/solvers/mujoco/solver_mujoco.py (1)

4886-4891: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard equality-attribute access behind the existing None-safe path.

Line 4890 and the related ranges directly dereference model.mujoco... even though this codepath now explicitly supports non-standard model assembly via None-safe equality reads. Those direct accesses can still raise AttributeError before the fallback logic is reached.

💡 Suggested fix
-            selected_constraints = np.arange(model.mujoco.equality_constraint_count, dtype=np.int32)
+            eq_constraint_count = int(len(eq_constraint_world)) if eq_constraint_world is not None else 0
+            selected_constraints = np.arange(eq_constraint_count, dtype=np.int32)
...
-            eq_constraints_per_world = model.mujoco.equality_constraint_count // model.world_count
+            eq_constraints_per_world = eq_constraint_count // model.world_count if model.world_count > 0 else 0
-        if self.model.mujoco.equality_constraint_count == 0:
+        mujoco_attrs = getattr(self.model, "mujoco", None)
+        eq_constraint_count = int(getattr(mujoco_attrs, "equality_constraint_count", 0))
+        if eq_constraint_count == 0:
             return
-        eq_constraint_world = (
-            model.mujoco.equality_constraint_world.numpy()
-            if model.mujoco.equality_constraint_count > 0
-            else np.empty(0, dtype=np.int32)
-        )
+        mujoco_attrs = getattr(model, "mujoco", None)
+        eq_constraint_count = int(getattr(mujoco_attrs, "equality_constraint_count", 0))
+        eq_constraint_world_attr = getattr(mujoco_attrs, "equality_constraint_world", None)
+        eq_constraint_world = (
+            eq_constraint_world_attr.numpy()
+            if eq_constraint_world_attr is not None and eq_constraint_count > 0
+            else np.empty(0, dtype=np.int32)
+        )

Also applies to: 6261-6261, 6984-6990, 7598-7599, 7850-7854, 7954-7956

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 4886 - 4891, The
code directly dereferences model.mujoco (e.g., when computing
selected_constraints and selected_mimic_constraints) which can raise
AttributeError; instead obtain a None-safe reference like mj = getattr(model,
"mujoco", None) and use getattr(mj, "<attr>", 0) (or appropriate default) for
equality_constraint_count and any other mujoco attributes, then build
selected_constraints/selected_mimic_constraints from those safe counts; apply
the same pattern to the other occurrences referenced (around the symbols
producing selected_constraints, selected_mimic_constraints and any direct
model.mujoco.* uses at the other listed locations).
🧹 Nitpick comments (2)
newton/_src/solvers/mujoco/kernels.py (1)

668-670: 💤 Low value

Clarify rotation-vs-multiplication notation in comment.

The expression w_newton = (q_cj^{-1} * qpos) * w_mj could be read as quaternion multiplication, but the operation is vector rotation. Consider using explicit notation like R(q_cj^{-1} * q_mj) · ω_mj to distinguish quaternion composition from rotating a vector. This aligns with the reviewer feedback requesting R(·) · v notation for clarity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/kernels.py` around lines 668 - 670, Update the
explanatory comment around q_cj, qpos, w_newton, and w_mj to make clear the
operation is a vector rotation rather than quaternion multiplication: replace
the ambiguous expression `w_newton = (q_cj^{-1} * qpos) * w_mj` with an explicit
rotation notation such as `w_newton = R(q_cj^{-1} * qpos) · w_mj` (or equivalent
R(...)·ω_mj), and optionally clarify that `r = q_cj^{-1} * qpos * q_cj` denotes
quaternion similarity while R(...) denotes the rotation matrix/operator applied
to the angular velocity vector.
newton/_src/solvers/mujoco/solver_mujoco.py (1)

4777-4779: ⚡ Quick win

Consolidate repeated inline rationale comments.

The same “shape-stable empty arrays / non-standard pipeline robustness” explanation is repeated in multiple places. Keep one concise canonical comment and trim duplicates to reduce noise.

As per coding guidelines, **/*.py: “Flag inline code comments ... that repeat the same point in multiple places. Comments should be brief and reserved for non-obvious code.”

Also applies to: 6988-6990, 7848-7850

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@newton/_src/solvers/mujoco/solver_mujoco.py` around lines 4777 - 4779,
Consolidate the repeated inline rationale about “shape-stable empty arrays /
non-standard pipeline robustness” into a single concise canonical comment next
to the None-safe helper call that reads the per-row equality arrays (keep a
short note mentioning that finalize() materializes shape-stable empty arrays and
the None-safe path preserves robustness for models missing the custom-attribute
pipeline). Remove the duplicate explanatory comments at the other occurrences
(the similar blocks around the other None-safe helper usages you pointed out) so
only the one canonical comment remains; keep any local, non-redundant comments
that are specific to the surrounding code logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 4886-4891: The code directly dereferences model.mujoco (e.g., when
computing selected_constraints and selected_mimic_constraints) which can raise
AttributeError; instead obtain a None-safe reference like mj = getattr(model,
"mujoco", None) and use getattr(mj, "<attr>", 0) (or appropriate default) for
equality_constraint_count and any other mujoco attributes, then build
selected_constraints/selected_mimic_constraints from those safe counts; apply
the same pattern to the other occurrences referenced (around the symbols
producing selected_constraints, selected_mimic_constraints and any direct
model.mujoco.* uses at the other listed locations).

---

Nitpick comments:
In `@newton/_src/solvers/mujoco/kernels.py`:
- Around line 668-670: Update the explanatory comment around q_cj, qpos,
w_newton, and w_mj to make clear the operation is a vector rotation rather than
quaternion multiplication: replace the ambiguous expression `w_newton =
(q_cj^{-1} * qpos) * w_mj` with an explicit rotation notation such as `w_newton
= R(q_cj^{-1} * qpos) · w_mj` (or equivalent R(...)·ω_mj), and optionally
clarify that `r = q_cj^{-1} * qpos * q_cj` denotes quaternion similarity while
R(...) denotes the rotation matrix/operator applied to the angular velocity
vector.

In `@newton/_src/solvers/mujoco/solver_mujoco.py`:
- Around line 4777-4779: Consolidate the repeated inline rationale about
“shape-stable empty arrays / non-standard pipeline robustness” into a single
concise canonical comment next to the None-safe helper call that reads the
per-row equality arrays (keep a short note mentioning that finalize()
materializes shape-stable empty arrays and the None-safe path preserves
robustness for models missing the custom-attribute pipeline). Remove the
duplicate explanatory comments at the other occurrences (the similar blocks
around the other None-safe helper usages you pointed out) so only the one
canonical comment remains; keep any local, non-redundant comments that are
specific to the surrounding code logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b2c8e2c6-71de-4eaa-b933-d7cf792176de

📥 Commits

Reviewing files that changed from the base of the PR and between 35e8bd8 and a48cc6c.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • newton/_src/solvers/mujoco/kernels.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/tests/test_mujoco_solver.py
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • newton/tests/test_mujoco_solver.py

@adenzler-nvidia adenzler-nvidia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few documentation and cleanup notes on the ball-joint conversion path — all non-blocking. The frame-conversion math and the actuator wiring look correct to me; these are just about a redundant debug assert, a stale comment, and two docstring/comment wording fixes. Details inline.

Comment thread newton/_src/solvers/mujoco/kernels.py
Comment thread newton/_src/solvers/mujoco/kernels.py Outdated
Comment thread newton/_src/solvers/mujoco/kernels.py Outdated
Comment thread newton/_src/solvers/mujoco/solver_mujoco.py Outdated
@camevor

camevor commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

Thanks for the review, @adenzler-nvidia! Fixed the remaining items (except for the assert). Reasoning:
The assert documents and trips an invariant, not a bounds check that is expected trigger occasionally. The return still protects the following indexed reads in environments/modes where the assert is not fatal.

@camevor
camevor enabled auto-merge June 8, 2026 09:53
@camevor
camevor added this pull request to the merge queue Jun 8, 2026
Merged via the queue into newton-physics:main with commit f62a4e8 Jun 8, 2026
25 checks passed
@camevor
camevor deleted the fix-ball-conversion-mj branch June 8, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants