Skip to content

[Fix] Apply rigid-body and mass properties to every link of nested-hierarchy assets#6377

Merged
hujc7 merged 2 commits into
isaac-sim:developfrom
hujc7:jichuanh/apply-nested-rigid-props
Jul 17, 2026
Merged

[Fix] Apply rigid-body and mass properties to every link of nested-hierarchy assets#6377
hujc7 merged 2 commits into
isaac-sim:developfrom
hujc7:jichuanh/apply-nested-rigid-props

Conversation

@hujc7

@hujc7 hujc7 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Description

Spawning an asset whose rigid bodies are nested (child link prims authored under their parent link prim, as produced by the URDF importer in Isaac Sim 6.0 and later) only applied rigid_props and mass_props to the first link: the apply_nested decorator stops descending into a prim's children once the wrapped function succeeds, assuming physics schemas cannot nest. On a 29-link arm, disable_gravity=True reached 1/29 bodies with no warning.

This completes the nested-hierarchy fix started in #6259 (which covered contact-sensor activation):

  • apply_nested gains a stop_on_success flag (default True; the dual-form decorator keeps every existing bare @apply_nested usage working unchanged).
  • modify_rigid_body_properties and modify_mass_properties opt out of the early stop, since their anchor prims are exactly the link prims that nest.
  • Regression test with a 3-deep nested rigid-body chain verifying both properties land on every body (mirrors the Fix contact sensor activation for nested rigid bodies #6259 test).

Scope: why only the rigid-body and mass writers

An audit of the 40 asset stages referenced by isaaclab_assets/isaaclab_tasks informed the scoping:

  1. Rigid-body nesting is the only independent-anchor nesting in use: ShadowHandNewton authors 24 of its 25 links body-under-body and is spawned with rigid_props by the shadow-hand task — this fix is required for those values to reach every link.
  2. No joint-under-joint nesting and no nested articulation roots exist in any audited asset; keeping the early stop for those writers is safe.
  3. Collider-under-collider exists only as duplicated same-intent anchors in a few props (e.g. the factory gear assets author CollisionAPI with SDF approximation on two ancestor Xforms of the same meshes, via layer composition). Those anchors describe the same geometry rather than independent colliders — the USD Physics spec ties CollisionAPI to leaf gprims, so nested Xform-level anchors have no defined precedence. Widening the traversal there would paper over an asset-level duplication instead of fixing schema application, so the collision writers keep the early stop; the asset duplication is being followed up separately.
  4. Some flat assets (e.g. Franka) author MassAPI on both link prims and mesh prims beneath them. With this change mass_props now also authors the nested MassAPI prims; per the USD Physics spec, a parent's explicit mass overrides mass properties authored further down the subtree, so effective per-body mass is unchanged.

Behavior note

The Newton shadow-hand task cfg sets disable_gravity=True (and related rigid-body properties) that previously reached only 1 of 25 links. With this fix the cfg applies to all 25 links as intended. This is the bug being fixed, but baselines tuned against the old (partial) behavior may shift for tasks whose assets have nested links.

Verification

  • End-to-end through the spawner (UsdFileCfg → the same property-application path UrdfFileCfg uses) on a nested Geometry-scoped 3-link chain: disable_gravity and mass author on 1/3 bodies before the fix and 3/3 after; contact-report API 3/3 on both (via Fix contact sensor activation for nested rigid bodies #6259).
  • New regression test in test_schemas.py (nested chain, asserts both properties on every link).
  • Full CI green (34/34 checks).

Fixes #5918

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump extension.toml — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

The apply_nested decorator stops descending into a prim's children
once the wrapped function succeeds, assuming physics schemas cannot
nest. The URDF importer in Isaac Sim 6.0+ authors child link prims
under their parent link prim, so rigid-body and mass properties were
only applied to the first link of such assets.

Add a stop_on_success flag to the decorator (default True, keeping
the existing behavior) and disable it for the rigid-body and mass
modifiers so every nested link is visited. Closes isaac-sim/IsaacLab
issue 5918 together with the earlier contact-sensor fix (PR 6259).
@github-actions github-actions Bot added the isaac-lab Related to Isaac Lab team label Jul 7, 2026
@hujc7
hujc7 marked this pull request as ready for review July 7, 2026 01:43
@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where modify_rigid_body_properties and modify_mass_properties only applied to the first rigid body in an asset with a nested link hierarchy (e.g., from the Isaac Sim 6.0 URDF importer), silently leaving the remaining links untouched.

  • Extends apply_nested to accept a stop_on_success flag (default True, preserving all existing callers) and converts the function into a dual-use decorator that works both as @apply_nested and @apply_nested(stop_on_success=...).
  • Decorates modify_rigid_body_properties and modify_mass_properties with @apply_nested(stop_on_success=False) so the BFS traversal continues into child prims after a successful application, reaching every nested link prim.
  • Adds a regression test with a 3-deep nested rigid-body chain verifying both disable_gravity and physics:mass are authored on all three nodes.

Confidence Score: 5/5

Safe to merge — a focused, well-contained bug fix that adds backward-compatible behavior to a single decorator utility.

The dual-use decorator pattern (func=None sentinel + keyword-only stop_on_success) is the standard Python idiom and is implemented correctly. All existing @apply_nested call-sites receive stop_on_success=True with no behavioral change. The two opt-out functions are the only ones where nested schemas legitimately occur, and the test directly validates the fix on a 3-deep chain.

No files require special attention; all changes are tightly scoped to the decorator utility and the two schema functions that need nested traversal.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/sim/utils/prims.py Refactors apply_nested into a dual-use decorator supporting both @apply_nested and @apply_nested(stop_on_success=...). The implementation correctly uses the func=None sentinel pattern with a keyword-only stop_on_success argument and preserves all existing call-sites.
source/isaaclab/isaaclab/sim/schemas/schemas.py Changes modify_rigid_body_properties and modify_mass_properties decorators from bare @apply_nested to @apply_nested(stop_on_success=False) so the traversal continues into child prims after a successful application, reaching all nested rigid-body link prims.
source/isaaclab/test/sim/test_schemas.py Adds test_modify_rigid_body_and_mass_properties_nested_rigid_bodies covering a 3-deep nested rigid-body chain; directly validates the fix by asserting both disableGravity and physics:mass land on every node.
source/isaaclab/changelog.d/apply-nested-rigid-props.minor.rst New changelog fragment correctly describes both the stop_on_success addition and the nested rigid-body/mass fix.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["apply_nested called"] --> B{func is None?}
    B -- "No (bare @apply_nested)" --> C["decorator(func) → wrapper\nstop_on_success=True"]
    B -- "Yes (@apply_nested(stop_on_success=...))" --> D["return decorator"]
    D --> E["decorator(func) → wrapper\nstop_on_success=False or True"]
    C --> W
    E --> W
    subgraph W["wrapper execution"]
        W1["BFS over prim subtree"] --> W2["Call func on each prim"]
        W2 --> W3{success?}
        W3 -- "False" --> W4["Add children to queue"]
        W3 -- "True" --> W5{stop_on_success?}
        W5 -- "True (default)" --> W6["Skip children"]
        W5 -- "False (rigid/mass props)" --> W4
        W4 --> W1
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["apply_nested called"] --> B{func is None?}
    B -- "No (bare @apply_nested)" --> C["decorator(func) → wrapper\nstop_on_success=True"]
    B -- "Yes (@apply_nested(stop_on_success=...))" --> D["return decorator"]
    D --> E["decorator(func) → wrapper\nstop_on_success=False or True"]
    C --> W
    E --> W
    subgraph W["wrapper execution"]
        W1["BFS over prim subtree"] --> W2["Call func on each prim"]
        W2 --> W3{success?}
        W3 -- "False" --> W4["Add children to queue"]
        W3 -- "True" --> W5{stop_on_success?}
        W5 -- "True (default)" --> W6["Skip children"]
        W5 -- "False (rigid/mass props)" --> W4
        W4 --> W1
    end
Loading

Reviews (1): Last reviewed commit: "Fix apply_nested skipping nested rigid b..." | Re-trigger Greptile

@AntoineRichard

AntoineRichard commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

AI-generated review comment:

Important — prims.py:561: The new configured decorator form returns a bare Callable, losing the decorated function’s signature and failing to enforce its required boolean return. Use ParamSpec with overloads for bare and configured forms, and type the wrapper’s actual None return.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There is the AI comment otherwise LGTM

The configured decorator form returned a bare Callable, losing the
decorated function's signature and dropping the required boolean
return contract of wrapped functions.

Add ParamSpec-based overloads for the bare and configured forms so
decorated functions keep their exact signature and type as returning
None, matching the wrapper's actual return. Enforce the bool contract
on wrapped functions and make bind_visual_material conform: it
returned None when Kit is absent and an untyped value otherwise.
@hujc7
hujc7 merged commit 10144da into isaac-sim:develop Jul 17, 2026
97 of 102 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Isaac Lab Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants