Skip to content

Fix locked D6 root base classification - #3792

Merged
eric-heiden merged 1 commit into
newton-physics:mainfrom
jcarius-nv:jcarius/fix-locked-d6-base
Aug 4, 2026
Merged

Fix locked D6 root base classification#3792
eric-heiden merged 1 commit into
newton-physics:mainfrom
jcarius-nv:jcarius/fix-locked-d6-base

Conversation

@jcarius-nv

@jcarius-nv jcarius-nv commented Aug 4, 2026

Copy link
Copy Markdown
Member

Description

Fixes #3727.

ArticulationView classified fixed bases solely from a root joint's JointType, so a fully locked, zero-DOF D6 root reported neither fixed nor floating. This caused downstream consumers to reserve six nonexistent base DOFs and select incorrect Jacobian columns.

Classify a root as fixed when its effective DOF count is zero. Keep floating-base classification restricted to FREE and DISTANCE roots, preserving their existing coordinate-layout assumptions.

Known limitation

ArticulationView already assumes selected articulations share one template, but its existing validation can allow heterogeneous root-DOF layouts and then expose metadata from the first articulation. This predates this PR; #3792 only corrects zero-DOF root classification for supported identical views. The validation gap is tracked separately in #3793.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes
  • CHANGELOG.md has been updated (if user-facing change)

Test plan

uv run --extra dev -m unittest newton.tests.test_selection
uvx --python 3.12 pre-commit run -a

Bug fix

Steps to reproduce:

  1. Build an articulation whose root is a D6 joint with no linear or angular axes.
  2. Construct an ArticulationView for it.
  3. Observe that is_fixed_base and is_floating_base are both False without this change.

Minimal reproduction:

import newton

builder = newton.ModelBuilder()
root = builder.add_link(label="root")
root_joint = builder.add_joint_d6(parent=-1, child=root)
builder.add_articulation([root_joint], label="robot")

model = builder.finalize(device="cpu")
view = newton.selection.ArticulationView(model, "robot")

assert view.is_fixed_base
assert not view.is_floating_base

Summary by CodeRabbit

  • Bug Fixes

    • Fixed root base classification for articulations with zero effective degrees of freedom, including fully constrained joints, which now correctly report as fixed-base.
  • Tests

    • Added regression test for root-base classification across different joint configurations.

Classify articulation roots from their effective DOF count so fully locked D6 roots report fixed-base semantics. Add focused selection coverage.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The fix changes how ArticulationView.is_fixed_base determines a fixed base. Instead of checking the root joint type against JointType.FIXED, it now computes the root joint's degree-of-freedom count and treats a zero count as fixed base, covering fully locked D6 joints.

Changes

Fixed-base DOF check

Layer / File(s) Summary
DOF-based fixed-base determination and test
newton/_src/utils/selection.py, newton/tests/test_selection.py, CHANGELOG.md
ArticulationView.__init__ computes root_joint_dof_count from model_joint_qd_start and sets is_fixed_base to True when this count is zero, replacing the root_joint_type == JointType.FIXED check. A new test verifies classification for fixed, zero-DOF D6, and free root joints. The changelog records the fix.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as test_root_base_classification_uses_dof_count
  participant View as ArticulationView.__init__
  participant Model as model_joint_qd_start

  Test->>View: construct with root joint (fixed/d6/free)
  View->>Model: read qd_start at root joint boundary
  Model-->>View: dof start indices
  View->>View: compute root_joint_dof_count
  View->>View: set is_fixed_base = (root_joint_dof_count == 0)
  View-->>Test: is_fixed_base, is_floating_base
Loading

Suggested reviewers: eric-heiden, adenzler-nvidia

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR addresses all requirements from issue #3727: locked D6 roots now report is_fixed_base=True, classification uses effective DOF count rather than joint type alone, and floating-base behavior for FREE/DISTANCE roots is preserved.
Out of Scope Changes check ✅ Passed All changes directly relate to the root-base classification fix: the bug fix in selection.py, regression test in test_selection.py, and CHANGELOG.md entry document the same scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing locked D6 root base classification, which is the core fix documented in the changelog and implemented in the code.
✨ 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.

@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/utils/selection.py`:
- Around line 757-759: The root_joint_dof_count is currently extracted only from
the first articulation (arti_0), but when multiple articulations are selected,
each root joint may have a different effective DOF count despite matching total
articulation DOFs and joint types. Since is_fixed_base is shared across all
selected articulations, this can cause incorrect classification. Update the code
to extract the root_joint_dof_count for each selected articulation and add a
validation check that all roots have identical DOF counts, incorporating this
check into the existing "Articulations are not identical" validation logic
alongside the existing joint type and total DOF comparisons. Also add a
regression test case that covers a mixed-root layout scenario where roots have
different DOF distributions.
🪄 Autofix

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 Plus

Run ID: 6240cae1-06f9-4343-b4b2-c2abe1d9aefc

📥 Commits

Reviewing files that changed from the base of the PR and between 0efb72d and a418e1d.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • newton/_src/utils/selection.py
  • newton/tests/test_selection.py

Comment thread newton/_src/utils/selection.py
@codecov

codecov Bot commented Aug 4, 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!

@jcarius-nv
jcarius-nv requested a review from eric-heiden August 4, 2026 15:31

@eric-heiden eric-heiden 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.

Thanks, LGTM!

@eric-heiden
eric-heiden added this pull request to the merge queue Aug 4, 2026
Merged via the queue into newton-physics:main with commit fc2ed00 Aug 4, 2026
32 checks passed
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.

ArticulationView: a fully-locked D6 root reports neither fixed nor floating base

2 participants