From 4c9a192024d997b40467bfc225503baa02976b31 Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 18:11:17 -0700 Subject: [PATCH 1/6] Add MuJoCo gravity comp + Newton schema cfgs (rebased on develop) Adds MuJoCo (Newton MuJoCo kernel) and Newton-native schema cfg classes to isaaclab_newton.sim.schemas using the framework from #5275: * MujocoRigidBodyPropertiesCfg (gravcomp -> mjc:gravcomp) * MujocoJointDrivePropertiesCfg (actuatorgravcomp -> mjc:actuatorgravcomp via MjcJointAPI) * NewtonCollisionPropertiesCfg (contact_margin, contact_gap via NewtonCollisionAPI) * NewtonMeshCollisionPropertiesCfg (max_hull_vertices via NewtonMeshCollisionAPI) * NewtonMaterialPropertiesCfg (torsional_friction, rolling_friction via NewtonMaterialAPI) * NewtonArticulationRootPropertiesCfg (self_collision_enabled via NewtonArticulationRootAPI) All cfgs follow the per-declaring-class MRO routing from #5275 with ClassVar metadata. Field names follow the snake_case = camelCase convention; old names (gravity_compensation_scale, gravity_compensation) kept as deprecation aliases forwarded via __post_init__. Forwarding shims on isaaclab.sim.schemas preserve existing imports. Spawner auto-enables body-level gravcomp when joint-level actuatorgravcomp is requested without it. --- .../vidur-add-mujoco-gravcomp.minor.rst | 12 ++ source/isaaclab/isaaclab/sim/__init__.py | 24 ++- source/isaaclab/isaaclab/sim/__init__.pyi | 18 ++ .../isaaclab/isaaclab/sim/schemas/__init__.py | 24 ++- .../isaaclab/sim/schemas/__init__.pyi | 14 ++ .../isaaclab/isaaclab/sim/schemas/schemas.py | 30 +-- .../isaaclab/sim/schemas/schemas_cfg.py | 22 ++ .../sim/spawners/from_files/from_files.py | 14 ++ source/isaaclab/test/sim/test_schemas.py | 92 +++++++- .../vidur-add-newton-schemas.minor.rst | 16 ++ .../isaaclab_newton/sim/schemas/__init__.py | 15 ++ .../isaaclab_newton/sim/schemas/__init__.pyi | 13 ++ .../sim/schemas/schemas_cfg.py | 202 ++++++++++++++++++ .../test/sim/test_newton_schemas.py | 183 ++++++++++++++++ 14 files changed, 663 insertions(+), 16 deletions(-) create mode 100644 source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst create mode 100644 source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst create mode 100644 source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py create mode 100644 source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi create mode 100644 source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py create mode 100644 source/isaaclab_newton/test/sim/test_newton_schemas.py diff --git a/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst b/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst new file mode 100644 index 000000000000..e162d1a5ba93 --- /dev/null +++ b/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst @@ -0,0 +1,12 @@ +Changed +^^^^^^^ + +* Deprecated :attr:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg.gravity_compensation_scale` + in favour of :attr:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg.gravcomp`. Forwarded + via ``__post_init__``. Removal in 5.0. +* Deprecated :attr:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg.gravity_compensation` + in favour of :attr:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg.actuatorgravcomp`. + Forwarded via ``__post_init__``. Removal in 5.0. +* Relocated :class:`MujocoRigidBodyPropertiesCfg` and :class:`MujocoJointDrivePropertiesCfg` + to :mod:`isaaclab_newton.sim.schemas`. Forwarding shims on :mod:`isaaclab.sim.schemas` and + :mod:`isaaclab.sim` preserve existing imports. Shims scheduled for removal in 5.0. diff --git a/source/isaaclab/isaaclab/sim/__init__.py b/source/isaaclab/isaaclab/sim/__init__.py index 9c140a2507cf..d5e9ebb614ad 100644 --- a/source/isaaclab/isaaclab/sim/__init__.py +++ b/source/isaaclab/isaaclab/sim/__init__.py @@ -69,6 +69,18 @@ _PHYSX_FORWARDS = _PHYSX_FORWARDS_SCHEMAS | _PHYSX_FORWARDS_MATERIALS +# Names that moved out of this package into ``isaaclab_newton.sim.schemas``. +# Resolved lazily on first access so importing ``isaaclab.sim`` does not +# require ``isaaclab_newton`` to be installed. +_NEWTON_FORWARDS = frozenset({ + "MujocoRigidBodyPropertiesCfg", + "MujocoJointDrivePropertiesCfg", + "NewtonCollisionPropertiesCfg", + "NewtonMeshCollisionPropertiesCfg", + "NewtonMaterialPropertiesCfg", + "NewtonArticulationRootPropertiesCfg", +}) + def __getattr__(name): if name in _PHYSX_FORWARDS_SCHEMAS: @@ -91,8 +103,18 @@ def __getattr__(name): " shim is scheduled for removal in 5.0." ) from e return getattr(_physx_mat_cfg, name) + if name in _NEWTON_FORWARDS: + try: + from isaaclab_newton.sim.schemas import schemas_cfg as _newton_cfg + except ImportError as e: + raise ImportError( + f"'isaaclab.sim.{name}' has moved to 'isaaclab_newton.sim.schemas'." + " Install the isaaclab_newton extension or update your import. This forwarding" + " shim is scheduled for removal in 5.0." + ) from e + return getattr(_newton_cfg, name) return _stub_getattr(name) def __dir__(): - return sorted(set(_stub_dir()) | _PHYSX_FORWARDS) + return sorted(set(_stub_dir()) | _PHYSX_FORWARDS | _NEWTON_FORWARDS) diff --git a/source/isaaclab/isaaclab/sim/__init__.pyi b/source/isaaclab/isaaclab/sim/__init__.pyi index e1d9f535a207..2a8ac0a7a98b 100644 --- a/source/isaaclab/isaaclab/sim/__init__.pyi +++ b/source/isaaclab/isaaclab/sim/__init__.pyi @@ -43,6 +43,14 @@ __all__ = [ "JointDriveBaseCfg", "MassPropertiesCfg", "MeshCollisionPropertiesCfg", + "MujocoJointDrivePropertiesCfg", + "MujocoRigidBodyPropertiesCfg", + "NewtonArticulationRootPropertiesCfg", + "NewtonCollisionPropertiesCfg", + "NewtonMaterialPropertiesCfg", + "NewtonMeshCollisionPropertiesCfg", + "PhysxJointDrivePropertiesCfg", + "PhysxRigidBodyPropertiesCfg", "RigidBodyBaseCfg", "SDFMeshPropertiesCfg", "SpatialTendonPropertiesCfg", @@ -209,12 +217,22 @@ from .schemas import ( JointDriveBaseCfg, MassPropertiesCfg, MeshCollisionPropertiesCfg, + PhysxJointDrivePropertiesCfg, + PhysxRigidBodyPropertiesCfg, RigidBodyBaseCfg, SDFMeshPropertiesCfg, SpatialTendonPropertiesCfg, TriangleMeshPropertiesCfg, TriangleMeshSimplificationPropertiesCfg, ) + +# Forwarded to isaaclab_newton.sim.schemas via __getattr__ shim +MujocoJointDrivePropertiesCfg = ... +MujocoRigidBodyPropertiesCfg = ... +NewtonArticulationRootPropertiesCfg = ... +NewtonCollisionPropertiesCfg = ... +NewtonMaterialPropertiesCfg = ... +NewtonMeshCollisionPropertiesCfg = ... from .spawners import ( SpawnerCfg, RigidObjectSpawnerCfg, diff --git a/source/isaaclab/isaaclab/sim/schemas/__init__.py b/source/isaaclab/isaaclab/sim/schemas/__init__.py index 2692196d4829..ada479c4402a 100644 --- a/source/isaaclab/isaaclab/sim/schemas/__init__.py +++ b/source/isaaclab/isaaclab/sim/schemas/__init__.py @@ -67,6 +67,18 @@ "PhysxSpatialTendonPropertiesCfg", }) +# Names that moved out of this module into ``isaaclab_newton.sim.schemas``. +# Resolved lazily on first access so importing ``isaaclab.sim.schemas`` does +# not require ``isaaclab_newton`` to be installed. +_NEWTON_FORWARDS = frozenset({ + "MujocoRigidBodyPropertiesCfg", + "MujocoJointDrivePropertiesCfg", + "NewtonCollisionPropertiesCfg", + "NewtonMeshCollisionPropertiesCfg", + "NewtonMaterialPropertiesCfg", + "NewtonArticulationRootPropertiesCfg", +}) + def __getattr__(name): if name in _PHYSX_FORWARDS: @@ -79,8 +91,18 @@ def __getattr__(name): " shim is scheduled for removal in 5.0." ) from e return getattr(_physx_cfg, name) + if name in _NEWTON_FORWARDS: + try: + from isaaclab_newton.sim.schemas import schemas_cfg as _newton_cfg + except ImportError as e: + raise ImportError( + f"'isaaclab.sim.schemas.{name}' has moved to 'isaaclab_newton.sim.schemas'." + " Install the isaaclab_newton extension or update your import. This forwarding" + " shim is scheduled for removal in 5.0." + ) from e + return getattr(_newton_cfg, name) return _stub_getattr(name) def __dir__(): - return sorted(set(_stub_dir()) | _PHYSX_FORWARDS) + return sorted(set(_stub_dir()) | _PHYSX_FORWARDS | _NEWTON_FORWARDS) diff --git a/source/isaaclab/isaaclab/sim/schemas/__init__.pyi b/source/isaaclab/isaaclab/sim/schemas/__init__.pyi index 9a90ed0d810d..97985543e678 100644 --- a/source/isaaclab/isaaclab/sim/schemas/__init__.pyi +++ b/source/isaaclab/isaaclab/sim/schemas/__init__.pyi @@ -28,6 +28,12 @@ __all__ = [ "JointDriveBaseCfg", "MassPropertiesCfg", "MeshCollisionBaseCfg", + "MujocoJointDrivePropertiesCfg", + "MujocoRigidBodyPropertiesCfg", + "NewtonArticulationRootPropertiesCfg", + "NewtonCollisionPropertiesCfg", + "NewtonMaterialPropertiesCfg", + "NewtonMeshCollisionPropertiesCfg", "RigidBodyBaseCfg", ] @@ -60,3 +66,11 @@ from .schemas_cfg import ( MeshCollisionBaseCfg, RigidBodyBaseCfg, ) + +# Forwarded to isaaclab_newton.sim.schemas via __getattr__ shim +MujocoJointDrivePropertiesCfg = ... +MujocoRigidBodyPropertiesCfg = ... +NewtonArticulationRootPropertiesCfg = ... +NewtonCollisionPropertiesCfg = ... +NewtonMaterialPropertiesCfg = ... +NewtonMeshCollisionPropertiesCfg = ... diff --git a/source/isaaclab/isaaclab/sim/schemas/schemas.py b/source/isaaclab/isaaclab/sim/schemas/schemas.py index 70f129413e5b..b7a74e27ff25 100644 --- a/source/isaaclab/isaaclab/sim/schemas/schemas.py +++ b/source/isaaclab/isaaclab/sim/schemas/schemas.py @@ -416,14 +416,14 @@ def define_rigid_body_properties(prim_path: str, cfg: schemas_cfg.RigidBodyBaseC def modify_rigid_body_properties( prim_path: str, cfg: schemas_cfg.RigidBodyBaseCfg, stage: Usd.Stage | None = None ) -> bool: - """Modify PhysX parameters for a rigid body prim. + """Modify parameters for a rigid body prim. - A `rigid body`_ is a single body that can be simulated by PhysX. It can be either dynamic or kinematic. - A dynamic body responds to forces and collisions. A `kinematic body`_ can be moved by the user, but does not - respond to forces. They are similar to having static bodies that can be moved around. + A `rigid body`_ is a single body that can be simulated by a physics engine. It can be either dynamic + or kinematic. A dynamic body responds to forces and collisions. A `kinematic body`_ can be moved by + the user, but does not respond to forces. - The schema comprises of attributes that belong to the `RigidBodyAPI`_ and `PhysxRigidBodyAPI`_. - schemas. The latter contains the PhysX parameters for the rigid body. + Solver-common properties (from `RigidBodyAPI`_) are always written. Solver-specific properties are + written based on the cfg subclass metadata (``_usd_namespace``, ``_usd_applied_schema``). .. note:: This function is decorated with :func:`apply_nested` that sets the properties to all the prims @@ -432,11 +432,13 @@ def modify_rigid_body_properties( .. _rigid body: https://nvidia-omniverse.github.io/PhysX/physx/5.4.1/docs/RigidBodyOverview.html .. _kinematic body: https://openusd.org/release/wp_rigid_body_physics.html#kinematic-bodies .. _RigidBodyAPI: https://openusd.org/dev/api/class_usd_physics_rigid_body_a_p_i.html - .. _PhysxRigidBodyAPI: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/104.2/class_physx_schema_physx_rigid_body_a_p_i.html Args: prim_path: The prim path to the rigid body. - cfg: The configuration for the rigid body. + cfg: The configuration for the rigid body. Accepts + :class:`~schemas_cfg.RigidBodyBaseCfg` for solver-common properties, + :class:`~schemas_cfg.PhysxRigidBodyPropertiesCfg` for PhysX properties, or + :class:`~schemas_cfg.MujocoRigidBodyPropertiesCfg` for Newton (MuJoCo) properties. stage: The stage where to find the prim. Defaults to None, in which case the current stage is used. @@ -727,15 +729,14 @@ def activate_contact_sensors(prim_path: str, threshold: float = 0.0, stage: Usd. def modify_joint_drive_properties( prim_path: str, cfg: schemas_cfg.JointDriveBaseCfg, stage: Usd.Stage | None = None ) -> bool: - """Modify PhysX parameters for a joint prim. + """Modify parameters for a joint prim. This function checks if the input prim is a prismatic or revolute joint and applies the joint drive schema on it. If the joint is a tendon (i.e., it has the `PhysxTendonAxisAPI`_ schema applied on it), then the joint drive schema is not applied. - Based on the configuration, this method modifies the properties of the joint drive. These properties are - based on the `UsdPhysics.DriveAPI`_ schema. For more information on the properties, please refer to the - official documentation. + Solver-common properties (from `UsdPhysics.DriveAPI`_) are always written. Solver-specific properties + are written based on the cfg subclass metadata (``_usd_namespace``, ``_usd_applied_schema``). .. caution:: @@ -748,7 +749,10 @@ def modify_joint_drive_properties( Args: prim_path: The prim path where to apply the joint drive schema. - cfg: The configuration for the joint drive. + cfg: The configuration for the joint drive. Accepts + :class:`~schemas_cfg.JointDriveBaseCfg` for solver-common properties, + :class:`~schemas_cfg.PhysxJointDrivePropertiesCfg` for PhysX properties, or + :class:`~schemas_cfg.MujocoJointDrivePropertiesCfg` for Newton (MuJoCo) properties. stage: The stage where to find the prim. Defaults to None, in which case the current stage is used. diff --git a/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py b/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py index eae040435429..4b4879842587 100644 --- a/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py +++ b/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py @@ -44,6 +44,17 @@ } ) +_NEWTON_FORWARDS = frozenset( + { + "MujocoRigidBodyPropertiesCfg", + "MujocoJointDrivePropertiesCfg", + "NewtonCollisionPropertiesCfg", + "NewtonMeshCollisionPropertiesCfg", + "NewtonMaterialPropertiesCfg", + "NewtonArticulationRootPropertiesCfg", + } +) + def __getattr__(name): if name in _PHYSX_FORWARDS: @@ -57,6 +68,17 @@ def __getattr__(name): " removal in 5.0." ) from e return getattr(_physx_cfg, name) + if name in _NEWTON_FORWARDS: + try: + from isaaclab_newton.sim.schemas import schemas_cfg as _newton_cfg + except ImportError as e: + raise ImportError( + f"'isaaclab.sim.schemas.schemas_cfg.{name}' has moved to" + " 'isaaclab_newton.sim.schemas.schemas_cfg'. Install the isaaclab_newton" + " extension or update your import. This forwarding shim is scheduled for" + " removal in 5.0." + ) from e + return getattr(_newton_cfg, name) raise AttributeError(f"module 'isaaclab.sim.schemas.schemas_cfg' has no attribute {name!r}") diff --git a/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py b/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py index be7bd6e7074e..83e39d91c980 100644 --- a/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py +++ b/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py @@ -365,6 +365,20 @@ def _spawn_from_usd_file( # note: these are only for setting low-level simulation properties. all others should be set or are # and overridden by the articulation/actuator properties. if cfg.joint_drive_props is not None: + # auto-enable body-level gravcomp if joint-level actuator gravcomp is requested + # without it — actuatorgravcomp has no effect since there are no forces to route + from isaaclab_newton.sim.schemas.schemas_cfg import MujocoJointDrivePropertiesCfg, MujocoRigidBodyPropertiesCfg + + if ( + isinstance(cfg.joint_drive_props, MujocoJointDrivePropertiesCfg) + and cfg.joint_drive_props.actuatorgravcomp + and not isinstance(cfg.rigid_props, MujocoRigidBodyPropertiesCfg) + ): + logger.info( + "Joint-level actuator gravity compensation requires body-level gravcomp." + " Auto-setting rigid_props to MujocoRigidBodyPropertiesCfg(gravcomp=1.0)." + ) + schemas.modify_rigid_body_properties(prim_path, MujocoRigidBodyPropertiesCfg(gravcomp=1.0)) schemas.modify_joint_drive_properties(prim_path, cfg.joint_drive_props) # define deformable body properties, or modify if deformable body API is present (PhysX only) diff --git a/source/isaaclab/test/sim/test_schemas.py b/source/isaaclab/test/sim/test_schemas.py index 1fb03ede1433..c00ce70e265d 100644 --- a/source/isaaclab/test/sim/test_schemas.py +++ b/source/isaaclab/test/sim/test_schemas.py @@ -106,7 +106,7 @@ def test_valid_properties_cfg(setup_simulation): sim, arti_cfg, rigid_cfg, collision_cfg, mass_cfg, joint_cfg = setup_simulation # deprecation aliases are nulled by __post_init__ after forwarding to the canonical # field; exclude them from the all-non-None check. - deprecation_aliases = {"max_velocity", "max_effort"} + deprecation_aliases = {"max_velocity", "max_effort", "gravity_compensation_scale", "gravity_compensation"} for cfg in [arti_cfg, rigid_cfg, collision_cfg, mass_cfg, joint_cfg]: for k, v in cfg.__dict__.items(): # skip class-metadata keys (``_usd_*``) and deprecation aliases nulled in __post_init__ @@ -879,6 +879,96 @@ def test_multi_instance_schema_detection_on_tendon_joints(setup_simulation): assert result is False, "Prim without tendon root schema should return False" +@pytest.mark.isaacsim_ci +def test_mujoco_gravity_compensation_scale_on_rigid_body(setup_simulation): + """Test that gravity_compensation_scale is written as mjc:gravcomp on rigid body prims.""" + sim, _, _, _, _, _ = setup_simulation + stage = sim_utils.get_current_stage() + + sim_utils.create_prim("/World/cube_gc", prim_type="Cube", translation=(0.0, 0.0, 0.62)) + rigid_cfg = schemas.MujocoRigidBodyPropertiesCfg(gravcomp=0.5) + schemas.define_rigid_body_properties("/World/cube_gc", rigid_cfg) + + prim = stage.GetPrimAtPath("/World/cube_gc") + attr = prim.GetAttribute("mjc:gravcomp") + assert attr.IsValid(), "mjc:gravcomp attribute not found on rigid body prim" + assert attr.Get() == pytest.approx(0.5) + + +@pytest.mark.isaacsim_ci +def test_mujoco_gravity_compensation_scale_not_set_when_none(setup_simulation): + """Test that mjc:gravcomp is not written when gravity_compensation_scale is None.""" + sim, _, _, _, _, _ = setup_simulation + stage = sim_utils.get_current_stage() + + sim_utils.create_prim("/World/cube_gc2", prim_type="Cube", translation=(1.0, 0.0, 0.62)) + rigid_cfg = schemas.MujocoRigidBodyPropertiesCfg() + schemas.define_rigid_body_properties("/World/cube_gc2", rigid_cfg) + + prim = stage.GetPrimAtPath("/World/cube_gc2") + attr = prim.GetAttribute("mjc:gravcomp") + assert not attr.IsValid(), "mjc:gravcomp should not be set when gravity_compensation_scale is None" + + +@pytest.mark.isaacsim_ci +def test_mujoco_joint_gravity_compensation_written(setup_simulation): + """Test that gravity_compensation is written as mjc:actuatorgravcomp on joint prims.""" + sim, _, _, _, _, _ = setup_simulation + stage = sim_utils.get_current_stage() + + sim_utils.create_prim("/World/jgc_test", prim_type="Xform") + sim_utils.create_prim("/World/jgc_test/body0", prim_type="Cube") + sim_utils.create_prim("/World/jgc_test/body1", prim_type="Cube") + UsdPhysics.RevoluteJoint.Define(stage, "/World/jgc_test/body1/joint0") + + joint_cfg = schemas.MujocoJointDrivePropertiesCfg(actuatorgravcomp=True) + schemas.modify_joint_drive_properties("/World/jgc_test", joint_cfg) + + joint_prim = stage.GetPrimAtPath("/World/jgc_test/body1/joint0") + attr = joint_prim.GetAttribute("mjc:actuatorgravcomp") + assert attr.IsValid(), "mjc:actuatorgravcomp not set on joint prim" + assert attr.Get() is True + + +@pytest.mark.isaacsim_ci +def test_mujoco_joint_gravity_compensation_not_set_when_none(setup_simulation): + """Test that mjc:actuatorgravcomp is not written when gravity_compensation is None.""" + sim, _, _, _, _, _ = setup_simulation + stage = sim_utils.get_current_stage() + + sim_utils.create_prim("/World/jgc_test2", prim_type="Xform") + sim_utils.create_prim("/World/jgc_test2/body0", prim_type="Cube") + sim_utils.create_prim("/World/jgc_test2/body1", prim_type="Cube") + UsdPhysics.RevoluteJoint.Define(stage, "/World/jgc_test2/body1/joint0") + + joint_cfg = schemas.MujocoJointDrivePropertiesCfg() + schemas.modify_joint_drive_properties("/World/jgc_test2", joint_cfg) + + joint_prim = stage.GetPrimAtPath("/World/jgc_test2/body1/joint0") + attr = joint_prim.GetAttribute("mjc:actuatorgravcomp") + assert not attr.IsValid(), "mjc:actuatorgravcomp should not be set when gravity_compensation is None" + + +@pytest.mark.isaacsim_ci +def test_mujoco_gravity_compensation_scale_deprecation_alias(setup_simulation): + """Legacy gravity_compensation_scale kwarg must forward to gravcomp with DeprecationWarning.""" + sim, _, _, _, _, _ = setup_simulation + with pytest.warns(DeprecationWarning, match="gravity_compensation_scale"): + cfg = schemas.MujocoRigidBodyPropertiesCfg(gravity_compensation_scale=0.5) + assert cfg.gravcomp == pytest.approx(0.5) + assert cfg.gravity_compensation_scale is None + + +@pytest.mark.isaacsim_ci +def test_mujoco_gravity_compensation_deprecation_alias(setup_simulation): + """Legacy gravity_compensation kwarg must forward to actuatorgravcomp with DeprecationWarning.""" + sim, _, _, _, _, _ = setup_simulation + with pytest.warns(DeprecationWarning, match="gravity_compensation"): + cfg = schemas.MujocoJointDrivePropertiesCfg(gravity_compensation=True) + assert cfg.actuatorgravcomp is True + assert cfg.gravity_compensation is None + + """ Helper functions. """ diff --git a/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst b/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst new file mode 100644 index 000000000000..7f3d9696055b --- /dev/null +++ b/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst @@ -0,0 +1,16 @@ +Added +^^^^^ + +* Added :class:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg` with + :attr:`gravcomp` for body-level gravity compensation (``mjc:gravcomp``). +* Added :class:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg` with + :attr:`actuatorgravcomp` for joint-level gravity compensation routing + (``mjc:actuatorgravcomp`` via ``MjcJointAPI``). +* Added :class:`~isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg` with + :attr:`contact_margin` and :attr:`contact_gap` (``newton:*`` via ``NewtonCollisionAPI``). +* Added :class:`~isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg` with + :attr:`max_hull_vertices` (``newton:maxHullVertices`` via ``NewtonMeshCollisionAPI``). +* Added :class:`~isaaclab_newton.sim.schemas.NewtonMaterialPropertiesCfg` with + :attr:`torsional_friction` and :attr:`rolling_friction` (``newton:*`` via ``NewtonMaterialAPI``). +* Added :class:`~isaaclab_newton.sim.schemas.NewtonArticulationRootPropertiesCfg` with + :attr:`self_collision_enabled` (``newton:selfCollisionEnabled`` via ``NewtonArticulationRootAPI``). diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py new file mode 100644 index 000000000000..e2bf6fdcba3a --- /dev/null +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +"""Newton and MuJoCo simulation schema configuration classes.""" + +from .schemas_cfg import ( + MujocoJointDrivePropertiesCfg, + MujocoRigidBodyPropertiesCfg, + NewtonArticulationRootPropertiesCfg, + NewtonCollisionPropertiesCfg, + NewtonMaterialPropertiesCfg, + NewtonMeshCollisionPropertiesCfg, +) diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi new file mode 100644 index 000000000000..4cdc015f6775 --- /dev/null +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi @@ -0,0 +1,13 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +from .schemas_cfg import ( + MujocoJointDrivePropertiesCfg as MujocoJointDrivePropertiesCfg, + MujocoRigidBodyPropertiesCfg as MujocoRigidBodyPropertiesCfg, + NewtonArticulationRootPropertiesCfg as NewtonArticulationRootPropertiesCfg, + NewtonCollisionPropertiesCfg as NewtonCollisionPropertiesCfg, + NewtonMaterialPropertiesCfg as NewtonMaterialPropertiesCfg, + NewtonMeshCollisionPropertiesCfg as NewtonMeshCollisionPropertiesCfg, +) diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py new file mode 100644 index 000000000000..3a6b67ef1446 --- /dev/null +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py @@ -0,0 +1,202 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +from __future__ import annotations + +from typing import ClassVar + +from isaaclab.sim.schemas.schemas_cfg import ( + ArticulationRootBaseCfg, + CollisionBaseCfg, + JointDriveBaseCfg, + MeshCollisionBaseCfg, + RigidBodyBaseCfg, + _deprecate_field_alias, +) +from isaaclab.sim.spawners.materials.physics_materials_cfg import RigidBodyMaterialBaseCfg +from isaaclab.utils import configclass + + +@configclass +class MujocoRigidBodyPropertiesCfg(RigidBodyBaseCfg): + """MuJoCo/Newton-specific rigid body properties. + + Extends :class:`~isaaclab.sim.schemas.RigidBodyBaseCfg` with body-level + gravity compensation for the Newton (MuJoCo) simulation backend. + + See :meth:`~isaaclab.sim.schemas.modify_rigid_body_properties` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "mjc" + _usd_applied_schema: ClassVar[str | None] = None + _usd_field_exceptions: ClassVar[dict] = {} + + def __post_init__(self): + _deprecate_field_alias(self, "gravity_compensation_scale", "gravcomp") + + gravcomp: float | None = None + """Gravity compensation scale for the body [dimensionless]. + + ``0.0`` = no compensation; ``1.0`` = full compensation. + Written to ``mjc:gravcomp`` on the rigid-body prim. + Body-level gravcomp must be set for joint-level actuatorgravcomp to have any effect. + """ + + gravity_compensation_scale: float | None = None + """Deprecated alias for :attr:`gravcomp`. Removal in 5.0.""" + + +@configclass +class MujocoJointDrivePropertiesCfg(JointDriveBaseCfg): + """MuJoCo/Newton-specific joint drive properties. + + Extends :class:`~isaaclab.sim.schemas.JointDriveBaseCfg` with joint-level + gravity compensation routing for the Newton (MuJoCo) simulation backend. + + See :meth:`~isaaclab.sim.schemas.modify_joint_drive_properties` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "mjc" + _usd_applied_schema: ClassVar[str | None] = "MjcJointAPI" + _usd_field_exceptions: ClassVar[dict] = {} + + def __post_init__(self): + super().__post_init__() # parent handles max_velocity/max_effort aliases + _deprecate_field_alias(self, "gravity_compensation", "actuatorgravcomp") + + actuatorgravcomp: bool | None = None + """Route gravity compensation forces through the actuator channel. + + When ``True``, compensation forces go to ``qfrc_actuator`` (subject to force limits). + Requires body-level :attr:`MujocoRigidBodyPropertiesCfg.gravcomp`. + Written to ``mjc:actuatorgravcomp`` via ``MjcJointAPI``. + """ + + gravity_compensation: bool | None = None + """Deprecated alias for :attr:`actuatorgravcomp`. Removal in 5.0.""" + + +@configclass +class NewtonCollisionPropertiesCfg(CollisionBaseCfg): + """Newton-specific collision properties. + + Extends :class:`~isaaclab.sim.schemas.CollisionBaseCfg` with Newton-native + contact geometry attributes. + + See :meth:`~isaaclab.sim.schemas.modify_collision_properties` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = "NewtonCollisionAPI" + _usd_field_exceptions: ClassVar[dict] = {} + + contact_margin: float | None = None + """Outward inflation of the collision surface [m]. + + Extends the effective collision surface outward. Sum of both bodies' margins is + used for collision detection. Essential for thin shells and cloth. + Written to ``newton:contactMargin`` via ``NewtonCollisionAPI``. + Range: [0, inf). + """ + + contact_gap: float | None = None + """Additional contact detection gap [m]. + + AABBs are expanded by this value; contacts detected earlier to avoid tunneling. + Written to ``newton:contactGap`` via ``NewtonCollisionAPI``. + Set to ``-inf`` to use Newton's builder default. Range: [0, inf). + """ + + +@configclass +class NewtonMeshCollisionPropertiesCfg(NewtonCollisionPropertiesCfg, MeshCollisionBaseCfg): + """Newton-specific mesh collision properties. + + Extends :class:`NewtonCollisionPropertiesCfg` with convex-hull vertex limit. + + See :meth:`~isaaclab.sim.schemas.modify_mesh_collision_properties` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = "NewtonMeshCollisionAPI" + _usd_field_exceptions: ClassVar[dict] = {} + + max_hull_vertices: int | None = None + """Maximum vertices in the convex hull approximation [dimensionless]. + + Only relevant when ``physics:approximation = "convexHull"``. + Written to ``newton:maxHullVertices`` via ``NewtonMeshCollisionAPI``. + Set to ``-1`` to use as many vertices as needed for a perfect hull. + """ + + +@configclass +class NewtonMaterialPropertiesCfg(RigidBodyMaterialBaseCfg): + """Newton-specific rigid body material properties. + + Extends :class:`~isaaclab.sim.spawners.materials.RigidBodyMaterialBaseCfg` + with Newton-native friction attributes. + + See :meth:`~isaaclab.sim.spawners.materials.spawn_rigid_body_material` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = "NewtonMaterialAPI" + _usd_field_exceptions: ClassVar[dict] = {} + + torsional_friction: float | None = None + """Torsional friction coefficient (resistance to spinning at a contact point) [dimensionless]. + + Written to ``newton:torsionalFriction`` via ``NewtonMaterialAPI``. + Range: [0, inf). + """ + + rolling_friction: float | None = None + """Rolling friction coefficient (resistance to rolling motion) [dimensionless]. + + Written to ``newton:rollingFriction`` via ``NewtonMaterialAPI``. + Range: [0, inf). + """ + + +@configclass +class NewtonArticulationRootPropertiesCfg(ArticulationRootBaseCfg): + """Newton-specific articulation root properties. + + Extends :class:`~isaaclab.sim.schemas.ArticulationRootBaseCfg` with + Newton-native self-collision control. + + See :meth:`~isaaclab.sim.schemas.modify_articulation_root_properties` for more information. + + .. note:: + If the values are None, they are not modified. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = "NewtonArticulationRootAPI" + _usd_field_exceptions: ClassVar[dict] = {} + + self_collision_enabled: bool | None = None + """Whether self-collisions between bodies in this articulation are enabled. + + Written to ``newton:selfCollisionEnabled`` via ``NewtonArticulationRootAPI``. + Newton's resolver checks this native attribute first before falling back to + ``physxArticulation:enabledSelfCollisions``. + """ diff --git a/source/isaaclab_newton/test/sim/test_newton_schemas.py b/source/isaaclab_newton/test/sim/test_newton_schemas.py new file mode 100644 index 000000000000..6c3554266f74 --- /dev/null +++ b/source/isaaclab_newton/test/sim/test_newton_schemas.py @@ -0,0 +1,183 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +"""Tests for Newton and MuJoCo schema cfg classes in isaaclab_newton.""" + +from isaaclab.app import AppLauncher + +# launch omniverse app +simulation_app = AppLauncher(headless=True).app + +"""Rest everything follows.""" + +import pytest +from isaaclab_newton.sim.schemas import ( + MujocoJointDrivePropertiesCfg, + MujocoRigidBodyPropertiesCfg, + NewtonArticulationRootPropertiesCfg, + NewtonCollisionPropertiesCfg, + NewtonMaterialPropertiesCfg, +) + +from pxr import UsdPhysics + +import isaaclab.sim as sim_utils +import isaaclab.sim.schemas as schemas +from isaaclab.sim import SimulationCfg, SimulationContext +from isaaclab.sim.spawners.materials import spawn_rigid_body_material + + +@pytest.fixture +def setup_sim(): + """Fixture to set up and tear down the simulation context.""" + sim_utils.create_new_stage() + sim = SimulationContext(SimulationCfg(dt=0.1)) + yield sim + sim._disable_app_control_on_stop_handle = True + sim.stop() + sim.clear_instance() + + +# --------------------------------------------------------------------------- +# MuJoCo rigid body gravity compensation +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_mujoco_gravcomp_written(setup_sim): + """gravcomp=0.5 must write mjc:gravcomp=0.5 on the prim.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/body_gc", prim_type="Cube", translation=(0.0, 0.0, 0.5)) + schemas.define_rigid_body_properties("/World/body_gc", MujocoRigidBodyPropertiesCfg(gravcomp=0.5)) + attr = stage.GetPrimAtPath("/World/body_gc").GetAttribute("mjc:gravcomp") + assert attr.IsValid(), "mjc:gravcomp was not authored" + assert attr.Get() == pytest.approx(0.5) + + +@pytest.mark.isaacsim_ci +def test_mujoco_gravcomp_not_written_when_none(setup_sim): + """gravcomp=None must not write mjc:gravcomp.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/body_gc2", prim_type="Cube", translation=(1.0, 0.0, 0.5)) + schemas.define_rigid_body_properties("/World/body_gc2", MujocoRigidBodyPropertiesCfg()) + attr = stage.GetPrimAtPath("/World/body_gc2").GetAttribute("mjc:gravcomp") + assert not attr.IsValid(), "mjc:gravcomp should not be authored when gravcomp=None" + + +# --------------------------------------------------------------------------- +# MuJoCo joint actuator gravity comp +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_mujoco_actuatorgravcomp_written(setup_sim): + """actuatorgravcomp=True must write mjc:actuatorgravcomp=True on the joint prim.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/art_gc", prim_type="Xform") + sim_utils.create_prim("/World/art_gc/body0", prim_type="Cube") + sim_utils.create_prim("/World/art_gc/body1", prim_type="Cube") + UsdPhysics.RevoluteJoint.Define(stage, "/World/art_gc/joint0") + schemas.modify_joint_drive_properties("/World/art_gc", MujocoJointDrivePropertiesCfg(actuatorgravcomp=True)) + attr = stage.GetPrimAtPath("/World/art_gc/joint0").GetAttribute("mjc:actuatorgravcomp") + assert attr.IsValid(), "mjc:actuatorgravcomp was not authored" + assert attr.Get() is True + + +@pytest.mark.isaacsim_ci +def test_mujoco_actuatorgravcomp_not_written_when_none(setup_sim): + """actuatorgravcomp=None must not write mjc:actuatorgravcomp.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/art_gc2", prim_type="Xform") + sim_utils.create_prim("/World/art_gc2/body0", prim_type="Cube") + sim_utils.create_prim("/World/art_gc2/body1", prim_type="Cube") + UsdPhysics.RevoluteJoint.Define(stage, "/World/art_gc2/joint0") + schemas.modify_joint_drive_properties("/World/art_gc2", MujocoJointDrivePropertiesCfg()) + attr = stage.GetPrimAtPath("/World/art_gc2/joint0").GetAttribute("mjc:actuatorgravcomp") + assert not attr.IsValid(), "mjc:actuatorgravcomp should not be authored when None" + + +# --------------------------------------------------------------------------- +# Newton collision +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_newton_collision_contact_margin_written(setup_sim): + """contact_margin=0.01 must write newton:contactMargin and apply NewtonCollisionAPI.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/col_newton", prim_type="Cube", translation=(2.0, 0.0, 0.5)) + schemas.define_collision_properties("/World/col_newton", NewtonCollisionPropertiesCfg(contact_margin=0.01)) + prim = stage.GetPrimAtPath("/World/col_newton") + assert prim.GetAttribute("newton:contactMargin").Get() == pytest.approx(0.01) + assert "NewtonCollisionAPI" in prim.GetAppliedSchemas() + + +@pytest.mark.isaacsim_ci +def test_newton_collision_no_schema_when_none(setup_sim): + """NewtonCollisionPropertiesCfg() with all None must NOT apply NewtonCollisionAPI.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/col_newton2", prim_type="Cube", translation=(3.0, 0.0, 0.5)) + schemas.define_collision_properties("/World/col_newton2", NewtonCollisionPropertiesCfg()) + applied = stage.GetPrimAtPath("/World/col_newton2").GetAppliedSchemas() + assert "NewtonCollisionAPI" not in applied + + +# --------------------------------------------------------------------------- +# Newton material +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_newton_material_properties_written(setup_sim): + """torsional_friction and rolling_friction must be written and NewtonMaterialAPI applied.""" + mat_cfg = NewtonMaterialPropertiesCfg(torsional_friction=0.3, rolling_friction=0.001) + prim = spawn_rigid_body_material("/World/newton_mat", mat_cfg) + assert prim.GetAttribute("newton:torsionalFriction").Get() == pytest.approx(0.3) + assert prim.GetAttribute("newton:rollingFriction").Get() == pytest.approx(0.001) + assert "NewtonMaterialAPI" in prim.GetAppliedSchemas() + + +@pytest.mark.isaacsim_ci +def test_newton_material_no_schema_when_none(setup_sim): + """NewtonMaterialPropertiesCfg() with all Newton fields None must NOT apply NewtonMaterialAPI.""" + mat_cfg = NewtonMaterialPropertiesCfg() + prim = spawn_rigid_body_material("/World/newton_mat2", mat_cfg) + assert "NewtonMaterialAPI" not in prim.GetAppliedSchemas() + + +# --------------------------------------------------------------------------- +# Newton articulation root +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_newton_articulation_self_collision_written(setup_sim): + """self_collision_enabled=True must write newton:selfCollisionEnabled and apply the API.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/nart", prim_type="Xform") + sim_utils.create_prim("/World/nart/body0", prim_type="Cube") + UsdPhysics.ArticulationRootAPI.Apply(stage.GetPrimAtPath("/World/nart")) + schemas.modify_articulation_root_properties( + "/World/nart", + NewtonArticulationRootPropertiesCfg(self_collision_enabled=True), + ) + prim = stage.GetPrimAtPath("/World/nart") + assert prim.GetAttribute("newton:selfCollisionEnabled").Get() is True + assert "NewtonArticulationRootAPI" in prim.GetAppliedSchemas() + + +@pytest.mark.isaacsim_ci +def test_newton_articulation_no_schema_when_none(setup_sim): + """NewtonArticulationRootPropertiesCfg() with None must NOT apply NewtonArticulationRootAPI.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/nart2", prim_type="Xform") + sim_utils.create_prim("/World/nart2/body0", prim_type="Cube") + UsdPhysics.ArticulationRootAPI.Apply(stage.GetPrimAtPath("/World/nart2")) + schemas.modify_articulation_root_properties( + "/World/nart2", + NewtonArticulationRootPropertiesCfg(), + ) + applied = stage.GetPrimAtPath("/World/nart2").GetAppliedSchemas() + assert "NewtonArticulationRootAPI" not in applied From 4e717233e4ccaac1136c67c67e260b0662d0f7cf Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 18:20:55 -0700 Subject: [PATCH 2/6] Make Mujoco cfgs subclass Newton cfgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mujoco is one of Newton's solver options (alongside MJWarp, XPBD, Featherstone, etc.), so the cfg class hierarchy now reflects that: * NewtonRigidBodyPropertiesCfg(RigidBodyBaseCfg) — empty Newton-targeted base * NewtonJointDrivePropertiesCfg(JointDriveBaseCfg) — empty Newton-targeted base * MujocoRigidBodyPropertiesCfg(NewtonRigidBodyPropertiesCfg) — gravcomp * MujocoJointDrivePropertiesCfg(NewtonJointDrivePropertiesCfg) — actuatorgravcomp The empty Newton bases reserve the newton:* namespace for future Newton-native fields (Newton has no rigid-body or joint-drive applied schemas today, so the classes are placeholders). Per-declaring-class MRO routing in _apply_namespaced_schemas keeps each field in its own USD namespace regardless of which subclass is instantiated: * gravcomp (declared on Mujoco subclass) -> mjc:gravcomp * future Newton-native field (declared on Newton parent) -> newton:* * inherited base fields -> physics:* isinstance(cfg, NewtonRigidBodyPropertiesCfg) is now true for both Newton-native and Mujoco-targeted cfgs, useful for spawner-side polymorphic dispatch. --- source/isaaclab/isaaclab/sim/__init__.py | 2 + source/isaaclab/isaaclab/sim/__init__.pyi | 4 ++ .../isaaclab/isaaclab/sim/schemas/__init__.py | 2 + .../isaaclab/sim/schemas/__init__.pyi | 4 ++ .../isaaclab/sim/schemas/schemas_cfg.py | 2 + .../vidur-add-newton-schemas.minor.rst | 16 +++-- .../isaaclab_newton/sim/schemas/__init__.py | 2 + .../isaaclab_newton/sim/schemas/__init__.pyi | 2 + .../sim/schemas/schemas_cfg.py | 58 ++++++++++++++++--- 9 files changed, 79 insertions(+), 13 deletions(-) diff --git a/source/isaaclab/isaaclab/sim/__init__.py b/source/isaaclab/isaaclab/sim/__init__.py index d5e9ebb614ad..8299d48aadf4 100644 --- a/source/isaaclab/isaaclab/sim/__init__.py +++ b/source/isaaclab/isaaclab/sim/__init__.py @@ -75,6 +75,8 @@ _NEWTON_FORWARDS = frozenset({ "MujocoRigidBodyPropertiesCfg", "MujocoJointDrivePropertiesCfg", + "NewtonRigidBodyPropertiesCfg", + "NewtonJointDrivePropertiesCfg", "NewtonCollisionPropertiesCfg", "NewtonMeshCollisionPropertiesCfg", "NewtonMaterialPropertiesCfg", diff --git a/source/isaaclab/isaaclab/sim/__init__.pyi b/source/isaaclab/isaaclab/sim/__init__.pyi index 2a8ac0a7a98b..2d5edfdf921f 100644 --- a/source/isaaclab/isaaclab/sim/__init__.pyi +++ b/source/isaaclab/isaaclab/sim/__init__.pyi @@ -47,8 +47,10 @@ __all__ = [ "MujocoRigidBodyPropertiesCfg", "NewtonArticulationRootPropertiesCfg", "NewtonCollisionPropertiesCfg", + "NewtonJointDrivePropertiesCfg", "NewtonMaterialPropertiesCfg", "NewtonMeshCollisionPropertiesCfg", + "NewtonRigidBodyPropertiesCfg", "PhysxJointDrivePropertiesCfg", "PhysxRigidBodyPropertiesCfg", "RigidBodyBaseCfg", @@ -231,8 +233,10 @@ MujocoJointDrivePropertiesCfg = ... MujocoRigidBodyPropertiesCfg = ... NewtonArticulationRootPropertiesCfg = ... NewtonCollisionPropertiesCfg = ... +NewtonJointDrivePropertiesCfg = ... NewtonMaterialPropertiesCfg = ... NewtonMeshCollisionPropertiesCfg = ... +NewtonRigidBodyPropertiesCfg = ... from .spawners import ( SpawnerCfg, RigidObjectSpawnerCfg, diff --git a/source/isaaclab/isaaclab/sim/schemas/__init__.py b/source/isaaclab/isaaclab/sim/schemas/__init__.py index ada479c4402a..d26c31935ba9 100644 --- a/source/isaaclab/isaaclab/sim/schemas/__init__.py +++ b/source/isaaclab/isaaclab/sim/schemas/__init__.py @@ -73,6 +73,8 @@ _NEWTON_FORWARDS = frozenset({ "MujocoRigidBodyPropertiesCfg", "MujocoJointDrivePropertiesCfg", + "NewtonRigidBodyPropertiesCfg", + "NewtonJointDrivePropertiesCfg", "NewtonCollisionPropertiesCfg", "NewtonMeshCollisionPropertiesCfg", "NewtonMaterialPropertiesCfg", diff --git a/source/isaaclab/isaaclab/sim/schemas/__init__.pyi b/source/isaaclab/isaaclab/sim/schemas/__init__.pyi index 97985543e678..fd0c882a5f35 100644 --- a/source/isaaclab/isaaclab/sim/schemas/__init__.pyi +++ b/source/isaaclab/isaaclab/sim/schemas/__init__.pyi @@ -32,8 +32,10 @@ __all__ = [ "MujocoRigidBodyPropertiesCfg", "NewtonArticulationRootPropertiesCfg", "NewtonCollisionPropertiesCfg", + "NewtonJointDrivePropertiesCfg", "NewtonMaterialPropertiesCfg", "NewtonMeshCollisionPropertiesCfg", + "NewtonRigidBodyPropertiesCfg", "RigidBodyBaseCfg", ] @@ -72,5 +74,7 @@ MujocoJointDrivePropertiesCfg = ... MujocoRigidBodyPropertiesCfg = ... NewtonArticulationRootPropertiesCfg = ... NewtonCollisionPropertiesCfg = ... +NewtonJointDrivePropertiesCfg = ... NewtonMaterialPropertiesCfg = ... NewtonMeshCollisionPropertiesCfg = ... +NewtonRigidBodyPropertiesCfg = ... diff --git a/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py b/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py index 4b4879842587..3a7bcbf57df3 100644 --- a/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py +++ b/source/isaaclab/isaaclab/sim/schemas/schemas_cfg.py @@ -48,6 +48,8 @@ { "MujocoRigidBodyPropertiesCfg", "MujocoJointDrivePropertiesCfg", + "NewtonRigidBodyPropertiesCfg", + "NewtonJointDrivePropertiesCfg", "NewtonCollisionPropertiesCfg", "NewtonMeshCollisionPropertiesCfg", "NewtonMaterialPropertiesCfg", diff --git a/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst b/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst index 7f3d9696055b..84eb5ce846a1 100644 --- a/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst +++ b/source/isaaclab_newton/changelog.d/vidur-add-newton-schemas.minor.rst @@ -1,11 +1,17 @@ Added ^^^^^ -* Added :class:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg` with - :attr:`gravcomp` for body-level gravity compensation (``mjc:gravcomp``). -* Added :class:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg` with - :attr:`actuatorgravcomp` for joint-level gravity compensation routing - (``mjc:actuatorgravcomp`` via ``MjcJointAPI``). +* Added :class:`~isaaclab_newton.sim.schemas.NewtonRigidBodyPropertiesCfg` and + :class:`~isaaclab_newton.sim.schemas.NewtonJointDrivePropertiesCfg` as Newton-targeted + bases for solver-specific subclasses. Currently empty (no Newton-native ``newton:*`` + rigid-body or joint-drive attributes today); reserved as the family root for any + future Newton-native fields. +* Added :class:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg` (subclasses + :class:`NewtonRigidBodyPropertiesCfg`) with :attr:`gravcomp` for body-level gravity + compensation (``mjc:gravcomp``). +* Added :class:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg` (subclasses + :class:`NewtonJointDrivePropertiesCfg`) with :attr:`actuatorgravcomp` for joint-level + gravity compensation routing (``mjc:actuatorgravcomp`` via ``MjcJointAPI``). * Added :class:`~isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg` with :attr:`contact_margin` and :attr:`contact_gap` (``newton:*`` via ``NewtonCollisionAPI``). * Added :class:`~isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg` with diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py index e2bf6fdcba3a..80f943ad46ee 100644 --- a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.py @@ -10,6 +10,8 @@ MujocoRigidBodyPropertiesCfg, NewtonArticulationRootPropertiesCfg, NewtonCollisionPropertiesCfg, + NewtonJointDrivePropertiesCfg, NewtonMaterialPropertiesCfg, NewtonMeshCollisionPropertiesCfg, + NewtonRigidBodyPropertiesCfg, ) diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi index 4cdc015f6775..fa2a49429d5f 100644 --- a/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/__init__.pyi @@ -8,6 +8,8 @@ from .schemas_cfg import ( MujocoRigidBodyPropertiesCfg as MujocoRigidBodyPropertiesCfg, NewtonArticulationRootPropertiesCfg as NewtonArticulationRootPropertiesCfg, NewtonCollisionPropertiesCfg as NewtonCollisionPropertiesCfg, + NewtonJointDrivePropertiesCfg as NewtonJointDrivePropertiesCfg, NewtonMaterialPropertiesCfg as NewtonMaterialPropertiesCfg, NewtonMeshCollisionPropertiesCfg as NewtonMeshCollisionPropertiesCfg, + NewtonRigidBodyPropertiesCfg as NewtonRigidBodyPropertiesCfg, ) diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py index 3a6b67ef1446..59a697a4de60 100644 --- a/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py @@ -20,11 +20,32 @@ @configclass -class MujocoRigidBodyPropertiesCfg(RigidBodyBaseCfg): - """MuJoCo/Newton-specific rigid body properties. +class NewtonRigidBodyPropertiesCfg(RigidBodyBaseCfg): + """Newton-targeted rigid body properties. - Extends :class:`~isaaclab.sim.schemas.RigidBodyBaseCfg` with body-level - gravity compensation for the Newton (MuJoCo) simulation backend. + Base class for cfgs that author rigid-body attributes consumed by any of + Newton's solver options (MuJoCo, XPBD, Featherstone, Semi-implicit, Kamino). + Newton has no native ``newton:*`` rigid-body attributes today, so this class + is currently empty — solver-specific subclasses (e.g., + :class:`MujocoRigidBodyPropertiesCfg`) carry the actual fields. + + The ``newton:`` namespace is reserved here so future Newton-native + rigid-body fields can be added without an API change. + + See :meth:`~isaaclab.sim.schemas.modify_rigid_body_properties` for more information. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = None + _usd_field_exceptions: ClassVar[dict] = {} + + +@configclass +class MujocoRigidBodyPropertiesCfg(NewtonRigidBodyPropertiesCfg): + """MuJoCo-solver-specific rigid body properties. + + Extends :class:`NewtonRigidBodyPropertiesCfg` with body-level gravity + compensation, consumed only when running Newton's MuJoCo solver. See :meth:`~isaaclab.sim.schemas.modify_rigid_body_properties` for more information. @@ -52,11 +73,32 @@ def __post_init__(self): @configclass -class MujocoJointDrivePropertiesCfg(JointDriveBaseCfg): - """MuJoCo/Newton-specific joint drive properties. +class NewtonJointDrivePropertiesCfg(JointDriveBaseCfg): + """Newton-targeted joint drive properties. + + Base class for cfgs that author joint-drive attributes consumed by any of + Newton's solver options. Newton has no native ``newton:*`` joint-drive + attributes today, so this class is currently empty — solver-specific + subclasses (e.g., :class:`MujocoJointDrivePropertiesCfg`) carry the actual + fields. + + The ``newton:`` namespace is reserved here so future Newton-native + joint-drive fields can be added without an API change. + + See :meth:`~isaaclab.sim.schemas.modify_joint_drive_properties` for more information. + """ + + _usd_namespace: ClassVar[str | None] = "newton" + _usd_applied_schema: ClassVar[str | None] = None + _usd_field_exceptions: ClassVar[dict] = {} + + +@configclass +class MujocoJointDrivePropertiesCfg(NewtonJointDrivePropertiesCfg): + """MuJoCo-solver-specific joint drive properties. - Extends :class:`~isaaclab.sim.schemas.JointDriveBaseCfg` with joint-level - gravity compensation routing for the Newton (MuJoCo) simulation backend. + Extends :class:`NewtonJointDrivePropertiesCfg` with joint-level gravity + compensation routing, consumed only when running Newton's MuJoCo solver. See :meth:`~isaaclab.sim.schemas.modify_joint_drive_properties` for more information. From e1144f6972eeceeffdf12665a0e82628488c877f Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 18:28:37 -0700 Subject: [PATCH 3/6] Drop gravity_compensation_scale/gravity_compensation deprecation aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These field names only existed on the unmerged 5276 PR — they were never released on develop, so no deprecation cycle is needed. Renaming to gravcomp and actuatorgravcomp directly without aliases. Removed the aliases, the __post_init__ forwarding, and the alias tests in the core test file. --- .../vidur-add-mujoco-gravcomp.minor.rst | 21 +++++++++--------- source/isaaclab/test/sim/test_schemas.py | 22 +------------------ .../sim/schemas/schemas_cfg.py | 14 ------------ 3 files changed, 11 insertions(+), 46 deletions(-) diff --git a/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst b/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst index e162d1a5ba93..15ec19098dfa 100644 --- a/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst +++ b/source/isaaclab/changelog.d/vidur-add-mujoco-gravcomp.minor.rst @@ -1,12 +1,11 @@ -Changed -^^^^^^^ +Added +^^^^^ -* Deprecated :attr:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg.gravity_compensation_scale` - in favour of :attr:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg.gravcomp`. Forwarded - via ``__post_init__``. Removal in 5.0. -* Deprecated :attr:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg.gravity_compensation` - in favour of :attr:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg.actuatorgravcomp`. - Forwarded via ``__post_init__``. Removal in 5.0. -* Relocated :class:`MujocoRigidBodyPropertiesCfg` and :class:`MujocoJointDrivePropertiesCfg` - to :mod:`isaaclab_newton.sim.schemas`. Forwarding shims on :mod:`isaaclab.sim.schemas` and - :mod:`isaaclab.sim` preserve existing imports. Shims scheduled for removal in 5.0. +* Added forwarding shims on :mod:`isaaclab.sim.schemas` and :mod:`isaaclab.sim` for the + Newton/MuJoCo cfg classes added in :mod:`isaaclab_newton.sim.schemas` + (:class:`NewtonRigidBodyPropertiesCfg`, :class:`NewtonJointDrivePropertiesCfg`, + :class:`NewtonCollisionPropertiesCfg`, :class:`NewtonMeshCollisionPropertiesCfg`, + :class:`NewtonMaterialPropertiesCfg`, :class:`NewtonArticulationRootPropertiesCfg`, + :class:`MujocoRigidBodyPropertiesCfg`, :class:`MujocoJointDrivePropertiesCfg`). + The shims resolve lazily on first access so importing :mod:`isaaclab.sim.schemas` + does not require :mod:`isaaclab_newton` to be installed. diff --git a/source/isaaclab/test/sim/test_schemas.py b/source/isaaclab/test/sim/test_schemas.py index c00ce70e265d..6d56cea7f1cb 100644 --- a/source/isaaclab/test/sim/test_schemas.py +++ b/source/isaaclab/test/sim/test_schemas.py @@ -106,7 +106,7 @@ def test_valid_properties_cfg(setup_simulation): sim, arti_cfg, rigid_cfg, collision_cfg, mass_cfg, joint_cfg = setup_simulation # deprecation aliases are nulled by __post_init__ after forwarding to the canonical # field; exclude them from the all-non-None check. - deprecation_aliases = {"max_velocity", "max_effort", "gravity_compensation_scale", "gravity_compensation"} + deprecation_aliases = {"max_velocity", "max_effort"} for cfg in [arti_cfg, rigid_cfg, collision_cfg, mass_cfg, joint_cfg]: for k, v in cfg.__dict__.items(): # skip class-metadata keys (``_usd_*``) and deprecation aliases nulled in __post_init__ @@ -949,26 +949,6 @@ def test_mujoco_joint_gravity_compensation_not_set_when_none(setup_simulation): assert not attr.IsValid(), "mjc:actuatorgravcomp should not be set when gravity_compensation is None" -@pytest.mark.isaacsim_ci -def test_mujoco_gravity_compensation_scale_deprecation_alias(setup_simulation): - """Legacy gravity_compensation_scale kwarg must forward to gravcomp with DeprecationWarning.""" - sim, _, _, _, _, _ = setup_simulation - with pytest.warns(DeprecationWarning, match="gravity_compensation_scale"): - cfg = schemas.MujocoRigidBodyPropertiesCfg(gravity_compensation_scale=0.5) - assert cfg.gravcomp == pytest.approx(0.5) - assert cfg.gravity_compensation_scale is None - - -@pytest.mark.isaacsim_ci -def test_mujoco_gravity_compensation_deprecation_alias(setup_simulation): - """Legacy gravity_compensation kwarg must forward to actuatorgravcomp with DeprecationWarning.""" - sim, _, _, _, _, _ = setup_simulation - with pytest.warns(DeprecationWarning, match="gravity_compensation"): - cfg = schemas.MujocoJointDrivePropertiesCfg(gravity_compensation=True) - assert cfg.actuatorgravcomp is True - assert cfg.gravity_compensation is None - - """ Helper functions. """ diff --git a/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py index 59a697a4de60..f0065daa867f 100644 --- a/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py +++ b/source/isaaclab_newton/isaaclab_newton/sim/schemas/schemas_cfg.py @@ -13,7 +13,6 @@ JointDriveBaseCfg, MeshCollisionBaseCfg, RigidBodyBaseCfg, - _deprecate_field_alias, ) from isaaclab.sim.spawners.materials.physics_materials_cfg import RigidBodyMaterialBaseCfg from isaaclab.utils import configclass @@ -57,9 +56,6 @@ class MujocoRigidBodyPropertiesCfg(NewtonRigidBodyPropertiesCfg): _usd_applied_schema: ClassVar[str | None] = None _usd_field_exceptions: ClassVar[dict] = {} - def __post_init__(self): - _deprecate_field_alias(self, "gravity_compensation_scale", "gravcomp") - gravcomp: float | None = None """Gravity compensation scale for the body [dimensionless]. @@ -68,9 +64,6 @@ def __post_init__(self): Body-level gravcomp must be set for joint-level actuatorgravcomp to have any effect. """ - gravity_compensation_scale: float | None = None - """Deprecated alias for :attr:`gravcomp`. Removal in 5.0.""" - @configclass class NewtonJointDrivePropertiesCfg(JointDriveBaseCfg): @@ -110,10 +103,6 @@ class MujocoJointDrivePropertiesCfg(NewtonJointDrivePropertiesCfg): _usd_applied_schema: ClassVar[str | None] = "MjcJointAPI" _usd_field_exceptions: ClassVar[dict] = {} - def __post_init__(self): - super().__post_init__() # parent handles max_velocity/max_effort aliases - _deprecate_field_alias(self, "gravity_compensation", "actuatorgravcomp") - actuatorgravcomp: bool | None = None """Route gravity compensation forces through the actuator channel. @@ -122,9 +111,6 @@ def __post_init__(self): Written to ``mjc:actuatorgravcomp`` via ``MjcJointAPI``. """ - gravity_compensation: bool | None = None - """Deprecated alias for :attr:`actuatorgravcomp`. Removal in 5.0.""" - @configclass class NewtonCollisionPropertiesCfg(CollisionBaseCfg): From 8b57185319d51ccf79918837ceb8a90574e0eeff Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 18:55:55 -0700 Subject: [PATCH 4/6] Address review feedback: drop duplicate tests, expand Newton coverage * Remove four MuJoCo gravcomp tests from source/isaaclab/test/sim/test_schemas.py that had stale docstrings (referencing the dropped gravity_compensation_scale/ gravity_compensation kwargs) and duplicated coverage already in test_newton_schemas.py. * Add four new tests in source/isaaclab_newton/test/sim/test_newton_schemas.py: - test_newton_mesh_collision_max_hull_vertices_written: covers NewtonMeshCollisionPropertiesCfg writing newton:maxHullVertices and applying NewtonMeshCollisionAPI. - test_newton_mesh_collision_no_schema_when_none: confirms gating works. - test_mujoco_isinstance_newton: locks in the class-hierarchy contract that spawner auto-enable depends on (MujocoXxxCfg IS-A NewtonXxxCfg). - test_newton_mesh_collision_mixed_namespace_write: verifies per-declaring- class MRO routing on a single instance with fields owned by both NewtonCollisionPropertiesCfg (contact_margin) and NewtonMeshCollisionPropertiesCfg (max_hull_vertices). --- source/isaaclab/test/sim/test_schemas.py | 70 --------------- .../test/sim/test_newton_schemas.py | 86 +++++++++++++++++++ 2 files changed, 86 insertions(+), 70 deletions(-) diff --git a/source/isaaclab/test/sim/test_schemas.py b/source/isaaclab/test/sim/test_schemas.py index 6d56cea7f1cb..1fb03ede1433 100644 --- a/source/isaaclab/test/sim/test_schemas.py +++ b/source/isaaclab/test/sim/test_schemas.py @@ -879,76 +879,6 @@ def test_multi_instance_schema_detection_on_tendon_joints(setup_simulation): assert result is False, "Prim without tendon root schema should return False" -@pytest.mark.isaacsim_ci -def test_mujoco_gravity_compensation_scale_on_rigid_body(setup_simulation): - """Test that gravity_compensation_scale is written as mjc:gravcomp on rigid body prims.""" - sim, _, _, _, _, _ = setup_simulation - stage = sim_utils.get_current_stage() - - sim_utils.create_prim("/World/cube_gc", prim_type="Cube", translation=(0.0, 0.0, 0.62)) - rigid_cfg = schemas.MujocoRigidBodyPropertiesCfg(gravcomp=0.5) - schemas.define_rigid_body_properties("/World/cube_gc", rigid_cfg) - - prim = stage.GetPrimAtPath("/World/cube_gc") - attr = prim.GetAttribute("mjc:gravcomp") - assert attr.IsValid(), "mjc:gravcomp attribute not found on rigid body prim" - assert attr.Get() == pytest.approx(0.5) - - -@pytest.mark.isaacsim_ci -def test_mujoco_gravity_compensation_scale_not_set_when_none(setup_simulation): - """Test that mjc:gravcomp is not written when gravity_compensation_scale is None.""" - sim, _, _, _, _, _ = setup_simulation - stage = sim_utils.get_current_stage() - - sim_utils.create_prim("/World/cube_gc2", prim_type="Cube", translation=(1.0, 0.0, 0.62)) - rigid_cfg = schemas.MujocoRigidBodyPropertiesCfg() - schemas.define_rigid_body_properties("/World/cube_gc2", rigid_cfg) - - prim = stage.GetPrimAtPath("/World/cube_gc2") - attr = prim.GetAttribute("mjc:gravcomp") - assert not attr.IsValid(), "mjc:gravcomp should not be set when gravity_compensation_scale is None" - - -@pytest.mark.isaacsim_ci -def test_mujoco_joint_gravity_compensation_written(setup_simulation): - """Test that gravity_compensation is written as mjc:actuatorgravcomp on joint prims.""" - sim, _, _, _, _, _ = setup_simulation - stage = sim_utils.get_current_stage() - - sim_utils.create_prim("/World/jgc_test", prim_type="Xform") - sim_utils.create_prim("/World/jgc_test/body0", prim_type="Cube") - sim_utils.create_prim("/World/jgc_test/body1", prim_type="Cube") - UsdPhysics.RevoluteJoint.Define(stage, "/World/jgc_test/body1/joint0") - - joint_cfg = schemas.MujocoJointDrivePropertiesCfg(actuatorgravcomp=True) - schemas.modify_joint_drive_properties("/World/jgc_test", joint_cfg) - - joint_prim = stage.GetPrimAtPath("/World/jgc_test/body1/joint0") - attr = joint_prim.GetAttribute("mjc:actuatorgravcomp") - assert attr.IsValid(), "mjc:actuatorgravcomp not set on joint prim" - assert attr.Get() is True - - -@pytest.mark.isaacsim_ci -def test_mujoco_joint_gravity_compensation_not_set_when_none(setup_simulation): - """Test that mjc:actuatorgravcomp is not written when gravity_compensation is None.""" - sim, _, _, _, _, _ = setup_simulation - stage = sim_utils.get_current_stage() - - sim_utils.create_prim("/World/jgc_test2", prim_type="Xform") - sim_utils.create_prim("/World/jgc_test2/body0", prim_type="Cube") - sim_utils.create_prim("/World/jgc_test2/body1", prim_type="Cube") - UsdPhysics.RevoluteJoint.Define(stage, "/World/jgc_test2/body1/joint0") - - joint_cfg = schemas.MujocoJointDrivePropertiesCfg() - schemas.modify_joint_drive_properties("/World/jgc_test2", joint_cfg) - - joint_prim = stage.GetPrimAtPath("/World/jgc_test2/body1/joint0") - attr = joint_prim.GetAttribute("mjc:actuatorgravcomp") - assert not attr.IsValid(), "mjc:actuatorgravcomp should not be set when gravity_compensation is None" - - """ Helper functions. """ diff --git a/source/isaaclab_newton/test/sim/test_newton_schemas.py b/source/isaaclab_newton/test/sim/test_newton_schemas.py index 6c3554266f74..67ee6265d82c 100644 --- a/source/isaaclab_newton/test/sim/test_newton_schemas.py +++ b/source/isaaclab_newton/test/sim/test_newton_schemas.py @@ -18,7 +18,10 @@ MujocoRigidBodyPropertiesCfg, NewtonArticulationRootPropertiesCfg, NewtonCollisionPropertiesCfg, + NewtonJointDrivePropertiesCfg, NewtonMaterialPropertiesCfg, + NewtonMeshCollisionPropertiesCfg, + NewtonRigidBodyPropertiesCfg, ) from pxr import UsdPhysics @@ -181,3 +184,86 @@ def test_newton_articulation_no_schema_when_none(setup_sim): ) applied = stage.GetPrimAtPath("/World/nart2").GetAppliedSchemas() assert "NewtonArticulationRootAPI" not in applied + + +# --------------------------------------------------------------------------- +# Newton mesh collision (max_hull_vertices, NewtonMeshCollisionAPI) +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_newton_mesh_collision_max_hull_vertices_written(setup_sim): + """max_hull_vertices=64 must write newton:maxHullVertices and apply NewtonMeshCollisionAPI.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/mesh_col", prim_type="Cube", translation=(4.0, 0.0, 0.5)) + schemas.define_mesh_collision_properties( + "/World/mesh_col", + NewtonMeshCollisionPropertiesCfg(mesh_approximation_name="convexHull", max_hull_vertices=64), + ) + prim = stage.GetPrimAtPath("/World/mesh_col") + assert prim.GetAttribute("newton:maxHullVertices").Get() == 64 + assert "NewtonMeshCollisionAPI" in prim.GetAppliedSchemas() + + +@pytest.mark.isaacsim_ci +def test_newton_mesh_collision_no_schema_when_none(setup_sim): + """NewtonMeshCollisionPropertiesCfg() with max_hull_vertices=None must NOT apply NewtonMeshCollisionAPI.""" + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/mesh_col2", prim_type="Cube", translation=(5.0, 0.0, 0.5)) + schemas.define_mesh_collision_properties( + "/World/mesh_col2", + NewtonMeshCollisionPropertiesCfg(mesh_approximation_name="convexHull"), + ) + applied = stage.GetPrimAtPath("/World/mesh_col2").GetAppliedSchemas() + assert "NewtonMeshCollisionAPI" not in applied + + +# --------------------------------------------------------------------------- +# Class hierarchy contract: Mujoco IS-A Newton +# --------------------------------------------------------------------------- + + +def test_mujoco_isinstance_newton(): + """MujocoXxxCfg instances must be isinstance of their Newton parent. + + The auto-enable spawner logic and any future polymorphic dispatch on + ``isinstance(cfg, NewtonRigidBodyPropertiesCfg)`` depends on this contract. + """ + mjc_rigid = MujocoRigidBodyPropertiesCfg(gravcomp=0.5) + assert isinstance(mjc_rigid, NewtonRigidBodyPropertiesCfg) + + mjc_joint = MujocoJointDrivePropertiesCfg(actuatorgravcomp=True) + assert isinstance(mjc_joint, NewtonJointDrivePropertiesCfg) + + +# --------------------------------------------------------------------------- +# Multi-namespace mixed write — verify per-declaring-class MRO routing keeps +# fields owned by different classes in different namespaces on the same prim. +# --------------------------------------------------------------------------- + + +@pytest.mark.isaacsim_ci +def test_newton_mesh_collision_mixed_namespace_write(setup_sim): + """A NewtonMeshCollisionPropertiesCfg with both contact_margin (declared on + NewtonCollisionPropertiesCfg) and max_hull_vertices (declared on + NewtonMeshCollisionPropertiesCfg) must write each under its declaring class's + namespace and apply both schemas. + """ + stage = sim_utils.get_current_stage() + sim_utils.create_prim("/World/mesh_mixed", prim_type="Cube", translation=(6.0, 0.0, 0.5)) + schemas.define_mesh_collision_properties( + "/World/mesh_mixed", + NewtonMeshCollisionPropertiesCfg( + mesh_approximation_name="convexHull", + max_hull_vertices=32, + contact_margin=0.005, + ), + ) + prim = stage.GetPrimAtPath("/World/mesh_mixed") + # Both attributes share the newton namespace but are gated on different applied + # schemas (NewtonCollisionAPI for contact_margin, NewtonMeshCollisionAPI for + # max_hull_vertices); per-declaring-class routing applies the right schema for each. + assert prim.GetAttribute("newton:contactMargin").Get() == pytest.approx(0.005) + assert prim.GetAttribute("newton:maxHullVertices").Get() == 32 + applied = prim.GetAppliedSchemas() + assert "NewtonMeshCollisionAPI" in applied From 3265ef054fe13a3fcf6e08984a57af2d5eaaa2db Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 20:08:34 -0700 Subject: [PATCH 5/6] Add documentation for schema cfg refactor * Add new core-concepts page `schema_cfgs.rst` explaining the base/subclass hierarchy, when to use each tier (base / Physx / Newton / Mujoco), what parameters live where, mixed-namespace authoring, and the spawner pattern. * Add migration entry to `migrating_to_isaaclab_3-0.rst` covering the class moves (RigidBodyPropertiesCfg -> RigidBodyBaseCfg + PhysxRigidBodyPropertiesCfg etc.), the field renames (max_velocity -> max_joint_velocity, max_effort -> max_force), and the new Newton/Mujoco cfg classes. * Update `isaaclab.sim.schemas` API doc to expose the new base classes (RigidBodyBaseCfg, JointDriveBaseCfg, CollisionBaseCfg, ArticulationRootBaseCfg, MeshCollisionBaseCfg) with cross-references to the PhysX and Newton subclasses. * Update `isaaclab_physx.sim.schemas` API doc with the full PhysX subclass inventory (rigid body, joint drive, collision, articulation root, mesh-cooking family, tendon, deformable body). * Add new `isaaclab_newton.sim.schemas` API doc listing the Newton family roots (Newton*PropertiesCfg) and MuJoCo solver-specific subclasses (Mujoco*Cfg). * Wire the new Newton schemas API doc into `api/index.rst`. Sphinx build clean (no new warnings introduced). --- docs/source/api/index.rst | 2 + docs/source/api/lab/isaaclab.sim.schemas.rst | 94 +++++- .../isaaclab_newton.sim.schemas.rst | 88 ++++++ .../lab_physx/isaaclab_physx.sim.schemas.rst | 117 ++++++- .../migration/migrating_to_isaaclab_3-0.rst | 122 +++++++ docs/source/overview/core-concepts/index.rst | 1 + .../overview/core-concepts/schema_cfgs.rst | 299 ++++++++++++++++++ 7 files changed, 708 insertions(+), 15 deletions(-) create mode 100644 docs/source/api/lab_newton/isaaclab_newton.sim.schemas.rst create mode 100644 docs/source/overview/core-concepts/schema_cfgs.rst diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst index cea73de6802d..2205953eebe7 100644 --- a/docs/source/api/index.rst +++ b/docs/source/api/index.rst @@ -160,6 +160,7 @@ The following modules are available in the ``isaaclab_newton`` extension: renderers scene_data_providers sensors + sim.schemas .. toctree:: :hidden: @@ -170,6 +171,7 @@ The following modules are available in the ``isaaclab_newton`` extension: lab_newton/isaaclab_newton.renderers lab_newton/isaaclab_newton.scene_data_providers lab_newton/isaaclab_newton.sensors + lab_newton/isaaclab_newton.sim.schemas isaaclab_ov extension --------------------- diff --git a/docs/source/api/lab/isaaclab.sim.schemas.rst b/docs/source/api/lab/isaaclab.sim.schemas.rst index 263e3152e596..bb0651c83ec2 100644 --- a/docs/source/api/lab/isaaclab.sim.schemas.rst +++ b/docs/source/api/lab/isaaclab.sim.schemas.rst @@ -1,18 +1,31 @@ -isaaclab.sim.schemas +isaaclab.sim.schemas ==================== .. automodule:: isaaclab.sim.schemas - .. rubric:: Classes + .. rubric:: Solver-common base classes + + These base classes carry the universal-physics fields that every backend honors. + They live in core ``isaaclab`` and have no backend dependency. For backend-specific + knobs, use the matching subclass in :mod:`isaaclab_physx.sim.schemas` or + :mod:`isaaclab_newton.sim.schemas`. See :doc:`/source/overview/core-concepts/schema_cfgs` + for the full design. .. autosummary:: - ArticulationRootPropertiesCfg - RigidBodyPropertiesCfg - CollisionPropertiesCfg + ArticulationRootBaseCfg + RigidBodyBaseCfg + CollisionBaseCfg + JointDriveBaseCfg + MeshCollisionBaseCfg MassPropertiesCfg - JointDrivePropertiesCfg - FixedTendonPropertiesCfg + + .. rubric:: Mesh collision approximations (USD-only, no PhysX schema) + + .. autosummary:: + + BoundingCubePropertiesCfg + BoundingSpherePropertiesCfg .. rubric:: Functions @@ -28,22 +41,33 @@ define_mass_properties modify_mass_properties modify_joint_drive_properties + define_mesh_collision_properties + modify_mesh_collision_properties modify_fixed_tendon_properties + modify_spatial_tendon_properties + +.. currentmodule:: isaaclab.sim.schemas Articulation Root ----------------- -.. autoclass:: ArticulationRootPropertiesCfg +.. autoclass:: ArticulationRootBaseCfg :members: :exclude-members: __init__ .. autofunction:: define_articulation_root_properties .. autofunction:: modify_articulation_root_properties +For PhysX-specific articulation properties (self-collisions, TGS solver iterations, +sleep/stabilization thresholds), see +:class:`~isaaclab_physx.sim.schemas.PhysxArticulationRootPropertiesCfg`. For +Newton-native self-collisions, see +:class:`~isaaclab_newton.sim.schemas.NewtonArticulationRootPropertiesCfg`. + Rigid Body ---------- -.. autoclass:: RigidBodyPropertiesCfg +.. autoclass:: RigidBodyBaseCfg :members: :exclude-members: __init__ @@ -51,16 +75,26 @@ Rigid Body .. autofunction:: modify_rigid_body_properties .. autofunction:: activate_contact_sensors +For PhysX-specific rigid body properties (damping, max velocities, solver iterations, +sleep/stabilization), see :class:`~isaaclab_physx.sim.schemas.PhysxRigidBodyPropertiesCfg`. +For MuJoCo-specific gravity compensation, see +:class:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg`. + Collision --------- -.. autoclass:: CollisionPropertiesCfg +.. autoclass:: CollisionBaseCfg :members: :exclude-members: __init__ .. autofunction:: define_collision_properties .. autofunction:: modify_collision_properties +For PhysX torsional patch friction, see +:class:`~isaaclab_physx.sim.schemas.PhysxCollisionPropertiesCfg`. For Newton-native +contact margin/gap, see +:class:`~isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg`. + Mass ---- @@ -74,20 +108,52 @@ Mass Joint Drive ----------- -.. autoclass:: JointDrivePropertiesCfg +.. autoclass:: JointDriveBaseCfg :members: :exclude-members: __init__ .. autofunction:: modify_joint_drive_properties -Fixed Tendon ------------- +For PhysX-specific drive properties, see +:class:`~isaaclab_physx.sim.schemas.PhysxJointDrivePropertiesCfg`. For MuJoCo +actuator gravity compensation, see +:class:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg`. + +Mesh Collision +-------------- -.. autoclass:: FixedTendonPropertiesCfg +.. autoclass:: MeshCollisionBaseCfg :members: :exclude-members: __init__ +.. autoclass:: BoundingCubePropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: BoundingSpherePropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autofunction:: define_mesh_collision_properties +.. autofunction:: modify_mesh_collision_properties + +For PhysX cooking schemas (convex hull / decomposition / triangle mesh / SDF), +see the ``Physx*PropertiesCfg`` family in :mod:`isaaclab_physx.sim.schemas`. +For Newton hull-vertex limit, see +:class:`~isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg`. + +Tendon +------ + .. autofunction:: modify_fixed_tendon_properties +.. autofunction:: modify_spatial_tendon_properties + +Tendon cfg classes are PhysX-only and live in +:mod:`isaaclab_physx.sim.schemas` +(:class:`~isaaclab_physx.sim.schemas.PhysxFixedTendonPropertiesCfg`, +:class:`~isaaclab_physx.sim.schemas.PhysxSpatialTendonPropertiesCfg`). Deformable Body --------------- diff --git a/docs/source/api/lab_newton/isaaclab_newton.sim.schemas.rst b/docs/source/api/lab_newton/isaaclab_newton.sim.schemas.rst new file mode 100644 index 000000000000..f0dde258fe8c --- /dev/null +++ b/docs/source/api/lab_newton/isaaclab_newton.sim.schemas.rst @@ -0,0 +1,88 @@ +isaaclab_newton.sim.schemas +=========================== + +.. automodule:: isaaclab_newton.sim.schemas + + Newton-targeted schema configuration classes. Each cfg below extends a + solver-common base in :mod:`isaaclab.sim.schemas` with Newton-namespaced + attributes (``newton:*``) or solver-specific attributes (``mjc:*`` for + Newton's MuJoCo solver). MuJoCo cfgs subclass their Newton counterpart + because MuJoCo is one of Newton's solver options. + + See :doc:`/source/overview/core-concepts/schema_cfgs` for the design and + when to use each class. + + .. rubric:: Newton-targeted (family roots) + + .. autosummary:: + + NewtonRigidBodyPropertiesCfg + NewtonJointDrivePropertiesCfg + NewtonCollisionPropertiesCfg + NewtonMeshCollisionPropertiesCfg + NewtonMaterialPropertiesCfg + NewtonArticulationRootPropertiesCfg + + .. rubric:: MuJoCo-solver-specific + + .. autosummary:: + + MujocoRigidBodyPropertiesCfg + MujocoJointDrivePropertiesCfg + +.. currentmodule:: isaaclab_newton.sim.schemas + +Rigid Body +---------- + +.. autoclass:: NewtonRigidBodyPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: MujocoRigidBodyPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Joint Drive +----------- + +.. autoclass:: NewtonJointDrivePropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: MujocoJointDrivePropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Collision +--------- + +.. autoclass:: NewtonCollisionPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: NewtonMeshCollisionPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Material +-------- + +.. autoclass:: NewtonMaterialPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Articulation Root +----------------- + +.. autoclass:: NewtonArticulationRootPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ diff --git a/docs/source/api/lab_physx/isaaclab_physx.sim.schemas.rst b/docs/source/api/lab_physx/isaaclab_physx.sim.schemas.rst index 40fb3addb275..305269068991 100644 --- a/docs/source/api/lab_physx/isaaclab_physx.sim.schemas.rst +++ b/docs/source/api/lab_physx/isaaclab_physx.sim.schemas.rst @@ -3,7 +3,49 @@ isaaclab_physx.sim.schemas .. automodule:: isaaclab_physx.sim.schemas - .. rubric:: Classes + PhysX-specific schema configuration classes. Each cfg below extends a + solver-common base in :mod:`isaaclab.sim.schemas` with PhysX-namespaced + attributes (``physx*:*``) and applies the corresponding ``Physx*API`` + applied schema. See :doc:`/source/overview/core-concepts/schema_cfgs` + for the design. + + .. rubric:: Rigid body and joint drive + + .. autosummary:: + + PhysxRigidBodyPropertiesCfg + PhysxJointDrivePropertiesCfg + + .. rubric:: Collision + + .. autosummary:: + + PhysxCollisionPropertiesCfg + + .. rubric:: Articulation root + + .. autosummary:: + + PhysxArticulationRootPropertiesCfg + + .. rubric:: Mesh collision (PhysX cooking) + + .. autosummary:: + + PhysxConvexHullPropertiesCfg + PhysxConvexDecompositionPropertiesCfg + PhysxTriangleMeshPropertiesCfg + PhysxTriangleMeshSimplificationPropertiesCfg + PhysxSDFMeshPropertiesCfg + + .. rubric:: Tendon + + .. autosummary:: + + PhysxFixedTendonPropertiesCfg + PhysxSpatialTendonPropertiesCfg + + .. rubric:: Deformable body .. autosummary:: @@ -18,6 +60,79 @@ isaaclab_physx.sim.schemas .. currentmodule:: isaaclab_physx.sim.schemas +Rigid Body +---------- + +.. autoclass:: PhysxRigidBodyPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Joint Drive +----------- + +.. autoclass:: PhysxJointDrivePropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Collision +--------- + +.. autoclass:: PhysxCollisionPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Articulation Root +----------------- + +.. autoclass:: PhysxArticulationRootPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Mesh Collision (PhysX cooking) +------------------------------- + +.. autoclass:: PhysxConvexHullPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: PhysxConvexDecompositionPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: PhysxTriangleMeshPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: PhysxTriangleMeshSimplificationPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: PhysxSDFMeshPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +Tendon +------ + +.. autoclass:: PhysxFixedTendonPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + +.. autoclass:: PhysxSpatialTendonPropertiesCfg + :members: + :show-inheritance: + :exclude-members: __init__ + Deformable Body --------------- diff --git a/docs/source/migration/migrating_to_isaaclab_3-0.rst b/docs/source/migration/migrating_to_isaaclab_3-0.rst index 4d29d5f4c8fe..7192a7c83b89 100644 --- a/docs/source/migration/migrating_to_isaaclab_3-0.rst +++ b/docs/source/migration/migrating_to_isaaclab_3-0.rst @@ -98,6 +98,128 @@ The following classes have been moved to ``isaaclab_physx``: installation steps are required. +Schema Configuration Class Refactor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Isaac Lab 3.0, the spawner schema cfg classes are split into solver-common +**base classes** (in ``isaaclab.sim.schemas``) and **backend-specific subclasses** +in ``isaaclab_physx.sim.schemas`` and ``isaaclab_newton.sim.schemas``. This makes +the same asset cfg portable across PhysX and Newton backends, and prepares the +spawner layer for solver-specific knobs (PhysX TGS iterations, MuJoCo gravity +compensation, etc.). + +For the full design, see :ref:`schema-cfgs`. + +**Class moves and renames** + +The following 2.x class names are kept as deprecated aliases. They forward to +the new location and will be removed in 5.0. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Isaac Lab 2.x + - Isaac Lab 3.0 + * - ``RigidBodyPropertiesCfg`` + - :class:`~isaaclab.sim.schemas.RigidBodyBaseCfg` (solver-common fields) + + :class:`~isaaclab_physx.sim.schemas.PhysxRigidBodyPropertiesCfg` (PhysX-specific) + * - ``JointDrivePropertiesCfg`` + - :class:`~isaaclab.sim.schemas.JointDriveBaseCfg` + + :class:`~isaaclab_physx.sim.schemas.PhysxJointDrivePropertiesCfg` + * - ``CollisionPropertiesCfg`` + - :class:`~isaaclab.sim.schemas.CollisionBaseCfg` + + :class:`~isaaclab_physx.sim.schemas.PhysxCollisionPropertiesCfg` + * - ``ArticulationRootPropertiesCfg`` + - :class:`~isaaclab.sim.schemas.ArticulationRootBaseCfg` + + :class:`~isaaclab_physx.sim.schemas.PhysxArticulationRootPropertiesCfg` + * - ``RigidBodyMaterialCfg`` + - :class:`~isaaclab.sim.spawners.materials.RigidBodyMaterialBaseCfg` + + :class:`~isaaclab_physx.sim.spawners.materials.PhysxRigidBodyMaterialCfg` + * - ``MeshCollisionPropertiesCfg`` family (``ConvexHullPropertiesCfg``, + ``ConvexDecompositionPropertiesCfg``, ``TriangleMeshPropertiesCfg``, + ``TriangleMeshSimplificationPropertiesCfg``, ``SDFMeshPropertiesCfg``) + - :class:`~isaaclab.sim.schemas.MeshCollisionBaseCfg` + + ``Physx*PropertiesCfg`` family in :mod:`isaaclab_physx.sim.schemas` + * - ``FixedTendonPropertiesCfg``, ``SpatialTendonPropertiesCfg`` + - :class:`~isaaclab_physx.sim.schemas.PhysxFixedTendonPropertiesCfg`, + :class:`~isaaclab_physx.sim.schemas.PhysxSpatialTendonPropertiesCfg` + +**Code migration** + +Existing 2.x code continues to work via the deprecation aliases: + +.. code-block:: python + + # Isaac Lab 2.x — still works in 3.0 (emits DeprecationWarning, removed in 5.0) + import isaaclab.sim as sim_utils + rigid_props = sim_utils.RigidBodyPropertiesCfg(disable_gravity=True, linear_damping=0.1) + + # Isaac Lab 3.0 — recommended + from isaaclab_physx.sim.schemas import PhysxRigidBodyPropertiesCfg + rigid_props = PhysxRigidBodyPropertiesCfg(disable_gravity=True, linear_damping=0.1) + + # Isaac Lab 3.0 — backend-portable (only universal-physics fields) + from isaaclab.sim.schemas import RigidBodyBaseCfg + rigid_props = RigidBodyBaseCfg(rigid_body_enabled=True, disable_gravity=True) + +**Field renames on** ``JointDriveBaseCfg`` + +Two cfg fields were renamed so their snake_case names map identity-style to the +USD camelCase attribute names. Both old names are forwarded via +``__post_init__`` and emit ``DeprecationWarning`` (removed in 5.0). + +.. list-table:: + :header-rows: 1 + :widths: 35 35 30 + + * - Isaac Lab 2.x + - Isaac Lab 3.0 + - USD attribute (unchanged) + * - ``max_velocity`` + - ``max_joint_velocity`` + - ``physxJoint:maxJointVelocity`` + * - ``max_effort`` + - ``max_force`` + - ``drive::physics:maxForce`` + +.. code-block:: python + + # Both still work; new names recommended + sim_utils.JointDrivePropertiesCfg(max_effort=80.0, max_velocity=5.0) # 2.x + sim_utils.JointDrivePropertiesCfg(max_force=80.0, max_joint_velocity=5.0) # 3.0 + +**New Newton and MuJoCo cfg classes** + +For the Newton backend (and Newton's MuJoCo solver), new cfg classes are +available under :mod:`isaaclab_newton.sim.schemas`: + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Class + - Use case + * - :class:`~isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg` + - ``newton:contactMargin`` / ``newton:contactGap`` via ``NewtonCollisionAPI`` + * - :class:`~isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg` + - ``newton:maxHullVertices`` via ``NewtonMeshCollisionAPI`` + * - :class:`~isaaclab_newton.sim.schemas.NewtonMaterialPropertiesCfg` + - ``newton:torsionalFriction`` / ``newton:rollingFriction`` via ``NewtonMaterialAPI`` + * - :class:`~isaaclab_newton.sim.schemas.NewtonArticulationRootPropertiesCfg` + - ``newton:selfCollisionEnabled`` via ``NewtonArticulationRootAPI`` + * - :class:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg` + - ``mjc:gravcomp`` (body-level gravity compensation, MuJoCo solver only) + * - :class:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg` + - ``mjc:actuatorgravcomp`` via ``MjcJointAPI`` (joint-level routing) + +The MuJoCo cfgs subclass their Newton parent because MuJoCo is one of Newton's +solver options. + +For complete tables of which fields live on which class and where each lands in +USD, see :ref:`schema-cfgs`. + + Renaming of ``XformPrimView`` to ``FrameView`` ----------------------------------------------- diff --git a/docs/source/overview/core-concepts/index.rst b/docs/source/overview/core-concepts/index.rst index 10fdf8935fbc..052d7080eb67 100644 --- a/docs/source/overview/core-concepts/index.rst +++ b/docs/source/overview/core-concepts/index.rst @@ -8,6 +8,7 @@ This section we introduce core concepts in Isaac Lab. multi_backend_architecture + schema_cfgs task_workflows actuators sensors/index.rst diff --git a/docs/source/overview/core-concepts/schema_cfgs.rst b/docs/source/overview/core-concepts/schema_cfgs.rst new file mode 100644 index 000000000000..f0a752102e41 --- /dev/null +++ b/docs/source/overview/core-concepts/schema_cfgs.rst @@ -0,0 +1,299 @@ +.. _schema-cfgs: + +Schema Configuration Classes +============================ + +Isaac Lab's spawners author USD physics attributes onto prims via a layered set of +configuration classes. The layering separates **universal-physics** parameters +(honored by every backend) from **backend-specific** parameters (only meaningful +to one solver), so the same asset cfg can be authored once and target any backend +that supports it. + +This page explains the class hierarchy, when to use each tier, and how parameters +route to the underlying USD attributes. + +.. contents:: + :local: + :depth: 2 + +Class hierarchy +--------------- + +For each property group (rigid body, joint drive, collision, articulation root, +material, mesh collision), Isaac Lab defines a single base class in core +``isaaclab.sim.schemas`` and one subclass per backend in the corresponding +extension package: + +.. code-block:: text + + isaaclab.sim.schemas + ├── RigidBodyBaseCfg + │ ├── isaaclab_physx.sim.schemas.PhysxRigidBodyPropertiesCfg + │ └── isaaclab_newton.sim.schemas.NewtonRigidBodyPropertiesCfg + │ └── isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg + │ + ├── JointDriveBaseCfg + │ ├── isaaclab_physx.sim.schemas.PhysxJointDrivePropertiesCfg + │ └── isaaclab_newton.sim.schemas.NewtonJointDrivePropertiesCfg + │ └── isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg + │ + ├── CollisionBaseCfg + │ ├── isaaclab_physx.sim.schemas.PhysxCollisionPropertiesCfg + │ └── isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg + │ + ├── ArticulationRootBaseCfg + │ ├── isaaclab_physx.sim.schemas.PhysxArticulationRootPropertiesCfg + │ └── isaaclab_newton.sim.schemas.NewtonArticulationRootPropertiesCfg + │ + ├── MeshCollisionBaseCfg + │ ├── isaaclab_physx.sim.schemas.{PhysxConvexHull, PhysxConvexDecomposition, + │ │ PhysxTriangleMesh, PhysxSDFMesh, ...}PropertiesCfg + │ └── isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg + │ + └── isaaclab.sim.spawners.materials.RigidBodyMaterialBaseCfg + ├── isaaclab_physx.sim.spawners.materials.PhysxRigidBodyMaterialCfg + └── isaaclab_newton.sim.schemas.NewtonMaterialPropertiesCfg + +The hierarchy is **single-rooted per spawner slot**: every spawner has a single +field for each property group (``rigid_props``, ``joint_drive_props``, +``collision_props``, etc.), and Python's polymorphism allows any subclass to be +passed where the base type is expected. + +When to use which class +----------------------- + +The choice depends on which backends you target and which fields you need. + +**Use a base class** (``RigidBodyBaseCfg``, ``JointDriveBaseCfg``, etc.) + when you only need universal-physics fields and you want your asset cfg to be + backend-portable. Importing the base class does not pull in + :mod:`isaaclab_physx` or :mod:`isaaclab_newton`. + +**Use a PhysX subclass** (``PhysxRigidBodyPropertiesCfg``, etc.) + when your asset uses PhysX-specific knobs (per-body damping, TGS solver + iterations, sleep / stabilization thresholds, torsional patch friction, + compliant-contact materials, etc.) and you target the PhysX backend. Inherits + all base-class fields, so you can set both universal and PhysX fields on the + same instance. + +**Use a Newton subclass** (``NewtonRigidBodyPropertiesCfg``, etc.) + when you target Newton and need Newton-native attributes + (``newton:contactMargin``, ``newton:torsionalFriction``, + ``newton:selfCollisionEnabled``, etc.). The empty Newton base classes + (``NewtonRigidBodyPropertiesCfg``, ``NewtonJointDrivePropertiesCfg``) reserve + the ``newton:*`` namespace for future native fields and act as the parent for + solver-specific subclasses. + +**Use a MuJoCo subclass** (``MujocoRigidBodyPropertiesCfg``, ``MujocoJointDrivePropertiesCfg``) + when you specifically use Newton's **MuJoCo** solver and need MuJoCo-only + knobs (gravity compensation via ``mjc:gravcomp`` / + ``mjc:actuatorgravcomp``). Inherits from the Newton base, so + ``isinstance(cfg, NewtonRigidBodyPropertiesCfg)`` is True. + +What parameters live where +-------------------------- + +Universal physics (``physics:*`` namespace, ``UsdPhysics.*API``) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Lives on the **base class**. Every backend honors these. + +.. list-table:: + :header-rows: 1 + :widths: 30 35 35 + + * - Base class + - Field + - USD attribute + * - ``RigidBodyBaseCfg`` + - ``rigid_body_enabled``, ``kinematic_enabled`` + - ``physics:rigidBodyEnabled``, ``physics:kinematicEnabled`` + * - ``RigidBodyBaseCfg`` + - ``disable_gravity`` + - ``physxRigidBody:disableGravity`` (per-body on PhysX; scene-level partial honor on Newton) + * - ``CollisionBaseCfg`` + - ``collision_enabled`` + - ``physics:collisionEnabled`` + * - ``CollisionBaseCfg`` + - ``contact_offset``, ``rest_offset`` + - ``physxCollision:contactOffset``, ``physxCollision:restOffset`` (Newton consumes via PhysX bridge) + * - ``ArticulationRootBaseCfg`` + - ``articulation_enabled`` + - ``physxArticulation:articulationEnabled`` + * - ``ArticulationRootBaseCfg`` + - ``fix_root_link`` + - synthesizes ``UsdPhysics.FixedJoint`` (writer-side, not a USD attribute) + * - ``JointDriveBaseCfg`` + - ``drive_type``, ``max_force``, ``stiffness``, ``damping`` + - ``drive::physics:type/maxForce/stiffness/damping`` + * - ``JointDriveBaseCfg`` + - ``max_joint_velocity`` + - ``physxJoint:maxJointVelocity`` (sole USD path; Newton consumes via PhysX bridge today) + * - ``MassPropertiesCfg`` + - ``mass``, ``density`` + - ``physics:mass``, ``physics:density`` + * - ``RigidBodyMaterialBaseCfg`` + - ``static_friction``, ``dynamic_friction``, ``restitution`` + - ``physics:staticFriction``, ``physics:dynamicFriction``, ``physics:restitution`` + * - ``MeshCollisionBaseCfg`` + - ``mesh_approximation_name`` + - ``physics:approximation`` + +PhysX-specific (``physx*:*`` namespace, ``Physx*API`` schemas) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Lives on the PhysX subclass. Only authored when the user opts in by setting the +field on a PhysX cfg. + +.. list-table:: + :header-rows: 1 + :widths: 35 35 30 + + * - PhysX subclass + - Fields (selection) + - USD namespace / schema + * - ``PhysxRigidBodyPropertiesCfg`` + - ``linear_damping``, ``angular_damping``, ``max_linear_velocity``, ``max_angular_velocity``, ``solver_position_iteration_count``, ``sleep_threshold``, ``enable_gyroscopic_forces``, … + - ``physxRigidBody:*`` / ``PhysxRigidBodyAPI`` + * - ``PhysxJointDrivePropertiesCfg`` + - (currently empty; reserved for future PhysX-only drive knobs) + - ``physxJoint:*`` / ``PhysxJointAPI`` + * - ``PhysxCollisionPropertiesCfg`` + - ``torsional_patch_radius``, ``min_torsional_patch_radius`` + - ``physxCollision:*`` / ``PhysxCollisionAPI`` + * - ``PhysxArticulationRootPropertiesCfg`` + - ``enabled_self_collisions``, ``solver_position_iteration_count``, ``sleep_threshold``, ``stabilization_threshold`` + - ``physxArticulation:*`` / ``PhysxArticulationAPI`` + * - ``PhysxRigidBodyMaterialCfg`` + - ``compliant_contact_stiffness``, ``compliant_contact_damping``, ``friction_combine_mode``, ``restitution_combine_mode`` + - ``physxMaterial:*`` / ``PhysxMaterialAPI`` + * - ``PhysxConvexHullPropertiesCfg`` (and other mesh-cooking subclasses) + - ``hull_vertex_limit``, ``min_thickness``, … + - ``physxConvexHullCollision:*`` / ``PhysxConvexHullCollisionAPI`` + +Newton-targeted (``newton:*`` namespace, ``Newton*API`` schemas) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Lives on the Newton subclass. Authored only when the user opts in. + +.. list-table:: + :header-rows: 1 + :widths: 35 35 30 + + * - Newton subclass + - Fields + - USD namespace / schema + * - ``NewtonRigidBodyPropertiesCfg`` + - (empty — reserved for future Newton-native rigid-body fields) + - ``newton:*`` + * - ``NewtonJointDrivePropertiesCfg`` + - (empty — reserved for future Newton-native joint-drive fields) + - ``newton:*`` + * - ``NewtonCollisionPropertiesCfg`` + - ``contact_margin``, ``contact_gap`` + - ``newton:*`` / ``NewtonCollisionAPI`` + * - ``NewtonMeshCollisionPropertiesCfg`` + - ``max_hull_vertices`` + - ``newton:*`` / ``NewtonMeshCollisionAPI`` + * - ``NewtonMaterialPropertiesCfg`` + - ``torsional_friction``, ``rolling_friction`` + - ``newton:*`` / ``NewtonMaterialAPI`` + * - ``NewtonArticulationRootPropertiesCfg`` + - ``self_collision_enabled`` + - ``newton:*`` / ``NewtonArticulationRootAPI`` + +MuJoCo-solver-specific (``mjc:*`` namespace) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Lives on a MuJoCo subclass that extends a Newton subclass. Only consumed when +running Newton's MuJoCo solver. + +.. list-table:: + :header-rows: 1 + :widths: 35 25 40 + + * - MuJoCo subclass + - Field + - USD attribute / schema + * - ``MujocoRigidBodyPropertiesCfg`` + - ``gravcomp`` + - ``mjc:gravcomp`` (raw attribute, no applied schema) + * - ``MujocoJointDrivePropertiesCfg`` + - ``actuatorgravcomp`` + - ``mjc:actuatorgravcomp`` via ``MjcJointAPI`` + +Mixed-namespace authoring on a single instance +---------------------------------------------- + +Because each cfg field is routed to its **declaring class's** namespace (not +the instance's class), a subclass instance can author attributes across multiple +namespaces on the same prim. For example: + +.. code-block:: python + + from isaaclab_newton.sim.schemas import MujocoRigidBodyPropertiesCfg + + cfg = MujocoRigidBodyPropertiesCfg( + rigid_body_enabled=True, # declared on RigidBodyBaseCfg → physics:rigidBodyEnabled + disable_gravity=True, # declared on RigidBodyBaseCfg (exception) → physxRigidBody:disableGravity + gravcomp=1.0, # declared on MujocoRigidBodyPropertiesCfg → mjc:gravcomp + ) + +The writer applies each field to the namespace of the class where the field is +declared. The applied schemas (``PhysxRigidBodyAPI`` for ``disable_gravity``, +none for the Mjc raw attribute) are added only when the corresponding +fields are non-None. + +Spawner usage +------------- + +Spawners (``UsdFileCfg``, ``MeshCuboidCfg``, ``RigidObjectSpawnerCfg``, …) accept +the base class type for each slot and use polymorphism to dispatch to the +correct subclass at write time: + +.. code-block:: python + + import isaaclab.sim as sim_utils + from isaaclab_physx.sim.schemas import PhysxRigidBodyPropertiesCfg + from isaaclab_newton.sim.schemas import MujocoJointDrivePropertiesCfg + + spawn = sim_utils.UsdFileCfg( + usd_path="...", + rigid_props=PhysxRigidBodyPropertiesCfg(disable_gravity=True, linear_damping=0.1), + joint_drive_props=MujocoJointDrivePropertiesCfg( + drive_type="acceleration", + stiffness=10.0, + damping=0.1, + actuatorgravcomp=True, + ), + ) + +The spawner auto-enables body-level gravity compensation when joint-level +``actuatorgravcomp=True`` is requested but no MuJoCo rigid-body cfg is provided — +``actuatorgravcomp`` only routes forces and has no effect without body-level +``gravcomp``. + +Naming convention +----------------- + +Cfg field names use ``snake_case``; the writer converts them to ``camelCase`` +USD attribute names (``contact_margin`` → ``newton:contactMargin``). For +single-token fields (``gravcomp``, ``actuatorgravcomp``), the conversion is +identity, which matches MuJoCo's lowercase convention. + +Field renames preserve backward compatibility via deprecation aliases. Two such +aliases live on ``JointDriveBaseCfg`` today: + +* ``max_velocity`` → ``max_joint_velocity`` (USD attribute is ``physxJoint:maxJointVelocity``) +* ``max_effort`` → ``max_force`` (USD attribute is ``drive::physics:maxForce``) + +The aliases emit a ``DeprecationWarning`` at instantiation and are scheduled for +removal in 5.0. + +See also +-------- + +* :doc:`/source/migration/migrating_to_isaaclab_3-0` — migration guide +* :doc:`/source/api/lab/isaaclab.sim.schemas` — solver-common base class API +* :doc:`/source/api/lab_physx/isaaclab_physx.sim.schemas` — PhysX subclass API +* :doc:`/source/api/lab_newton/isaaclab_newton.sim.schemas` — Newton/MuJoCo subclass API From cc202e87966ef79b5ee733c496ebccc404da7799 Mon Sep 17 00:00:00 2001 From: Vidur Vij Date: Thu, 7 May 2026 20:18:54 -0700 Subject: [PATCH 6/6] Address tech writer review on schema cfg docs * Add 'Quick example' section near top of schema_cfgs.rst so the most common use case (MuJoCo gravity compensation) appears within the first screen. * Fix hierarchy diagram: NewtonMeshCollisionPropertiesCfg uses multiple inheritance (NewtonCollisionPropertiesCfg + MeshCollisionBaseCfg); annotate in the tree and add a paragraph framing it as the textbook MRO routing case. * Recategorize the 'Universal physics' table heading (was misleading because some base-class fields like disable_gravity route to physx*: namespaces via _usd_field_exceptions). Now titled 'Universal physics (declared on the base class)' with a clarifying lead paragraph. * Add ensure_drives_exist row to the base-class table. * Add :ref: anchor on Mixed-namespace section (schema-cfgs-mixed) for in-page links from earlier sections. * Add dedicated 'Gravity compensation (MuJoCo solver)' subsection (schema-cfgs-gravcomp anchor) explaining body- vs joint-level halves and documenting the spawner's auto-enable behavior. * Naming convention section now correctly describes the rename mechanism: old names remain as real dataclass fields (visible to dataclasses.fields()) and forward via __post_init__; documents the both-set collision behavior (canonical wins, alias value discarded). * Migration doc: add :ref: anchor (schemas-cfg-refactor) so other pages can link in. Fix the rename-section's misdescription of the alias mechanism. Fix the migration code example: the '3.0' line was using the deprecated JointDrivePropertiesCfg alias as if it were the recommended name; now uses JointDriveBaseCfg or PhysxJointDrivePropertiesCfg. * Migration doc: add the auto-enable foot-gun note with ref into the explainer. * Drop the abstract RigidObjectSpawnerCfg from the spawner-list ('used by abstract base, not instantiated by users'). --- .../migration/migrating_to_isaaclab_3-0.rst | 44 +++++++-- .../overview/core-concepts/schema_cfgs.rst | 96 ++++++++++++++++--- 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/docs/source/migration/migrating_to_isaaclab_3-0.rst b/docs/source/migration/migrating_to_isaaclab_3-0.rst index 7192a7c83b89..442c4d5415f1 100644 --- a/docs/source/migration/migrating_to_isaaclab_3-0.rst +++ b/docs/source/migration/migrating_to_isaaclab_3-0.rst @@ -98,6 +98,8 @@ The following classes have been moved to ``isaaclab_physx``: installation steps are required. +.. _schemas-cfg-refactor: + Schema Configuration Class Refactor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -166,8 +168,13 @@ Existing 2.x code continues to work via the deprecation aliases: **Field renames on** ``JointDriveBaseCfg`` Two cfg fields were renamed so their snake_case names map identity-style to the -USD camelCase attribute names. Both old names are forwarded via -``__post_init__`` and emit ``DeprecationWarning`` (removed in 5.0). +USD camelCase attribute names. The old names remain as deprecated dataclass +fields on :class:`~isaaclab.sim.schemas.JointDriveBaseCfg` (so +``dataclasses.fields()`` still sees them) and are forwarded to the new fields +in ``__post_init__`` with a ``DeprecationWarning``. Setting **both** the old +and new field on the same instance is silent — the canonical (new) field +wins; the old field's value is discarded after the warning. Both aliases are +scheduled for removal in 5.0. .. list-table:: :header-rows: 1 @@ -176,18 +183,28 @@ USD camelCase attribute names. Both old names are forwarded via * - Isaac Lab 2.x - Isaac Lab 3.0 - USD attribute (unchanged) - * - ``max_velocity`` - - ``max_joint_velocity`` + * - :attr:`~isaaclab.sim.schemas.JointDriveBaseCfg.max_velocity` + - :attr:`~isaaclab.sim.schemas.JointDriveBaseCfg.max_joint_velocity` - ``physxJoint:maxJointVelocity`` - * - ``max_effort`` - - ``max_force`` + * - :attr:`~isaaclab.sim.schemas.JointDriveBaseCfg.max_effort` + - :attr:`~isaaclab.sim.schemas.JointDriveBaseCfg.max_force` - ``drive::physics:maxForce`` .. code-block:: python - # Both still work; new names recommended - sim_utils.JointDrivePropertiesCfg(max_effort=80.0, max_velocity=5.0) # 2.x - sim_utils.JointDrivePropertiesCfg(max_force=80.0, max_joint_velocity=5.0) # 3.0 + # Both still work; new names recommended. + import isaaclab.sim as sim_utils + from isaaclab.sim.schemas import JointDriveBaseCfg + + # Isaac Lab 2.x style — JointDrivePropertiesCfg is now a deprecated alias + sim_utils.JointDrivePropertiesCfg(max_effort=80.0, max_velocity=5.0) + + # Isaac Lab 3.0 — backend-portable + JointDriveBaseCfg(max_force=80.0, max_joint_velocity=5.0) + + # Isaac Lab 3.0 — PhysX-targeted (with PhysX-only fields available) + from isaaclab_physx.sim.schemas import PhysxJointDrivePropertiesCfg + PhysxJointDrivePropertiesCfg(max_force=80.0, max_joint_velocity=5.0) **New Newton and MuJoCo cfg classes** @@ -216,6 +233,15 @@ available under :mod:`isaaclab_newton.sim.schemas`: The MuJoCo cfgs subclass their Newton parent because MuJoCo is one of Newton's solver options. +.. note:: + + Spawners auto-enable body-level gravity compensation when joint-level + ``actuatorgravcomp=True`` is requested but no Mujoco rigid-body cfg is + provided — without ``gravcomp`` on the bodies, ``actuatorgravcomp`` is a + no-op (no forces to route). To override, pass an explicit + ``MujocoRigidBodyPropertiesCfg`` in ``rigid_props``. See + :ref:`schema-cfgs-gravcomp` for details. + For complete tables of which fields live on which class and where each lands in USD, see :ref:`schema-cfgs`. diff --git a/docs/source/overview/core-concepts/schema_cfgs.rst b/docs/source/overview/core-concepts/schema_cfgs.rst index f0a752102e41..1051df1c4a48 100644 --- a/docs/source/overview/core-concepts/schema_cfgs.rst +++ b/docs/source/overview/core-concepts/schema_cfgs.rst @@ -5,17 +5,41 @@ Schema Configuration Classes Isaac Lab's spawners author USD physics attributes onto prims via a layered set of configuration classes. The layering separates **universal-physics** parameters -(honored by every backend) from **backend-specific** parameters (only meaningful -to one solver), so the same asset cfg can be authored once and target any backend -that supports it. +from **backend-specific** parameters, so the same asset cfg can be authored once +and target any backend that supports it. This page explains the class hierarchy, when to use each tier, and how parameters route to the underlying USD attributes. +Migrating from 2.x? See :ref:`schemas-cfg-refactor` in the 3.0 migration guide. + .. contents:: :local: :depth: 2 +Quick example +------------- + +Add MuJoCo (MJC) gravity compensation to an articulated asset: + +.. code-block:: python + + import isaaclab.sim as sim_utils + from isaaclab_newton.sim.schemas import ( + MujocoRigidBodyPropertiesCfg, + MujocoJointDrivePropertiesCfg, + ) + + spawn = sim_utils.UsdFileCfg( + usd_path=f"{ISAAC_NUCLEUS_DIR}/Robots/Franka/franka_instanceable.usd", + rigid_props=MujocoRigidBodyPropertiesCfg(gravcomp=1.0), + joint_drive_props=MujocoJointDrivePropertiesCfg(actuatorgravcomp=True), + ) + +The Mujoco-specific fields land under ``mjc:*`` on the prim; any +``RigidBodyBaseCfg`` / ``JointDriveBaseCfg`` fields you set on the same instance +land under ``physics:*``. See :ref:`schema-cfgs-mixed` for the full routing rules. + Class hierarchy --------------- @@ -49,11 +73,21 @@ extension package: │ ├── isaaclab_physx.sim.schemas.{PhysxConvexHull, PhysxConvexDecomposition, │ │ PhysxTriangleMesh, PhysxSDFMesh, ...}PropertiesCfg │ └── isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg + │ (also inherits NewtonCollisionPropertiesCfg — multi-namespace) │ └── isaaclab.sim.spawners.materials.RigidBodyMaterialBaseCfg ├── isaaclab_physx.sim.spawners.materials.PhysxRigidBodyMaterialCfg └── isaaclab_newton.sim.schemas.NewtonMaterialPropertiesCfg +:class:`~isaaclab_newton.sim.schemas.NewtonMeshCollisionPropertiesCfg` uses +multiple inheritance: it extends both +:class:`~isaaclab_newton.sim.schemas.NewtonCollisionPropertiesCfg` (for +``contact_margin`` / ``contact_gap``) and +:class:`~isaaclab.sim.schemas.MeshCollisionBaseCfg` (for +``mesh_approximation_name``). This is the textbook case for the per-declaring- +class MRO routing described under :ref:`schema-cfgs-mixed` — each inherited +field is written under the namespace of the class that declared it. + The hierarchy is **single-rooted per spawner slot**: every spawner has a single field for each property group (``rigid_props``, ``joint_drive_props``, ``collision_props``, etc.), and Python's polymorphism allows any subclass to be @@ -93,10 +127,16 @@ The choice depends on which backends you target and which fields you need. What parameters live where -------------------------- -Universal physics (``physics:*`` namespace, ``UsdPhysics.*API``) +Universal physics (declared on the base class) """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Lives on the **base class**. Every backend honors these. +Lives on the **base class**. Most fields write to ``physics:*`` (the standard +``UsdPhysics.*API`` namespace), but a small set of "exception" fields are +declared on the base for backend-portability yet route to a non-``physics:*`` +namespace because that is the only USD path honored today (e.g., +``disable_gravity`` writes ``physxRigidBody:disableGravity`` because both PhysX +and Newton's importer consume the PhysX attribute). The "USD attribute" column +below is the actual emitted attribute, not the namespace family. .. list-table:: :header-rows: 1 @@ -129,6 +169,11 @@ Lives on the **base class**. Every backend honors these. * - ``JointDriveBaseCfg`` - ``max_joint_velocity`` - ``physxJoint:maxJointVelocity`` (sole USD path; Newton consumes via PhysX bridge today) + * - ``JointDriveBaseCfg`` + - ``ensure_drives_exist`` + - writer-side only — when ``True``, ensures any drive with ``stiffness=0`` and + ``damping=0`` gets a minimal ``stiffness=1e-3`` so backends like Newton recognize + the joint as actively driven; not a USD attribute on its own * - ``MassPropertiesCfg`` - ``mass``, ``density`` - ``physics:mass``, ``physics:density`` @@ -222,6 +267,8 @@ running Newton's MuJoCo solver. - ``actuatorgravcomp`` - ``mjc:actuatorgravcomp`` via ``MjcJointAPI`` +.. _schema-cfgs-mixed: + Mixed-namespace authoring on a single instance ---------------------------------------------- @@ -247,7 +294,7 @@ fields are non-None. Spawner usage ------------- -Spawners (``UsdFileCfg``, ``MeshCuboidCfg``, ``RigidObjectSpawnerCfg``, …) accept +Spawners (``UsdFileCfg``, ``MeshCuboidCfg``, ``MeshSphereCfg``, …) accept the base class type for each slot and use polymorphism to dispatch to the correct subclass at write time: @@ -268,10 +315,30 @@ correct subclass at write time: ), ) -The spawner auto-enables body-level gravity compensation when joint-level -``actuatorgravcomp=True`` is requested but no MuJoCo rigid-body cfg is provided — -``actuatorgravcomp`` only routes forces and has no effect without body-level -``gravcomp``. +.. _schema-cfgs-gravcomp: + +Gravity compensation (MuJoCo solver) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Gravity compensation has two halves and you typically need both: + +* **Body-level**: + :attr:`~isaaclab_newton.sim.schemas.MujocoRigidBodyPropertiesCfg.gravcomp` + on each rigid body (writes ``mjc:gravcomp``). This is what *computes* the + compensation force. +* **Joint-level**: + :attr:`~isaaclab_newton.sim.schemas.MujocoJointDrivePropertiesCfg.actuatorgravcomp` + on each joint (writes ``mjc:actuatorgravcomp``). This routes the compensation + force through the actuator channel (``qfrc_actuator``) so it counts against + ``actuatorfrcrange``; otherwise it goes to ``qfrc_passive``. + +``actuatorgravcomp=True`` alone is a no-op — without body-level ``gravcomp`` +there are no forces to route. To prevent this footgun, the spawner +**auto-enables** ``MujocoRigidBodyPropertiesCfg(gravcomp=1.0)`` whenever +``joint_drive_props`` is a Mujoco cfg with ``actuatorgravcomp=True`` and +``rigid_props`` is not already a Mujoco cfg. If you want a different +``gravcomp`` value (or want to disable the auto-enable), pass an explicit +``MujocoRigidBodyPropertiesCfg`` in ``rigid_props``. Naming convention ----------------- @@ -287,8 +354,13 @@ aliases live on ``JointDriveBaseCfg`` today: * ``max_velocity`` → ``max_joint_velocity`` (USD attribute is ``physxJoint:maxJointVelocity``) * ``max_effort`` → ``max_force`` (USD attribute is ``drive::physics:maxForce``) -The aliases emit a ``DeprecationWarning`` at instantiation and are scheduled for -removal in 5.0. +The old names remain as real dataclass fields (so ``dataclasses.fields()`` +sees them), defaulting to ``None``. ``__post_init__`` runs +``_deprecate_field_alias`` which, when the old field is set: emits a +``DeprecationWarning``, copies the value into the canonical field if the +canonical is ``None``, then nulls the old field. Setting **both** in the same +constructor is silent — the canonical wins; the old name's value is discarded. +Both aliases are scheduled for removal in 5.0. See also --------