Skip to content

Commit 965c091

Browse files
Fix Newton self-collisions being uncontrolled via the deprecated PhysX cfg (#7164)
## Summary - `ArticulationRootPropertiesCfg`/`PhysxArticulationRootPropertiesCfg.enabled_self_collisions` only authored `physxArticulation:enabledSelfCollisions`. Newton's schema resolver checks `newton:selfCollisionEnabled` first and only falls back to the PhysX attribute when it's unauthored, so the deprecated cfg's setting silently never reached Newton simulations. - `modify_articulation_root_properties` now mirrors `enabled_self_collisions` onto `newton:selfCollisionEnabled` (applying `NewtonArticulationRootAPI`) whenever it's set, so the deprecated cfg controls self-collisions on both backends. - Migrated `ALLEGRO_HAND_CFG`, `SHADOW_HAND_CFG`, `SHADOW_HAND_NEWTON_CFG`, and `KUKA_ALLEGRO_CFG` off the deprecated cfg to explicit `PhysxArticulationCfg` + `NewtonArticulationCfg` fragments. Several of the reorientation/handover tasks built on these hands (`Isaac-Reorient-Cube-Allegro*`, `Isaac-Reorient-Cube-Shadow-Direct*`, `Isaac-Shadow-Handover-Direct`) default to the `newton_mjwarp` preset, so this was a real training-time gap, not just a hypothetical one. - Adds `isaaclab_physx`/`isaaclab_newton` as declared dependencies of `isaaclab_assets` (needed for the fragment imports above). ## Test plan - [x] `test_physx_articulation_root_writes_self_collisions` extended to assert `newton:selfCollisionEnabled` / `NewtonArticulationRootAPI` are authored; confirmed it fails without the fix and passes with it. - [x] `source/isaaclab/test/sim/test_schemas.py` (43 tests) and `test_articulation_fragments.py` (26 tests) pass. - [x] `source/isaaclab_assets` test suite passes (`test_asset_configs` loads all three migrated robot configs). - [x] `test_initialization_hand_with_tendons` (Shadow Hand, PhysX backend) passes with the fragment-based `articulation_props`. - [x] `uv run isaaclab -f` passes (formatting, changelog fragments). --------- Co-authored-by: Kelly Guo <kellyg@nvidia.com>
1 parent 470dce0 commit 965c091

11 files changed

Lines changed: 143 additions & 28 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed the deprecated :class:`~isaaclab_physx.sim.schemas.ArticulationRootPropertiesCfg` /
5+
:class:`~isaaclab_physx.sim.schemas.PhysxArticulationRootPropertiesCfg` ``enabled_self_collisions``
6+
field silently no-oping under Newton. The legacy writer only authored
7+
``physxArticulation:enabledSelfCollisions`` (via ``PhysxArticulationAPI``); Newton's schema
8+
resolver checks the native ``newton:selfCollisionEnabled`` attribute first and only falls back to
9+
the PhysX one when it is unauthored, so the value never reached Newton simulations.
10+
:meth:`~isaaclab.sim.schemas.modify_articulation_root_properties` now also mirrors
11+
``enabled_self_collisions`` onto ``newton:selfCollisionEnabled`` (applying
12+
``NewtonArticulationRootAPI``), so the deprecated cfg controls self-collisions on both backends.
13+
The mirror is authored after root-link relocation so ``fix_root_link=True`` leaves a single
14+
articulation root.
15+
* Fixed ``./isaaclab.sh -i`` and the CI Docker install failing with ``No matching distribution
16+
found for isaaclab_physx`` because ``CORE_ISAACLAB_SUBMODULES`` installed ``isaaclab_assets``
17+
before ``isaaclab_newton``/``isaaclab_physx``, which it now depends on. Reordered the submodule
18+
list so the backend packages install first.

source/isaaclab/isaaclab/cli/commands/install.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -662,17 +662,18 @@ def _install_isaacsim() -> None:
662662
# Source directories installed on every ./isaaclab.sh -i invocation (even "core").
663663
# Order must respect inter-package dependencies (topological sort):
664664
# isaaclab first, then ppisp (no inter-package deps, precedes renderer backends),
665-
# then contrib (needed by assets), then assets, then tasks (needed by rl),
666-
# then rl. Packages with only an isaaclab dep can go anywhere after isaaclab.
665+
# then contrib and the backend packages newton/physx (needed by assets), then
666+
# assets, then tasks (needed by rl), then rl. Packages with only an isaaclab
667+
# dep can go anywhere after isaaclab.
667668
CORE_ISAACLAB_SUBMODULES: list[str] = [
668669
"isaaclab",
669670
"isaaclab_ppisp",
670671
"isaaclab_contrib",
672+
"isaaclab_newton",
673+
"isaaclab_physx",
671674
"isaaclab_assets",
672675
"isaaclab_experimental",
673-
"isaaclab_newton",
674676
"isaaclab_ov",
675-
"isaaclab_physx",
676677
"isaaclab_tasks",
677678
"isaaclab_tasks_experimental",
678679
"isaaclab_rl",

source/isaaclab/isaaclab/sim/schemas/schemas.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,41 @@ def modify_articulation_root_properties(
582582
if not parent_attr:
583583
parent_attr = parent_prim.CreateAttribute(aname, attr.GetTypeName())
584584
parent_attr.Set(attr.Get())
585+
# -- Newton root schema and its authored properties
586+
newton_root_schema = "NewtonArticulationRootAPI"
587+
if newton_root_schema in articulation_prim.GetAppliedSchemas():
588+
if not parent_prim.AddAppliedSchema(newton_root_schema):
589+
raise RuntimeError(f"Failed to apply '{newton_root_schema}' to '{parent_prim.GetPath()}'.")
590+
schema_definition = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(newton_root_schema)
591+
newton_properties = []
592+
if schema_definition is not None:
593+
for property_name in schema_definition.GetPropertyNames():
594+
prop = articulation_prim.GetProperty(property_name)
595+
if prop and prop.IsAuthored():
596+
newton_properties.append(prop)
597+
for prop in newton_properties:
598+
if not prop.FlattenTo(parent_prim):
599+
raise RuntimeError(f"Failed to move '{prop.GetPath()}' to '{parent_prim.GetPath()}'.")
600+
for prop in newton_properties:
601+
if not articulation_prim.RemoveProperty(prop.GetName()):
602+
raise RuntimeError(f"Failed to remove '{prop.GetPath()}' from the former articulation root.")
603+
if not articulation_prim.RemoveAppliedSchema(newton_root_schema):
604+
raise RuntimeError(f"Failed to remove '{newton_root_schema}' from '{articulation_prim.GetPath()}'.")
585605

586606
# remove api from root
587607
articulation_prim.RemoveAppliedSchema("PhysxArticulationAPI")
588608
articulation_prim.RemoveAPI(UsdPhysics.ArticulationRootAPI)
609+
articulation_prim = parent_prim
610+
611+
# Mirror after any root relocation so the Newton API does not recreate an articulation root
612+
# on the former root link.
613+
enabled_self_collisions = cfg_dict.get("enabled_self_collisions")
614+
if enabled_self_collisions is not None:
615+
if "NewtonArticulationRootAPI" not in articulation_prim.GetAppliedSchemas():
616+
articulation_prim.AddAppliedSchema("NewtonArticulationRootAPI")
617+
safe_set_attribute_on_usd_prim(
618+
articulation_prim, "newton:selfCollisionEnabled", enabled_self_collisions, camel_case=False
619+
)
589620

590621
# success
591622
return True

source/isaaclab/test/sim/test_schemas.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,8 @@ def test_articulation_root_base_no_physx_schema_when_only_fix_root_link_set(setu
506506

507507
@pytest.mark.isaacsim_ci
508508
def test_physx_articulation_root_writes_self_collisions(setup_simulation):
509-
"""Setting ``enabled_self_collisions`` on ``PhysxArticulationRootPropertiesCfg`` must
510-
author ``physxArticulation:enabledSelfCollisions`` AND apply ``PhysxArticulationAPI``."""
509+
"""Setting ``enabled_self_collisions`` on ``PhysxArticulationRootPropertiesCfg`` must author
510+
``physxArticulation:enabledSelfCollisions`` and mirror onto ``newton:selfCollisionEnabled``."""
511511
sim, _, _, _, _, _ = setup_simulation
512512
stage = sim_utils.get_current_stage()
513513

@@ -517,8 +517,35 @@ def test_physx_articulation_root_writes_self_collisions(setup_simulation):
517517

518518
prim = stage.GetPrimAtPath("/World/arti_sc")
519519
assert prim.GetAttribute("physxArticulation:enabledSelfCollisions").Get() is True
520+
assert prim.GetAttribute("newton:selfCollisionEnabled").Get() is True
520521
applied = prim.GetAppliedSchemas()
521522
assert "PhysxArticulationAPI" in applied
523+
assert "NewtonArticulationRootAPI" in applied
524+
525+
526+
@pytest.mark.isaacsim_ci
527+
def test_physx_articulation_root_self_collisions_follow_fixed_root(setup_simulation):
528+
"""Mirrored Newton self-collision properties must follow a relocated articulation root."""
529+
sim, _, _, _, _, _ = setup_simulation
530+
stage = sim_utils.get_current_stage()
531+
532+
parent = sim_utils.create_prim("/World/arti_fixed", prim_type="Xform")
533+
child = sim_utils.create_prim("/World/arti_fixed/base", prim_type="Cube")
534+
UsdPhysics.RigidBodyAPI.Apply(child)
535+
UsdPhysics.ArticulationRootAPI.Apply(child)
536+
child.AddAppliedSchema("NewtonArticulationRootAPI")
537+
child.GetAttribute("newton:selfCollisionEnabled").Set(False)
538+
539+
cfg = PhysxArticulationRootPropertiesCfg(enabled_self_collisions=True, fix_root_link=True)
540+
schemas.modify_articulation_root_properties(child.GetPath(), cfg)
541+
542+
roots = [prim for prim in stage.Traverse() if prim.HasAPI(UsdPhysics.ArticulationRootAPI)]
543+
assert roots == [parent]
544+
assert parent.GetAttribute("physxArticulation:enabledSelfCollisions").Get() is True
545+
assert parent.GetAttribute("newton:selfCollisionEnabled").Get() is True
546+
assert "NewtonArticulationRootAPI" in parent.GetAppliedSchemas()
547+
assert "NewtonArticulationRootAPI" not in child.GetAppliedSchemas()
548+
assert not child.GetAttribute("newton:selfCollisionEnabled").HasAuthoredValue()
522549

523550

524551
@pytest.mark.isaacsim_ci
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed self-collisions being uncontrolled under Newton for
5+
:data:`~isaaclab_assets.robots.allegro.ALLEGRO_HAND_CFG`,
6+
:data:`~isaaclab_assets.robots.shadow_hand.SHADOW_HAND_CFG`,
7+
:data:`~isaaclab_assets.robots.shadow_hand.SHADOW_HAND_NEWTON_CFG`, and
8+
:data:`~isaaclab_assets.robots.kuka_allegro.KUKA_ALLEGRO_CFG`. Their ``articulation_props`` used
9+
the deprecated PhysX-only ``ArticulationRootPropertiesCfg``, which never authored the
10+
``newton:selfCollisionEnabled`` attribute Newton's schema resolver checks. They now pass a
11+
``PhysxArticulationCfg`` + ``NewtonArticulationCfg`` fragment pair so ``enabled_self_collisions``
12+
is authored on both backends explicitly.

source/isaaclab_assets/isaaclab_assets/robots/allegro.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
import math
1919

20+
from isaaclab_newton.sim.schemas import NewtonArticulationCfg
21+
from isaaclab_physx.sim.schemas import PhysxArticulationCfg
22+
2023
import isaaclab.sim as sim_utils
2124
from isaaclab.actuators import ImplicitActuatorCfg
2225
from isaaclab.assets.articulation import ArticulationCfg
@@ -40,13 +43,16 @@
4043
max_depenetration_velocity=1000.0,
4144
max_contact_impulse=1e32,
4245
),
43-
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
44-
enabled_self_collisions=True,
45-
solver_position_iteration_count=8,
46-
solver_velocity_iteration_count=0,
47-
sleep_threshold=0.005,
48-
stabilization_threshold=0.0005,
49-
),
46+
articulation_props=[
47+
PhysxArticulationCfg(
48+
enabled_self_collisions=True,
49+
solver_position_iteration_count=8,
50+
solver_velocity_iteration_count=0,
51+
sleep_threshold=0.005,
52+
stabilization_threshold=0.0005,
53+
),
54+
NewtonArticulationCfg(self_collision_enabled=True),
55+
],
5056
# collision_props=sim_utils.CollisionPropertiesCfg(contact_offset=0.005, rest_offset=0.0),
5157
),
5258
init_state=ArticulationCfg.InitialStateCfg(

source/isaaclab_assets/isaaclab_assets/robots/kuka_allegro.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
1717
"""
1818

19+
from isaaclab_newton.sim.schemas import NewtonArticulationCfg
20+
from isaaclab_physx.sim.schemas import PhysxArticulationCfg
21+
1922
import isaaclab.sim as sim_utils
2023
from isaaclab.actuators import ImplicitActuatorCfg
2124
from isaaclab.assets.articulation import ArticulationCfg
@@ -37,13 +40,16 @@
3740
max_angular_velocity=1000.0,
3841
max_depenetration_velocity=1000.0,
3942
),
40-
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
41-
enabled_self_collisions=True,
42-
solver_position_iteration_count=32,
43-
solver_velocity_iteration_count=1,
44-
sleep_threshold=0.005,
45-
stabilization_threshold=0.0005,
46-
),
43+
articulation_props=[
44+
PhysxArticulationCfg(
45+
enabled_self_collisions=True,
46+
solver_position_iteration_count=32,
47+
solver_velocity_iteration_count=1,
48+
sleep_threshold=0.005,
49+
stabilization_threshold=0.0005,
50+
),
51+
NewtonArticulationCfg(self_collision_enabled=True),
52+
],
4753
joint_drive_props=sim_utils.JointDrivePropertiesCfg(drive_type="force"),
4854
),
4955
init_state=ArticulationCfg.InitialStateCfg(

source/isaaclab_assets/isaaclab_assets/robots/shadow_hand.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
1717
"""
1818

19+
from isaaclab_newton.sim.schemas import NewtonArticulationCfg
20+
from isaaclab_physx.sim.schemas import PhysxArticulationCfg
21+
1922
import isaaclab.sim as sim_utils
2023
from isaaclab.actuators import ImplicitActuatorCfg
2124
from isaaclab.assets.articulation import ArticulationCfg
@@ -34,13 +37,16 @@
3437
retain_accelerations=True,
3538
max_depenetration_velocity=1000.0,
3639
),
37-
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
38-
enabled_self_collisions=True,
39-
solver_position_iteration_count=8,
40-
solver_velocity_iteration_count=0,
41-
sleep_threshold=0.005,
42-
stabilization_threshold=0.0005,
43-
),
40+
articulation_props=[
41+
PhysxArticulationCfg(
42+
enabled_self_collisions=True,
43+
solver_position_iteration_count=8,
44+
solver_velocity_iteration_count=0,
45+
sleep_threshold=0.005,
46+
stabilization_threshold=0.0005,
47+
),
48+
NewtonArticulationCfg(self_collision_enabled=True),
49+
],
4450
# collision_props=sim_utils.CollisionPropertiesCfg(contact_offset=0.005, rest_offset=0.0),
4551
joint_drive_props=sim_utils.JointDrivePropertiesCfg(drive_type="force"),
4652
fixed_tendons_props=sim_utils.FixedTendonPropertiesCfg(limit_stiffness=30.0, damping=0.1),
@@ -96,7 +102,10 @@
96102
retain_accelerations=True,
97103
max_depenetration_velocity=1000.0,
98104
),
99-
articulation_props=sim_utils.ArticulationRootPropertiesCfg(enabled_self_collisions=True),
105+
articulation_props=[
106+
PhysxArticulationCfg(enabled_self_collisions=True),
107+
NewtonArticulationCfg(self_collision_enabled=True),
108+
],
100109
joint_drive_props=sim_utils.JointDrivePropertiesCfg(drive_type="force", ensure_drives_exist=True),
101110
fixed_tendons_props=sim_utils.FixedTendonPropertiesCfg(damping=0.1),
102111
),

source/isaaclab_assets/pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ requires-python = ">=3.12"
2020
dependencies = [
2121
"isaaclab",
2222
"isaaclab_contrib",
23+
"isaaclab_physx",
24+
"isaaclab_newton",
2325
]
2426

2527
[tool.uv.sources]
2628
isaaclab = { path = "../isaaclab", editable = true }
2729
isaaclab_contrib = { path = "../isaaclab_contrib", editable = true }
30+
isaaclab_physx = { path = "../isaaclab_physx", editable = true }
31+
isaaclab_newton = { path = "../isaaclab_newton", editable = true }
2832

2933
[project.urls]
3034
Homepage = "https://github.com/isaac-sim/IsaacLab"

source/isaaclab_ov/changelog.d/fix-ov-benchmark-sim-cfg.skip

Whitespace-only changes.

0 commit comments

Comments
 (0)