From 0d215182f2af559779251e15ff125d5df1bd88f4 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 19:12:55 +0200 Subject: [PATCH 01/24] Add flat Franka asset and backend body-resolution support --- ...aximiliank-direct-body-prim-resolution.rst | 4 + source/isaaclab/isaaclab/sim/utils/queries.py | 8 ++ source/isaaclab/test/sim/test_cloner.py | 8 ++ .../maximiliank-franka-flat-config.minor.rst | 14 ++ .../isaaclab_assets/__init__.pyi | 6 + .../isaaclab_assets/robots/__init__.pyi | 6 + .../isaaclab_assets/robots/franka.py | 124 +++++++++++++++--- .../test/test_valid_configs.py | 20 +++ ...miliank-franka-material-body-selection.rst | 4 + .../assets/articulation/articulation.py | 8 +- .../isaaclab_newton/envs/mdp/events.py | 10 +- .../test/assets/test_articulation.py | 52 ++++---- ...iliank-frame-transformer-nested-bodies.rst | 5 + .../frame_transformer/frame_transformer.py | 10 +- .../test/assets/test_articulation.py | 34 ++++- .../test/sensors/test_frame_transformer.py | 42 ++++++ ...iliank-frame-transformer-nested-bodies.rst | 5 + .../frame_transformer/frame_transformer.py | 12 +- .../test/assets/test_articulation.py | 26 ++-- .../test/sensors/test_frame_transformer.py | 39 ++++++ 20 files changed, 360 insertions(+), 77 deletions(-) create mode 100644 source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst create mode 100644 source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst create mode 100644 source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst create mode 100644 source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst create mode 100644 source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst diff --git a/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst new file mode 100644 index 000000000000..4ead32834c86 --- /dev/null +++ b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst @@ -0,0 +1,4 @@ +Fixed +^^^^^ + +* Fixed direct rigid-body path queries so nested rigid-body descendants are not selected when the requested body matches. diff --git a/source/isaaclab/isaaclab/sim/utils/queries.py b/source/isaaclab/isaaclab/sim/utils/queries.py index 0994b049c44c..b73ae060289a 100644 --- a/source/isaaclab/isaaclab/sim/utils/queries.py +++ b/source/isaaclab/isaaclab/sim/utils/queries.py @@ -387,6 +387,7 @@ def resolve_matching_prims_from_source( env_regex_ns: str = "/World/envs/env_[^/]+", raise_if_no_matches: bool = True, traverse_instance_prims: bool = True, + prefer_direct_matches: bool = False, ) -> list[tuple[Usd.Prim, str]]: """Resolve matching prims from a single(source) instance when multiple instances are present. @@ -402,6 +403,8 @@ def resolve_matching_prims_from_source( env_regex_ns: Namespace pattern that marks one instance root when no clone plan applies. raise_if_no_matches: Whether to raise if no prim matches ``path_expr``. Defaults to True. traverse_instance_prims: Whether to traverse instance prims when applying ``predicate``. + prefer_direct_matches: Prefer matching prims named by ``path_expr`` over their matching descendants. + Descendants remain a fallback when no direct prim satisfies ``predicate``. Returns: A list of ``(source_prim, destination_expr)`` pairs. Empty only when @@ -481,6 +484,11 @@ def resolve_matching_prims_from_source( unique_matches.setdefault(child_path, (child, dest + child_path[len(source_path) :])) results = list(unique_matches.values()) + if prefer_direct_matches: + direct_matches = [pair for pair in results if re.fullmatch(path_expr, pair[0].GetPath().pathString)] + if direct_matches: + results = direct_matches + if expected_num_matches is not None and len(results) != expected_num_matches: raise RuntimeError(f"Expected {expected_num_matches} prims at '{path_expr}', found {len(results)}.") if raise_if_no_matches and not results: diff --git a/source/isaaclab/test/sim/test_cloner.py b/source/isaaclab/test/sim/test_cloner.py index 51bfc38077f8..7ea2acef280c 100644 --- a/source/isaaclab/test/sim/test_cloner.py +++ b/source/isaaclab/test/sim/test_cloner.py @@ -285,3 +285,11 @@ def test_resolve_matching_prims_from_source(sim, with_clone_plan): "/World/envs/env_[^/]+/Robot/foo/bar", "/World/envs/env_[^/]+/Robot/other/bar", ] + + matches = queries.resolve_matching_prims_from_source( + r"/World/envs/env_[^/]+/Robot/foo", + predicate=lambda prim: prim.GetName() in {"foo", "bar"}, + expected_num_matches=1, + prefer_direct_matches=True, + ) + assert [prim.GetPath().pathString for prim, _ in matches] == ["/World/envs/env_0/Robot/foo"] diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst new file mode 100644 index 000000000000..6618848f9c25 --- /dev/null +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst @@ -0,0 +1,14 @@ +Added +^^^^^ + +* Added ``FRANKA_PANDA_FLAT_CFG`` and ``FRANKA_PANDA_FLAT_HIGH_PD_CFG`` for the shared flat Franka + asset. These configurations selected gripper-only colliders and the ``panda_arm`` actuator group; + select the ``Physics`` variant for the target backend. + +Deprecated +^^^^^^^^^^ + +* Deprecated ``FRANKA_PANDA_CFG``, ``FRANKA_PANDA_HIGH_PD_CFG``, and + ``FRANKA_PANDA_MENAGERIE_CFG``. Their previous asset and actuator contracts remained available + during the deprecation window. Use the corresponding ``FRANKA_PANDA_FLAT_*`` configuration to + migrate to the shared flat asset, and replace shoulder/forearm actuator overrides with ``panda_arm``. diff --git a/source/isaaclab_assets/isaaclab_assets/__init__.pyi b/source/isaaclab_assets/isaaclab_assets/__init__.pyi index 2c491a499d7d..b38edb800a5f 100644 --- a/source/isaaclab_assets/isaaclab_assets/__init__.pyi +++ b/source/isaaclab_assets/isaaclab_assets/__init__.pyi @@ -22,7 +22,10 @@ __all__ = [ "GR1T2_CFG", "GR1T2_HIGH_PD_CFG", "FRANKA_PANDA_CFG", + "FRANKA_PANDA_FLAT_CFG", + "FRANKA_PANDA_FLAT_HIGH_PD_CFG", "FRANKA_PANDA_HIGH_PD_CFG", + "FRANKA_PANDA_LEGACY_CFG", "FRANKA_PANDA_MENAGERIE_CFG", "FRANKA_ROBOTIQ_GRIPPER_CFG", "FOURBAR_POLE_CFG", @@ -89,7 +92,10 @@ from .robots import ( GR1T2_CFG, GR1T2_HIGH_PD_CFG, FRANKA_PANDA_CFG, + FRANKA_PANDA_FLAT_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_LEGACY_CFG, FRANKA_PANDA_MENAGERIE_CFG, FRANKA_ROBOTIQ_GRIPPER_CFG, FOURBAR_POLE_CFG, diff --git a/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi b/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi index 023c8e801230..e54481a15ee5 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi +++ b/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi @@ -22,7 +22,10 @@ __all__ = [ "GR1T2_CFG", "GR1T2_HIGH_PD_CFG", "FRANKA_PANDA_CFG", + "FRANKA_PANDA_FLAT_CFG", + "FRANKA_PANDA_FLAT_HIGH_PD_CFG", "FRANKA_PANDA_HIGH_PD_CFG", + "FRANKA_PANDA_LEGACY_CFG", "FRANKA_PANDA_MENAGERIE_CFG", "FRANKA_ROBOTIQ_GRIPPER_CFG", "FOURBAR_POLE_CFG", @@ -82,7 +85,10 @@ from .cassie import CASSIE_CFG from .fourier import GR1T2_CFG, GR1T2_HIGH_PD_CFG from .franka import ( FRANKA_PANDA_CFG, + FRANKA_PANDA_FLAT_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_LEGACY_CFG, FRANKA_PANDA_MENAGERIE_CFG, FRANKA_ROBOTIQ_GRIPPER_CFG, ) diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index c8749fab4fdd..11849e12b234 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -7,14 +7,23 @@ The following configurations are available: -* :obj:`FRANKA_PANDA_CFG`: Franka Emika Panda robot with Panda hand -* :obj:`FRANKA_PANDA_MENAGERIE_CFG`: Franka Emika Panda robot converted from MuJoCo Menagerie -* :obj:`FRANKA_PANDA_HIGH_PD_CFG`: Franka Emika Panda robot with Panda hand with stiffer PD control +* :obj:`FRANKA_PANDA_FLAT_CFG`: Shared flat asset for maintained Franka tasks +* :obj:`FRANKA_PANDA_FLAT_HIGH_PD_CFG`: Flat asset with stiffer PD control +* :obj:`FRANKA_PANDA_LEGACY_CFG`: Legacy Franka Emika Panda asset configuration +* :obj:`FRANKA_PANDA_CFG`: Deprecated alias retaining the legacy asset and actuators +* :obj:`FRANKA_PANDA_HIGH_PD_CFG`: Deprecated legacy high-PD configuration +* :obj:`FRANKA_PANDA_MENAGERIE_CFG`: Deprecated nested-instance Menagerie configuration * :obj:`FRANKA_ROBOTIQ_GRIPPER_CFG`: Franka robot with Robotiq_2f_85 gripper +The old public names retain their original configuration contracts for the deprecation window. Use +``FRANKA_PANDA_FLAT_CFG`` for new code and select its ``Physics`` variant for the chosen backend. + Reference: https://github.com/frankaemika/franka_ros """ +import warnings +from typing import TYPE_CHECKING + from isaaclab_newton.sim.schemas import NewtonArticulationCfg from isaaclab_physx.sim.schemas import PhysxArticulationCfg, PhysxRigidBodyCfg @@ -28,7 +37,7 @@ # Configuration ## -FRANKA_PANDA_CFG = ArticulationCfg( +FRANKA_PANDA_LEGACY_CFG = ArticulationCfg( spawn=sim_utils.UsdFileCfg( usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/Legacy/panda_instanceable.usd", activate_contact_sensors=False, @@ -77,45 +86,120 @@ }, soft_joint_pos_limit_factor=1.0, ) -"""Configuration of Franka Emika Panda robot.""" +"""Configuration of the legacy Franka Emika Panda robot asset.""" -FRANKA_PANDA_MENAGERIE_CFG = clone(FRANKA_PANDA_CFG) -FRANKA_PANDA_MENAGERIE_CFG.spawn.usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda" -FRANKA_PANDA_MENAGERIE_CFG.actuators = { +FRANKA_PANDA_FLAT_CFG = clone(FRANKA_PANDA_LEGACY_CFG) +FRANKA_PANDA_FLAT_CFG.spawn.usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda" +FRANKA_PANDA_FLAT_CFG.spawn.variants = {"Physics": "physx", "Colliders": "gripper_only"} +next( + props for props in FRANKA_PANDA_FLAT_CFG.spawn.articulation_props if isinstance(props, PhysxArticulationCfg) +).enabled_self_collisions = False +next( + props for props in FRANKA_PANDA_FLAT_CFG.spawn.articulation_props if isinstance(props, NewtonArticulationCfg) +).self_collision_enabled = False +FRANKA_PANDA_FLAT_CFG.actuators = { "panda_arm": ImplicitActuatorCfg( joint_names_expr=["panda_joint[1-7]"], + joint_effort_limit={"panda_joint[1-4]": 100.0, "panda_joint[5-7]": 12.0}, joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, stiffness=None, damping=None, + viscous_friction=0.0, ), "panda_hand": ImplicitActuatorCfg( - joint_names_expr=["panda_finger_joint.*"], + joint_names_expr=["panda_finger_joint1"], + joint_effort_limit=200.0, stiffness=None, damping=None, + viscous_friction=0.0, + ), + "panda_finger2_passive": ImplicitActuatorCfg( + joint_names_expr=["panda_finger_joint2"], + joint_effort_limit=200.0, + stiffness=0.0, + damping=0.0, + viscous_friction=0.0, ), } -"""Configuration of the MuJoCo Menagerie-derived Franka Emika Panda robot. +"""Configuration of the Franka Emika Panda robot. -The converted model has different inertial and drive authoring from the legacy asset used by -:attr:`FRANKA_PANDA_CFG`. The solver velocity limits provide consistent behavior across physics -backends, while the arm and hand retain their USD-authored drives. +The flat asset contains PhysX and MuJoCo physics variants and gripper-only, primitive, and convex-hull +collider variants. The gripper-only collider variant is the default. Explicit solver properties keep +the actuator contract consistent across physics payloads. Only the leading finger has an active drive; +the authored mimic constraint moves the passive follower. The standalone configuration selects the PhysX +payload by default; direct Newton consumers must select the ``mujoco`` physics variant explicitly. """ -FRANKA_PANDA_HIGH_PD_CFG = clone(FRANKA_PANDA_CFG) -FRANKA_PANDA_HIGH_PD_CFG.spawn.rigid_props.disable_gravity = True -FRANKA_PANDA_HIGH_PD_CFG.actuators["panda_shoulder"].stiffness = 400.0 -FRANKA_PANDA_HIGH_PD_CFG.actuators["panda_shoulder"].damping = 80.0 -FRANKA_PANDA_HIGH_PD_CFG.actuators["panda_forearm"].stiffness = 400.0 -FRANKA_PANDA_HIGH_PD_CFG.actuators["panda_forearm"].damping = 80.0 +FRANKA_PANDA_FLAT_HIGH_PD_CFG = clone(FRANKA_PANDA_FLAT_CFG) +FRANKA_PANDA_FLAT_HIGH_PD_CFG.spawn.rigid_props.disable_gravity = True +FRANKA_PANDA_FLAT_HIGH_PD_CFG.actuators["panda_arm"].stiffness = 400.0 +FRANKA_PANDA_FLAT_HIGH_PD_CFG.actuators["panda_arm"].damping = 80.0 """Configuration of Franka Emika Panda robot with stiffer PD control. This configuration is useful for task-space control using differential IK. """ -FRANKA_ROBOTIQ_GRIPPER_CFG = clone(FRANKA_PANDA_CFG) +_FRANKA_PANDA_COMPAT_CFG = clone(FRANKA_PANDA_LEGACY_CFG) + + +_FRANKA_PANDA_LEGACY_HIGH_PD_CFG = clone(FRANKA_PANDA_LEGACY_CFG) +_FRANKA_PANDA_LEGACY_HIGH_PD_CFG.spawn.rigid_props.disable_gravity = True +for actuator in ("panda_shoulder", "panda_forearm"): + _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].stiffness = 400.0 + _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].damping = 80.0 + + +_FRANKA_PANDA_NESTED_MENAGERIE_CFG = clone(FRANKA_PANDA_LEGACY_CFG) +_FRANKA_PANDA_NESTED_MENAGERIE_CFG.spawn.usd_path = ( + f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda_nestedInstance.usda" +) +_FRANKA_PANDA_NESTED_MENAGERIE_CFG.actuators = { + "panda_arm": ImplicitActuatorCfg( + joint_names_expr=["panda_joint[1-7]"], + joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, + stiffness=None, + damping=None, + ), + "panda_hand": ImplicitActuatorCfg( + joint_names_expr=["panda_finger_joint.*"], + stiffness=None, + damping=None, + ), +} + + +_DEPRECATED_FRANKA_CFGS = { + "FRANKA_PANDA_CFG": (_FRANKA_PANDA_COMPAT_CFG, "FRANKA_PANDA_FLAT_CFG"), + "FRANKA_PANDA_HIGH_PD_CFG": (_FRANKA_PANDA_LEGACY_HIGH_PD_CFG, "FRANKA_PANDA_FLAT_HIGH_PD_CFG"), + "FRANKA_PANDA_MENAGERIE_CFG": (_FRANKA_PANDA_NESTED_MENAGERIE_CFG, "FRANKA_PANDA_FLAT_CFG"), +} + +if TYPE_CHECKING: + FRANKA_PANDA_CFG: ArticulationCfg + FRANKA_PANDA_HIGH_PD_CFG: ArticulationCfg + FRANKA_PANDA_MENAGERIE_CFG: ArticulationCfg + + +def __getattr__(name: str) -> ArticulationCfg: + if name not in _DEPRECATED_FRANKA_CFGS: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + cfg, replacement = _DEPRECATED_FRANKA_CFGS[name] + warnings.warn( + f"{name} is deprecated; use {replacement} for the flat Franka asset.", + FutureWarning, + stacklevel=2, + ) + return cfg + + +def __dir__() -> list[str]: + return sorted(set(globals()) | _DEPRECATED_FRANKA_CFGS.keys()) + + +FRANKA_ROBOTIQ_GRIPPER_CFG = clone(FRANKA_PANDA_LEGACY_CFG) FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.usd_path = f"{ISAAC_NUCLEUS_DIR}/Robots/FrankaRobotics/FrankaPanda/franka.usd" FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.variants = {"Gripper": "Robotiq_2F_85"} FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.rigid_props.disable_gravity = True diff --git a/source/isaaclab_assets/test/test_valid_configs.py b/source/isaaclab_assets/test/test_valid_configs.py index 3832e196def1..b267e4862bd4 100644 --- a/source/isaaclab_assets/test/test_valid_configs.py +++ b/source/isaaclab_assets/test/test_valid_configs.py @@ -19,6 +19,26 @@ from isaaclab.test.utils import DeviceScope, test_devices import isaaclab_assets as lab_assets # noqa: F401 +import isaaclab_assets.robots.franka as franka_assets + + +def test_franka_legacy_configs_warn_and_keep_their_contract() -> None: + """Deprecated Franka names retain their previous asset and actuator contracts.""" + with pytest.warns(FutureWarning, match="FRANKA_PANDA_CFG.*deprecated"): + legacy_cfg = franka_assets.FRANKA_PANDA_CFG + assert legacy_cfg.spawn.usd_path.endswith("/Legacy/panda_instanceable.usd") + assert set(legacy_cfg.actuators) == {"panda_shoulder", "panda_forearm", "panda_hand"} + + with pytest.warns(FutureWarning, match="FRANKA_PANDA_HIGH_PD_CFG.*deprecated"): + high_pd_cfg = franka_assets.FRANKA_PANDA_HIGH_PD_CFG + assert high_pd_cfg.spawn.usd_path == legacy_cfg.spawn.usd_path + assert high_pd_cfg.actuators["panda_shoulder"].stiffness == 400.0 + assert high_pd_cfg.actuators["panda_forearm"].stiffness == 400.0 + + with pytest.warns(FutureWarning, match="FRANKA_PANDA_MENAGERIE_CFG.*deprecated"): + menagerie_cfg = franka_assets.FRANKA_PANDA_MENAGERIE_CFG + assert menagerie_cfg.spawn.usd_path.endswith("/franka_panda_nestedInstance.usda") + assert set(menagerie_cfg.actuators) == {"panda_arm", "panda_hand"} @pytest.fixture(scope="module") diff --git a/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst b/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst new file mode 100644 index 000000000000..f3763ed81629 --- /dev/null +++ b/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst @@ -0,0 +1,4 @@ +Fixed +^^^^^ + +* Fixed Newton articulation material randomization for bodies whose shapes are interleaved in the native shape array. diff --git a/source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py b/source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py index e905d1adb0e7..66d8c4bb07d1 100644 --- a/source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py +++ b/source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py @@ -271,7 +271,7 @@ def num_bodies(self) -> int: @property def num_shapes_per_body(self) -> list[int]: - """Number of collision shapes per body in public body-name order. + """Number of shapes per body in public body-name order. Each element corresponds to the body at the same index in :attr:`body_names`. Backend-order counts are cached; a nonidentity body @@ -287,11 +287,11 @@ def num_shapes_per_body(self) -> list[int]: @property def backend_num_shapes_per_body(self) -> list[int]: - """Number of collision shapes per body in active backend solver-view order. + """Number of shapes per body in active backend solver-view order. Each element corresponds to the body at the same index in - :attr:`backend_body_names`, matching the shape axis of the backend - solver arrays. The counts are cached on first access. Use + :attr:`backend_body_names`. Shapes belonging to one body need not be + contiguous in the backend shape arrays. The counts are cached on first access. Use :attr:`num_shapes_per_body` for public body order. Returns: diff --git a/source/isaaclab_newton/isaaclab_newton/envs/mdp/events.py b/source/isaaclab_newton/isaaclab_newton/envs/mdp/events.py index e7c5faa973af..4724037e0869 100644 --- a/source/isaaclab_newton/isaaclab_newton/envs/mdp/events.py +++ b/source/isaaclab_newton/isaaclab_newton/envs/mdp/events.py @@ -63,14 +63,10 @@ def __init__(self, cfg: EventTermCfg, env: ManagerBasedEnv) -> None: self._restitution_binding = asset._root_view.get_attribute("shape_material_restitution", model)[:, 0] # type: ignore if isinstance(asset, assets.Articulation) and asset_cfg.body_ids != slice(None): - # Shape counts use backend body order. - num_shapes_per_body = asset.backend_num_shapes_per_body - shape_indices_list = [] backend_body_ids = asset.map_body_ids_to_backend(asset_cfg.body_ids) - for body_id in backend_body_ids: - start_idx = sum(num_shapes_per_body[:body_id]) - end_idx = start_idx + num_shapes_per_body[body_id] - shape_indices_list.extend(range(start_idx, end_idx)) + shape_indices_list = [ + shape for body_id in backend_body_ids for shape in asset.root_view.body_shapes[body_id] + ] self._shape_indices = torch.tensor(shape_indices_list, dtype=torch.long) else: self._shape_indices = torch.arange(self._friction_binding.shape[1], dtype=torch.long) diff --git a/source/isaaclab_newton/test/assets/test_articulation.py b/source/isaaclab_newton/test/assets/test_articulation.py index f0f4b5da6dbc..9cc6e1787eac 100644 --- a/source/isaaclab_newton/test/assets/test_articulation.py +++ b/source/isaaclab_newton/test/assets/test_articulation.py @@ -66,9 +66,14 @@ ## # Pre-defined configs ## -from isaaclab_assets import ANYMAL_C_CFG, FRANKA_PANDA_CFG, FRANKA_PANDA_HIGH_PD_CFG # isort:skip +from isaaclab_assets import ANYMAL_C_CFG, FRANKA_PANDA_FLAT_CFG, FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort:skip from isaaclab_assets.robots.shadow_hand import SHADOW_HAND_NEWTON_CFG +_FRANKA_PANDA_NEWTON_CFG = FRANKA_PANDA_FLAT_CFG.copy() +_FRANKA_PANDA_NEWTON_CFG.spawn.variants = {"Physics": "mujoco", "Colliders": "gripper_only"} +_FRANKA_PANDA_HIGH_PD_NEWTON_CFG = FRANKA_PANDA_FLAT_HIGH_PD_CFG.copy() +_FRANKA_PANDA_HIGH_PD_NEWTON_CFG.spawn.variants = {"Physics": "mujoco", "Colliders": "gripper_only"} + SIM_CFGs = { "humanoid": SimulationCfg( physics=NewtonCfg( @@ -227,7 +232,7 @@ def generate_articulation_cfg( actuators={"body": ImplicitActuatorCfg(joint_names_expr=[".*"], stiffness=stiffness, damping=damping)}, ) elif articulation_type == "panda": - articulation_cfg = FRANKA_PANDA_CFG + articulation_cfg = _FRANKA_PANDA_NEWTON_CFG elif articulation_type == "anymal": articulation_cfg = ANYMAL_C_CFG elif articulation_type == "shadow_hand": @@ -438,7 +443,7 @@ def generate_articulation( def _setup_franka_at_home_pose(sim, *, zero_actuator_pd: bool = False, disable_gravity: bool = True): """Build a Franka articulation at its configured home pose. - Constructs :data:`FRANKA_PANDA_HIGH_PD_CFG`, optionally zeroes the + Constructs :data:`_FRANKA_PANDA_HIGH_PD_NEWTON_CFG`, optionally zeroes the arm-actuator PD gains, resets the simulator, and teleports the arm joints to :attr:`default_joint_pos` (the env reset path that normally does this is not invoked for standalone tests, so the @@ -447,23 +452,21 @@ def _setup_franka_at_home_pose(sim, *, zero_actuator_pd: bool = False, disable_g Args: sim: The simulation context to use. - zero_actuator_pd: If True, sets the panda_shoulder/panda_forearm - actuator stiffness and damping to zero. Used by the OSC test + zero_actuator_pd: If True, sets the ``panda_arm`` actuator stiffness + and damping to zero. Used by the OSC test so OSC's joint-effort output is not opposed by the implicit-PD's residual ``kp·(target − q)``. disable_gravity: Per-body gravity flag written to the spawn config. - :data:`FRANKA_PANDA_HIGH_PD_CFG` ships with gravity disabled; + :data:`_FRANKA_PANDA_HIGH_PD_NEWTON_CFG` ships with gravity disabled; pass False for tests where the arm must feel scene gravity. Returns: Tuple of ``(robot, ee_frame_idx, ee_jacobi_idx, arm_joint_ids)``. """ - cfg = replace(clone(FRANKA_PANDA_HIGH_PD_CFG), prim_path="/World/Env_[^/]*/Robot") + cfg = replace(_FRANKA_PANDA_HIGH_PD_NEWTON_CFG, prim_path="/World/Env_[^/]*/Robot") if zero_actuator_pd: - cfg.actuators["panda_shoulder"].stiffness = 0.0 - cfg.actuators["panda_shoulder"].damping = 0.0 - cfg.actuators["panda_forearm"].stiffness = 0.0 - cfg.actuators["panda_forearm"].damping = 0.0 + cfg.actuators["panda_arm"].stiffness = 0.0 + cfg.actuators["panda_arm"].damping = 0.0 cfg.spawn.rigid_props.disable_gravity = disable_gravity sim_utils.create_prim("/World/Env_0", "Xform", translation=(0.0, 0.0, 0.0)) clone_plan_from_env_0(CloneCfg(clone_template="/World/Env_{}"), (cfg,), 1, 0.0) @@ -1738,7 +1741,6 @@ def test_out_of_range_default_joint_state(sim, device, articulation_type, state_ quantity = "positions" if state_field == "joint_pos" else "velocities" replicate(sim.get_clone_plan()) with pytest.raises(ValueError, match=f"default {quantity} out of the limits"): - replicate(sim.get_clone_plan()) sim.reset() @@ -2511,29 +2513,31 @@ def test_write_joint_viscous_friction_to_sim(sim, num_articulations, device, art Static joint friction writes also propagate directly to the Newton model. """ - articulation_cfg = generate_articulation_cfg(articulation_type) - articulation_cfg.actuators["panda_shoulder"].viscous_friction = 0.25 + articulation_cfg = clone(generate_articulation_cfg(articulation_type)) + articulation_cfg.actuators["panda_arm"].viscous_friction = 0.25 + articulation_cfg.actuators["panda_arm"].damping = 2.0 articulation, _ = generate_articulation(articulation_cfg, num_articulations, device) replicate(sim.get_clone_plan()) sim.reset() - shoulder_joint_ids = articulation.actuators["panda_shoulder"].joint_indices - expected_viscous_friction = torch.full((articulation.num_instances, 4), 0.25, device=device) + arm_joint_ids = articulation.actuators["panda_arm"].joint_indices + expected_viscous_friction = torch.full((articulation.num_instances, len(arm_joint_ids)), 0.25, device=device) torch.testing.assert_close( - articulation.data.joint_viscous_friction_coeff.torch[:, shoulder_joint_ids], expected_viscous_friction + articulation.data.joint_viscous_friction_coeff.torch[:, arm_joint_ids], expected_viscous_friction ) torch.testing.assert_close( wp.to_torch(articulation.root_view.get_attribute("joint_damping", SimulationManager.get_model()))[ - :, 0, shoulder_joint_ids + :, 0, arm_joint_ids ], expected_viscous_friction, ) - expected_pd_damping = torch.full_like(expected_viscous_friction, 4.0) - torch.testing.assert_close(articulation.data.joint_damping.torch[:, shoulder_joint_ids], expected_pd_damping) + expected_pd_damping = torch.full_like(expected_viscous_friction, 2.0) + assert not torch.allclose(expected_pd_damping, expected_viscous_friction) + torch.testing.assert_close(articulation.data.joint_damping.torch[:, arm_joint_ids], expected_pd_damping) torch.testing.assert_close( wp.to_torch(articulation.root_view.get_attribute("joint_target_kd", SimulationManager.get_model()))[ - :, 0, shoulder_joint_ids + :, 0, arm_joint_ids ], expected_pd_damping, ) @@ -2840,7 +2844,7 @@ def test_heterogeneous_scene_per_view_shapes(sim, device, add_ground_plane, arti # per-articulation shape gate without that pre-existing quirk. num_per_type = 1 - franka_cfg = replace(FRANKA_PANDA_CFG, prim_path="/World/Env_[^/]*/Franka") + franka_cfg = replace(_FRANKA_PANDA_NEWTON_CFG, prim_path="/World/Env_[^/]*/Franka") anymal_cfg = replace(ANYMAL_C_CFG, prim_path="/World/Env_[^/]*/Anymal") anymal_cfg.init_state.pos = (0.0, 5.0, anymal_cfg.init_state.pos[2]) @@ -3142,7 +3146,7 @@ def test_get_gravity_compensation_forces_static_equilibrium(sim, num_articulatio # gravity-comp signal. Default Franka cfg has stiffness=80 / damping=4 # which would absorb gravity through PD bias and hide accessor bugs. cfg = replace(base_cfg, actuators={"all": ImplicitActuatorCfg(joint_names_expr=[".*"], stiffness=0.0, damping=0.0)}) - # FRANKA_PANDA_CFG has rigid_props.disable_gravity=False already, but be + # FRANKA_PANDA_FLAT_CFG has rigid_props.disable_gravity=False already, but be # defensive — gravity must be ON for τ_gc to have anything to cancel. cfg = replace(cfg, spawn=replace(cfg.spawn, rigid_props=replace(cfg.spawn.rigid_props, disable_gravity=False))) @@ -3160,7 +3164,7 @@ def test_get_gravity_compensation_forces_static_equilibrium(sim, num_articulatio articulation.write_joint_velocity_to_sim_index(velocity=default_qd) articulation.update(sim.cfg.dt) - # Default joint pose from FRANKA_PANDA_CFG bends the elbow + # Default joint pose from FRANKA_PANDA_FLAT_CFG bends the elbow # (joint2=-0.569, joint4=-2.81, joint6=3.04) so several links carry a # gravity load — τ_gc is non-trivial in this configuration. A natural- # hang pose (all zeros) would produce near-zero τ_gc and make this diff --git a/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst b/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst new file mode 100644 index 000000000000..02a80fb24471 --- /dev/null +++ b/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst @@ -0,0 +1,5 @@ +Fixed +^^^^^ + +* Fixed frame-transformer path expressions that directly match a rigid body from also selecting + nested rigid-body descendants. diff --git a/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py b/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py index 0dec1c3c1368..f5a001c43eff 100644 --- a/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py +++ b/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py @@ -176,7 +176,11 @@ def has_rigid_body_api(prim) -> bool: return bool(prim.HasAPI(UsdPhysics.RigidBodyAPI)) matches = resolve_matching_prims_from_source( - prim_path, predicate=has_rigid_body_api, raise_if_no_matches=False + prim_path, + predicate=has_rigid_body_api, + expected_num_matches=1 if frame_type == "source" else None, + raise_if_no_matches=False, + prefer_direct_matches=True, ) if not matches: raise ValueError( @@ -296,8 +300,8 @@ def has_rigid_body_api(prim) -> bool: # -- target frames: use relative prim path for unique identification self._target_frame_body_names = [self._get_relative_body_path(prim_path) for prim_path in sorted_prim_paths] - # -- source frame: use relative prim path for unique identification - self._source_frame_body_name = self._get_relative_body_path(self.cfg.prim_path) + # -- source frame: retain the concrete body resolved from the configured expression + self._source_frame_body_name = tracked_body_names[0] source_frame_index = self._target_frame_body_names.index(self._source_frame_body_name) # Only remove source frame from tracked bodies if it is not also a target frame diff --git a/source/isaaclab_ov/test/assets/test_articulation.py b/source/isaaclab_ov/test/assets/test_articulation.py index 40cea80c376a..0c7a57456c27 100644 --- a/source/isaaclab_ov/test/assets/test_articulation.py +++ b/source/isaaclab_ov/test/assets/test_articulation.py @@ -98,7 +98,7 @@ ## # Pre-defined configs ## -from isaaclab_assets import ANYMAL_C_CFG, CARTPOLE_CFG, FRANKA_PANDA_CFG, SHADOW_HAND_PHYSX_CFG # isort:skip +from isaaclab_assets import ANYMAL_C_CFG, CARTPOLE_CFG, FRANKA_PANDA_FLAT_CFG, SHADOW_HAND_PHYSX_CFG # isort:skip wp.init() @@ -437,7 +437,7 @@ def generate_articulation_cfg( actuators={"body": ImplicitActuatorCfg(joint_names_expr=[".*"], stiffness=stiffness, damping=damping)}, ) elif articulation_type == "panda": - articulation_cfg = FRANKA_PANDA_CFG + articulation_cfg = FRANKA_PANDA_FLAT_CFG elif articulation_type == "anymal": articulation_cfg = ANYMAL_C_CFG elif articulation_type == "shadow_hand": @@ -528,6 +528,32 @@ def generate_articulation( return articulation, translations +@pytest.mark.parametrize("device", ["cuda:0"]) +@pytest.mark.parametrize("gravity_enabled", [False]) +def test_franka_newton_mimic_constraint_tracks_passive_finger(sim, device, gravity_enabled): + """Drive only the Franka leader finger and preserve mimic tracking in every clone.""" + articulation, _ = generate_articulation(FRANKA_PANDA_FLAT_CFG, 2, device) + sim.reset() + + leader_id = articulation.find_joints("panda_finger_joint1")[0][0] + follower_id = articulation.find_joints("panda_finger_joint2")[0][0] + initial_leader_pos = articulation.data.joint_pos.torch[:, leader_id].clone() + leader_target = torch.full((articulation.num_instances, 1), 0.01, device=device) + articulation.actuators.target_command.set_position_index(value=leader_target, joint_ids=[leader_id]) + + for _ in range(120): + articulation.write_data_to_sim() + sim.step() + articulation.update(sim.cfg.dt) + assert torch.isfinite(articulation.data.joint_pos.torch).all() + assert torch.isfinite(articulation.data.joint_vel.torch).all() + + leader_pos = articulation.data.joint_pos.torch[:, leader_id] + follower_pos = articulation.data.joint_pos.torch[:, follower_id] + assert torch.all(torch.abs(leader_pos - initial_leader_pos) > 0.005) + torch.testing.assert_close(follower_pos, leader_pos, rtol=0.0, atol=5.0e-4) + + @pytest.mark.parametrize("device", ["cuda:0"]) def test_newton_native_explicit_actuator_submits_ovphysx_effort(device): """Run a Newton-native explicit actuator through the current OVPhysX state and effort binding.""" @@ -1745,7 +1771,7 @@ def test_out_of_range_default_joint_vel(sim, device): 1. The articulation fails to initialize when joint velocities are out of range 2. The error is properly handled """ - articulation_cfg = replace(FRANKA_PANDA_CFG, prim_path="/World/Robot") + articulation_cfg = replace(FRANKA_PANDA_FLAT_CFG, prim_path="/World/Robot") articulation_cfg.init_state.joint_vel = { "panda_joint1": 100.0, "panda_joint[2, 4]": -60.0, @@ -2555,7 +2581,7 @@ def test_com_orientation_write_invalidates_static_inertia_cache_with_body_orderi below forbids cross-device staging, so this test is CPU-only. """ sim._app_control_on_stop_handle = None - articulation_cfg = replace(FRANKA_PANDA_CFG, body_ordering=PANDA_ROOT_PRESERVING_REVERSED_BODY_NAMES) + articulation_cfg = replace(FRANKA_PANDA_FLAT_CFG, body_ordering=PANDA_ROOT_PRESERVING_REVERSED_BODY_NAMES) articulation, _ = generate_articulation(articulation_cfg, 1, device=device) sim.reset() diff --git a/source/isaaclab_ov/test/sensors/test_frame_transformer.py b/source/isaaclab_ov/test/sensors/test_frame_transformer.py index 4f520bd382b0..45aadfb9735b 100644 --- a/source/isaaclab_ov/test/sensors/test_frame_transformer.py +++ b/source/isaaclab_ov/test/sensors/test_frame_transformer.py @@ -50,6 +50,7 @@ from isaaclab.utils import configclass, replace # noqa: E402 from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # noqa: E402 +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # noqa: E402 wp.init() @@ -668,3 +669,44 @@ class MultiRobotSceneCfg(InteractiveSceneCfg): assert any(torch.allclose(rf_pos, expected, atol=1e-5) for expected in expected_rf_positions), ( f"RF_SHANK position {rf_pos} doesn't match either configured body offset" ) + + +@pytest.mark.parametrize("device", ["cpu", "cuda:0"]) +def test_frame_transformer_nested_rigid_bodies(device): + """Test that a matched rigid body does not include nested rigid-body descendants.""" + with _ovphysx_sim_context(device=device) as sim: + sim._app_control_on_stop_handle = None + scene_cfg = _SceneCfg(num_envs=2, env_spacing=5.0, lazy_sensor_update=False) + scene_cfg.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + scene_cfg.frame_transformer = FrameTransformerCfg( + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", + target_frames=[ + FrameTransformerCfg.FrameCfg( + name="hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", + ), + FrameTransformerCfg.FrameCfg( + name="left_finger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", + ), + FrameTransformerCfg.FrameCfg( + name="right_finger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", + ), + ], + ) + scene = InteractiveScene(scene_cfg) + + sim.reset() + scene.update(sim.get_physics_dt()) + + robot = scene.articulations["robot"] + source_id = robot.find_bodies("panda_link0")[0][0] + target_ids = robot.find_bodies(["panda_hand", "panda_leftfinger", "panda_rightfinger"])[0] + frame_data = scene.sensors["frame_transformer"].data + + assert frame_data.target_frame_names == ["hand", "left_finger", "right_finger"] + torch.testing.assert_close(frame_data.source_pos_w.torch, robot.data.body_pos_w.torch[:, source_id]) + torch.testing.assert_close(frame_data.source_quat_w.torch, robot.data.body_quat_w.torch[:, source_id]) + torch.testing.assert_close(frame_data.target_pos_w.torch, robot.data.body_pos_w.torch[:, target_ids]) + torch.testing.assert_close(frame_data.target_quat_w.torch, robot.data.body_quat_w.torch[:, target_ids]) diff --git a/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst b/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst new file mode 100644 index 000000000000..02a80fb24471 --- /dev/null +++ b/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst @@ -0,0 +1,5 @@ +Fixed +^^^^^ + +* Fixed frame-transformer path expressions that directly match a rigid body from also selecting + nested rigid-body descendants. diff --git a/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py b/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py index 9a9055e10c98..1f17ce8463b2 100644 --- a/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py +++ b/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py @@ -191,7 +191,13 @@ def _initialize_impl(self): def has_rigid_body_api(prim) -> bool: return bool(prim.HasAPI(UsdPhysics.RigidBodyAPI)) - matches = resolve_matching_prims_from_source(prim_path, has_rigid_body_api, raise_if_no_matches=False) + matches = resolve_matching_prims_from_source( + prim_path, + has_rigid_body_api, + expected_num_matches=1 if frame_type == "source" else None, + raise_if_no_matches=False, + prefer_direct_matches=True, + ) if not matches: raise ValueError( f"Failed to create frame transformer for frame '{frame}' with path '{prim_path}'." @@ -298,8 +304,8 @@ def extract_env_num_and_prim_path(item: str) -> tuple[int, str]: # -- target frames: use relative prim path for unique identification self._target_frame_body_names = [self._get_relative_body_path(prim_path) for prim_path in sorted_prim_paths] - # -- source frame: use relative prim path for unique identification - self._source_frame_body_name = self._get_relative_body_path(self.cfg.prim_path) + # -- source frame: retain the concrete body resolved from the configured expression + self._source_frame_body_name = tracked_body_names[0] source_frame_index = self._target_frame_body_names.index(self._source_frame_body_name) # Only remove source frame from tracked bodies if it is not also a target frame diff --git a/source/isaaclab_physx/test/assets/test_articulation.py b/source/isaaclab_physx/test/assets/test_articulation.py index 7078c528911e..81e6007b18e4 100644 --- a/source/isaaclab_physx/test/assets/test_articulation.py +++ b/source/isaaclab_physx/test/assets/test_articulation.py @@ -51,8 +51,8 @@ ## from isaaclab_assets import ( # isort:skip ANYMAL_C_CFG, - FRANKA_PANDA_CFG, - FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_FLAT_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, ) from isaaclab_assets.robots.shadow_hand import SHADOW_HAND_PHYSX_CFG @@ -98,7 +98,7 @@ def generate_articulation_cfg( actuators={"body": ImplicitActuatorCfg(joint_names_expr=[".*"], stiffness=stiffness, damping=damping)}, ) elif articulation_type == "panda": - articulation_cfg = FRANKA_PANDA_CFG + articulation_cfg = FRANKA_PANDA_FLAT_CFG elif articulation_type == "anymal": articulation_cfg = ANYMAL_C_CFG elif articulation_type == "shadow_hand": @@ -217,7 +217,7 @@ def _setup_franka_at_home_pose(sim): Returns: Tuple of ``(robot, ee_frame_idx, ee_jacobi_idx, arm_joint_ids)``. """ - cfg = replace(clone(FRANKA_PANDA_HIGH_PD_CFG), prim_path="/World/Env_[^/]*/Robot") + cfg = replace(clone(FRANKA_PANDA_FLAT_HIGH_PD_CFG), prim_path="/World/Env_[^/]*/Robot") sim_utils.create_prim("/World/Env_0", "Xform", translation=(0.0, 0.0, 0.0)) robot = Articulation(cfg) sim.reset() @@ -309,7 +309,7 @@ def sim(request): def test_live_manual_root_preserving_ordering_reorders_backend_reads_and_writes(sim, device, gravity_enabled): """Smoke-test non-identity joint/body ordering through a live PhysX articulation.""" articulation_cfg = replace( - FRANKA_PANDA_CFG, + FRANKA_PANDA_FLAT_CFG, prim_path="/World/Robot", joint_ordering=tuple(reversed(PANDA_JOINT_NAMES)), body_ordering=PANDA_ROOT_PRESERVING_REVERSED_BODY_NAMES, @@ -433,13 +433,13 @@ def test_reversed_joint_dynamics_use_public_joint_basis(sim, device, gravity_ena @pytest.mark.parametrize("gravity_enabled", [False]) def test_live_floating_root_writers_match_identity_after_body_reordering(sim, device, gravity_enabled): """Keep floating-base root writes invariant when public body order moves the root.""" - floating_spawn = replace(FRANKA_PANDA_CFG.spawn, fix_root_link=False) + floating_spawn = replace(FRANKA_PANDA_FLAT_CFG.spawn, fix_root_link=False) identity = Articulation( - replace(FRANKA_PANDA_CFG, prim_path="/World/IdentityRobot", spawn=floating_spawn, body_ordering=None) + replace(FRANKA_PANDA_FLAT_CFG, prim_path="/World/IdentityRobot", spawn=floating_spawn, body_ordering=None) ) ordered = Articulation( replace( - FRANKA_PANDA_CFG, + FRANKA_PANDA_FLAT_CFG, prim_path="/World/OrderedRobot", spawn=floating_spawn, body_ordering=tuple(reversed(PANDA_BODY_NAMES)), @@ -511,7 +511,9 @@ def test_live_direct_view_mass_inertia_writes_become_visible(sim, device, gravit ``user_to_backend``. """ body_ordering_arg = None if body_ordering == "identity" else PANDA_ROOT_PRESERVING_REVERSED_BODY_NAMES - articulation = Articulation(replace(FRANKA_PANDA_CFG, prim_path="/World/Robot", body_ordering=body_ordering_arg)) + articulation = Articulation( + replace(FRANKA_PANDA_FLAT_CFG, prim_path="/World/Robot", body_ordering=body_ordering_arg) + ) sim.reset() assert articulation.is_initialized @@ -861,7 +863,7 @@ def test_out_of_range_default_joint_vel(sim, device): 1. The articulation fails to initialize when joint velocities are out of range 2. The error is properly handled """ - articulation_cfg = replace(FRANKA_PANDA_CFG, prim_path="/World/Robot") + articulation_cfg = replace(FRANKA_PANDA_FLAT_CFG, prim_path="/World/Robot") articulation_cfg.init_state.joint_vel = { "panda_joint1": 100.0, "panda_joint[2, 4]": -60.0, @@ -2141,7 +2143,7 @@ def test_get_gravity_compensation_forces_static_equilibrium(sim, num_articulatio # gravity-comp signal. Default Franka cfg has stiffness=80 / damping=4 # which would absorb gravity through PD bias and hide accessor bugs. cfg = replace(base_cfg, actuators={"all": ImplicitActuatorCfg(joint_names_expr=[".*"], stiffness=0.0, damping=0.0)}) - # FRANKA_PANDA_CFG has rigid_props.disable_gravity=False already, but be + # FRANKA_PANDA_FLAT_CFG has rigid_props.disable_gravity=False already, but be # defensive — gravity must be ON for τ_gc to have anything to cancel. cfg = replace(cfg, spawn=replace(cfg.spawn, rigid_props=replace(cfg.spawn.rigid_props, disable_gravity=False))) @@ -2157,7 +2159,7 @@ def test_get_gravity_compensation_forces_static_equilibrium(sim, num_articulatio articulation.write_joint_state_to_sim(default_q, default_qd) articulation.update(sim.cfg.dt) - # Default joint pose from FRANKA_PANDA_CFG bends the elbow + # Default joint pose from FRANKA_PANDA_FLAT_CFG bends the elbow # (joint2=-0.569, joint4=-2.81, joint6=3.04) so several links carry a # gravity load — τ_gc is non-trivial in this configuration. A natural- # hang pose (all zeros) would produce near-zero τ_gc and make this diff --git a/source/isaaclab_physx/test/sensors/test_frame_transformer.py b/source/isaaclab_physx/test/sensors/test_frame_transformer.py index 7d0ffb0d918a..8775fa47d35f 100644 --- a/source/isaaclab_physx/test/sensors/test_frame_transformer.py +++ b/source/isaaclab_physx/test/sensors/test_frame_transformer.py @@ -32,6 +32,7 @@ # Pre-defined configs ## from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort:skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # isort:skip def quat_from_euler_rpy(roll, pitch, yaw, degrees=False): @@ -720,3 +721,41 @@ def test_frame_transformer_invalidation_drops_cached_launch_state(monkeypatch): assert sensor._frame_physx_view is None assert sensor._raw_transforms is None assert sensor._update_cmd is None + + +def test_frame_transformer_nested_rigid_bodies(sim): + """Test that a matched rigid body does not include nested rigid-body descendants.""" + scene_cfg = MySceneCfg(num_envs=2, env_spacing=5.0, lazy_sensor_update=False) + scene_cfg.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + scene_cfg.frame_transformer = FrameTransformerCfg( + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", + target_frames=[ + FrameTransformerCfg.FrameCfg( + name="hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", + ), + FrameTransformerCfg.FrameCfg( + name="left_finger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", + ), + FrameTransformerCfg.FrameCfg( + name="right_finger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", + ), + ], + ) + scene = InteractiveScene(scene_cfg) + + sim.reset() + scene.update(sim.get_physics_dt()) + + robot = scene.articulations["robot"] + source_id = robot.find_bodies("panda_link0")[0][0] + target_ids = robot.find_bodies(["panda_hand", "panda_leftfinger", "panda_rightfinger"])[0] + frame_data = scene.sensors["frame_transformer"].data + + assert frame_data.target_frame_names == ["hand", "left_finger", "right_finger"] + torch.testing.assert_close(frame_data.source_pos_w.torch, robot.data.body_pos_w.torch[:, source_id]) + torch.testing.assert_close(frame_data.source_quat_w.torch, robot.data.body_quat_w.torch[:, source_id]) + torch.testing.assert_close(frame_data.target_pos_w.torch, robot.data.body_pos_w.torch[:, target_ids]) + torch.testing.assert_close(frame_data.target_quat_w.torch, robot.data.body_quat_w.torch[:, target_ids]) From 7d4731f053d49fdc9e0d1ae5b1420edc5ff0df66 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 19:15:09 +0200 Subject: [PATCH 02/24] Migrate Franka Reach and Drawer to flat asset --- examples/haply_teleoperation.py | 9 +- .../tutorials/05_controllers/run_diff_ik.py | 4 +- scripts/tutorials/05_controllers/run_osc.py | 10 +- ...maximiliank-diffik-action-offset.minor.rst | 5 + .../isaaclab/envs/mdp/actions/actions_cfg.py | 2 + .../envs/mdp/actions/task_space_actions.py | 22 ++-- .../test/controllers/test_differential_ik.py | 4 +- .../controllers/test_operational_space.py | 5 +- .../envs/test_diffik_action_processing.py | 56 ++++++++++ .../maximiliank-franka-reach-drawer.major.rst | 11 ++ .../render_benchmark_env_cfg.py | 9 +- .../cabinet/config/franka/ik_abs_env_cfg.py | 6 +- .../cabinet/config/franka/ik_rel_env_cfg.py | 6 +- .../contrib/franka_pour/pour_env_cfg.py | 45 ++------ .../lift/config/franka/ik_abs_env_cfg.py | 4 +- .../lift/config/franka/ik_rel_env_cfg.py | 4 +- .../lift/config/franka/joint_pos_env_cfg.py | 8 +- .../config/franka/bin_stack_ik_rel_env_cfg.py | 4 +- .../franka/bin_stack_joint_pos_env_cfg.py | 12 +-- .../config/franka/stack_ik_abs_env_cfg.py | 4 +- .../franka/stack_ik_rel_blueprint_env_cfg.py | 4 +- .../config/franka/stack_ik_rel_env_cfg.py | 4 +- .../franka/stack_ik_rel_env_cfg_skillgen.py | 4 +- ...stack_ik_rel_instance_randomize_env_cfg.py | 4 +- .../stack_ik_rel_visuomotor_cosmos_env_cfg.py | 2 +- .../franka/stack_ik_rel_visuomotor_env_cfg.py | 14 +-- .../config/franka/stack_joint_pos_env_cfg.py | 20 ++-- ...ck_joint_pos_instance_randomize_env_cfg.py | 12 +-- .../config/franka/cabinet_direct_env_cfg.py | 11 +- .../config/franka/joint_pos_env_cfg.py | 19 ++-- .../config/franka/franka_reach_env_cfg.py | 50 +++++++-- .../config/franka/franka_reach_osc_env_cfg.py | 7 +- .../benchmark/test_render_benchmark_cfg.py | 13 +-- .../test/contrib/test_franka_pour_env_cfg.py | 2 +- .../test/core/test_reach_franka_presets.py | 101 ++++++++++++++---- 35 files changed, 334 insertions(+), 163 deletions(-) create mode 100644 source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst create mode 100644 source/isaaclab/test/envs/test_diffik_action_processing.py create mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst diff --git a/examples/haply_teleoperation.py b/examples/haply_teleoperation.py index 129d9fa3e674..679150eac477 100644 --- a/examples/haply_teleoperation.py +++ b/examples/haply_teleoperation.py @@ -33,7 +33,7 @@ from isaaclab.utils import configclass, instantiate, replace from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR -from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG +from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG if TYPE_CHECKING: from isaaclab.assets import Articulation, RigidObject @@ -127,10 +127,11 @@ class FrankaHaplySceneCfg(InteractiveSceneCfg): init_state=AssetBaseCfg.InitialStateCfg(pos=(0.50, 0.0, 1.05), rot=(0.707, 0, 0, 0.707)), ) - robot_cfg: ArticulationCfg = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot_cfg: ArticulationCfg = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") robot = instantiate(robot_cfg) robot.init_state.pos = (-0.02, 0.0, 1.05) robot.spawn.activate_contact_sensors = True + robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics == "newton_mjwarp" else "physx" cube = RigidObjectCfg( prim_path="{ENV_REGEX_NS}/Cube", @@ -146,7 +147,7 @@ class FrankaHaplySceneCfg(InteractiveSceneCfg): ) left_finger_contact_sensor = ContactSensorCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", update_period=0.0, history_length=3, debug_vis=True, @@ -154,7 +155,7 @@ class FrankaHaplySceneCfg(InteractiveSceneCfg): ) right_finger_contact_sensor = ContactSensorCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", update_period=0.0, history_length=3, debug_vis=True, diff --git a/scripts/tutorials/05_controllers/run_diff_ik.py b/scripts/tutorials/05_controllers/run_diff_ik.py index 9f91b6596195..2acd470b6fb6 100644 --- a/scripts/tutorials/05_controllers/run_diff_ik.py +++ b/scripts/tutorials/05_controllers/run_diff_ik.py @@ -53,7 +53,7 @@ ## # Pre-defined configs ## -from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG, UR10_CFG # isort:skip +from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG, UR10_CFG # isort:skip @configclass @@ -82,7 +82,7 @@ class TableTopSceneCfg(InteractiveSceneCfg): # articulation if args_cli.robot == "franka_panda": - robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") elif args_cli.robot == "ur10": robot = replace(UR10_CFG, prim_path="{ENV_REGEX_NS}/Robot") else: diff --git a/scripts/tutorials/05_controllers/run_osc.py b/scripts/tutorials/05_controllers/run_osc.py index f2dddf957364..03b8e886c75e 100644 --- a/scripts/tutorials/05_controllers/run_osc.py +++ b/scripts/tutorials/05_controllers/run_osc.py @@ -57,7 +57,7 @@ ## # Pre-defined configs ## -from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG # isort:skip +from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort:skip @configclass @@ -97,11 +97,9 @@ class SceneCfg(InteractiveSceneCfg): debug_vis=False, ) - robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - robot.actuators["panda_shoulder"].stiffness = 0.0 - robot.actuators["panda_shoulder"].damping = 0.0 - robot.actuators["panda_forearm"].stiffness = 0.0 - robot.actuators["panda_forearm"].damping = 0.0 + robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot.actuators["panda_arm"].stiffness = 0.0 + robot.actuators["panda_arm"].damping = 0.0 robot.spawn.rigid_props.disable_gravity = True diff --git a/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst b/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst new file mode 100644 index 000000000000..2af70b827142 --- /dev/null +++ b/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst @@ -0,0 +1,5 @@ +Added +^^^^^ + +* Added an ``offset`` to ``DifferentialInverseKinematicsActionCfg`` so normalized policies can use + an affine task-space action transform. The default is zero and preserves existing configurations. diff --git a/source/isaaclab/isaaclab/envs/mdp/actions/actions_cfg.py b/source/isaaclab/isaaclab/envs/mdp/actions/actions_cfg.py index 6bd98583073e..ecb0ef1dabe2 100644 --- a/source/isaaclab/isaaclab/envs/mdp/actions/actions_cfg.py +++ b/source/isaaclab/isaaclab/envs/mdp/actions/actions_cfg.py @@ -325,6 +325,8 @@ class OffsetCfg: """Offset of target frame w.r.t. to the body frame. Defaults to None, in which case no offset is applied.""" scale: float | tuple[float, ...] = 1.0 """Scale factor for the action. Defaults to 1.0.""" + offset: float | tuple[float, ...] = 0.0 + """Offset applied to the scaled action in controller-specific units. Defaults to 0.0.""" controller: DifferentialIKControllerCfg = MISSING """The configuration for the differential IK controller.""" diff --git a/source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py b/source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py index 3b077356cea5..e089047e49b7 100644 --- a/source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py +++ b/source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py @@ -34,15 +34,15 @@ class DifferentialInverseKinematicsAction(ActionTerm): r"""Inverse Kinematics action term. - This action term performs pre-processing of the raw actions using scaling transformation. + This action term pre-processes raw actions using an affine transformation. .. math:: - \text{action} = \text{scaling} \times \text{input action} + \text{action} = \text{offset} + \text{scaling} \times \text{input action} \text{joint position} = J^{-} \times \text{action} - where :math:`\text{scaling}` is the scaling applied to the input action, and :math:`\text{input action}` - is the input action from the user, :math:`J` is the Jacobian over the articulation's actuated joints, - and \text{joint position} is the desired joint position command for the articulation's joints. + where :math:`\text{offset}` and :math:`\text{scaling}` define the affine transformation, + :math:`\text{input action}` is the input action from the user, :math:`J` is the Jacobian over the + articulation's actuated joints, and \text{joint position} is the desired joint position command. """ cfg: actions_cfg.DifferentialInverseKinematicsActionCfg @@ -50,7 +50,9 @@ class DifferentialInverseKinematicsAction(ActionTerm): _asset: Articulation """The articulation asset on which the action term is applied.""" _scale: torch.Tensor - """The scaling factor applied to the input action. Shape is (1, action_dim).""" + """The scaling factor applied to the input action. Shape is (num_envs, action_dim).""" + _offset: torch.Tensor + """The offset applied to the scaled action. Shape is (num_envs, action_dim).""" _clip: torch.Tensor """The clip applied to the input action.""" @@ -100,9 +102,11 @@ def __init__(self, cfg: actions_cfg.DifferentialInverseKinematicsActionCfg, env: # owned buffer; _compute_frame_jacobian mutates this, not the data-layer view. self._jacobian_b = torch.zeros(self.num_envs, 6, len(self._jacobi_joint_ids), device=self.device) - # save the scale as tensors + # save the affine transform as tensors self._scale = torch.zeros((self.num_envs, self.action_dim), device=self.device) self._scale[:] = torch.tensor(self.cfg.scale, device=self.device) + self._offset = torch.zeros((self.num_envs, self.action_dim), device=self.device) + self._offset[:] = torch.tensor(self.cfg.offset, device=self.device) # convert the fixed offsets to torch tensors of batched shape if self.cfg.body_offset is not None: @@ -160,6 +164,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor: - body_name: The name of the body. - joint_names: The names of the joints. - scale: The scale of the action term. + - offset: The offset of the action term. - clip: The clip of the action term. - controller_cfg: The configuration of the controller. - body_offset: The offset of the body. @@ -174,6 +179,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor: self._IO_descriptor.body_name = self._body_name self._IO_descriptor.joint_names = self._joint_names self._IO_descriptor.scale = self._scale + self._IO_descriptor.offset = self._offset if self.cfg.clip is not None: self._IO_descriptor.clip = self.cfg.clip else: @@ -189,7 +195,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor: def process_actions(self, actions: torch.Tensor): # store the raw actions self._raw_actions[:] = actions - self._processed_actions[:] = self.raw_actions * self._scale + self._processed_actions[:] = self.raw_actions * self._scale + self._offset if self.cfg.clip is not None: self._processed_actions = torch.clamp( self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1] diff --git a/source/isaaclab/test/controllers/test_differential_ik.py b/source/isaaclab/test/controllers/test_differential_ik.py index 4b91b1158cff..4df4cad5d92d 100644 --- a/source/isaaclab/test/controllers/test_differential_ik.py +++ b/source/isaaclab/test/controllers/test_differential_ik.py @@ -31,7 +31,7 @@ ## # Pre-defined configs ## -from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG, UR10_CFG # isort:skip +from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG, UR10_CFG # isort:skip pytestmark = pytest.mark.integration @@ -441,7 +441,7 @@ def test_franka_ik_pose_abs(sim): sim_context, num_envs, ee_pose_b_des_set = sim # Create robot instance - robot_cfg = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot_cfg = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") robot = Articulation(cfg=robot_cfg) # Create IK controller diff --git a/source/isaaclab/test/controllers/test_operational_space.py b/source/isaaclab/test/controllers/test_operational_space.py index 2dd6e63e4028..76ed5a42165f 100644 --- a/source/isaaclab/test/controllers/test_operational_space.py +++ b/source/isaaclab/test/controllers/test_operational_space.py @@ -50,7 +50,7 @@ subtract_frame_transforms, ) -from isaaclab_assets import FRANKA_PANDA_CFG, G1_29DOF_CFG # isort:skip +from isaaclab_assets import FRANKA_PANDA_LEGACY_CFG, G1_29DOF_CFG # isort:skip pytestmark = pytest.mark.integration @@ -95,7 +95,8 @@ def sim(): # clone the env xform cloner.usd_replicate(stage, [env_fmt.format(0)], [env_fmt], env_ids, positions=env_origins) - robot_cfg = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + # Keep controller regressions on their original plant; canonical asset parity is tested by each backend. + robot_cfg = replace(FRANKA_PANDA_LEGACY_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Explicit torque actuators enforce effort limits on the commands sent to the simulator. for actuator_name in ("panda_shoulder", "panda_forearm"): actuator_cfg = robot_cfg.actuators[actuator_name] diff --git a/source/isaaclab/test/envs/test_diffik_action_processing.py b/source/isaaclab/test/envs/test_diffik_action_processing.py new file mode 100644 index 000000000000..8a6d9634a9ea --- /dev/null +++ b/source/isaaclab/test/envs/test_diffik_action_processing.py @@ -0,0 +1,56 @@ +# 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 + +"""Unit tests for differential inverse-kinematics action processing.""" + +from types import SimpleNamespace + +import pytest +import torch + +from isaaclab.controllers import DifferentialIKControllerCfg +from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg +from isaaclab.envs.mdp.actions.task_space_actions import DifferentialInverseKinematicsAction + +pytestmark = pytest.mark.unit + + +def test_process_actions_applies_scale_then_offset(monkeypatch: pytest.MonkeyPatch) -> None: + """DiffIK actions use the configured affine transformation before reaching the controller.""" + num_envs = 2 + controller_cfg = DifferentialIKControllerCfg(command_type="position", use_relative_mode=False, ik_method="dls") + cfg = DifferentialInverseKinematicsActionCfg( + asset_name="robot", + joint_names=[".*"], + body_name="tool", + scale=(0.5, 2.0, -1.0), + offset=(0.1, -0.2, 0.3), + controller=controller_cfg, + ) + asset = SimpleNamespace( + find_joints=lambda _names: ([0, 1, 2], ["joint1", "joint2", "joint3"]), + find_bodies=lambda _name: ([0], ["tool"]), + num_joints=3, + num_base_dofs=0, + is_fixed_base=False, + ) + env = SimpleNamespace(scene={"robot": asset}, num_envs=num_envs, device="cpu") + action = DifferentialInverseKinematicsAction(cfg, env) + ee_pos = torch.zeros(num_envs, 3) + ee_quat = torch.tensor([[0.0, 0.0, 0.0, 1.0]]).repeat(num_envs, 1) + monkeypatch.setattr(action, "_compute_frame_pose", lambda: (ee_pos, ee_quat)) + + raw_actions = torch.tensor([[1.0, -2.0, 0.5], [-1.0, 0.25, -0.5]]) + expected = torch.tensor([[0.6, -4.2, -0.2], [-0.4, 0.3, 0.8]]) + + action.process_actions(raw_actions) + + torch.testing.assert_close(action.raw_actions, raw_actions) + torch.testing.assert_close(action.processed_actions, expected) + torch.testing.assert_close(action._ik_controller.ee_pos_des, expected) + + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst new file mode 100644 index 000000000000..d3e71b259a74 --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst @@ -0,0 +1,11 @@ +Changed +^^^^^^^ + +* Migrated maintained Franka Reach, Drawer, and related contributed tasks to the shared flat asset with + backend-specific physics and gripper-only collisions by default. Select ``arm_collisions`` where arm + contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. + +Fixed +^^^^^ + +* Corrected the Reach action and controller contracts for the shared asset. diff --git a/source/isaaclab_tasks/isaaclab_tasks/benchmark/render_benchmark/render_benchmark_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/benchmark/render_benchmark/render_benchmark_env_cfg.py index a09bdf673811..3e1c4ba20fce 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/benchmark/render_benchmark/render_benchmark_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/benchmark/render_benchmark/render_benchmark_env_cfg.py @@ -25,10 +25,10 @@ from isaaclab.utils import configclass, replace from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR -from isaaclab_tasks.utils import PresetCfg +from isaaclab_tasks.utils import PresetCfg, preset from isaaclab_tasks.utils.presets import MultiBackendRendererCfg -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG BenchmarkMode = Literal["render", "physics_render"] """Animation mode used by the render benchmark. @@ -144,10 +144,11 @@ class RenderBenchmarkSceneCfg(InteractiveSceneCfg): init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, -0.05)), ) robot: ArticulationCfg = replace( - FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", - init_state=replace(FRANKA_PANDA_HIGH_PD_CFG.init_state, pos=(1.0, 0.0, 0.0), rot=(0.0, 0.0, 1.0, 0.0)), + init_state=replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG.init_state, pos=(1.0, 0.0, 0.0), rot=(0.0, 0.0, 1.0, 0.0)), ) + robot.spawn.variants["Physics"] = preset(default="mujoco", isaacsim_physx="physx", ovphysx="physx", physx="physx") cabinet: ArticulationCfg = ArticulationCfg( prim_path="{ENV_REGEX_NS}/Cabinet", spawn=sim_utils.UsdFileCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py index 7707d97e8a7e..8a7da6c667c5 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -23,7 +23,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + physics_variants = self.scene.robot.spawn.variants + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = physics_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py index 7e2e96e9460e..aae63d444a09 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -23,7 +23,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + physics_variants = self.scene.robot.spawn.variants + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = physics_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/franka_pour/pour_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/franka_pour/pour_env_cfg.py index 1dc988351a67..687eaa69c89e 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/franka_pour/pour_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/franka_pour/pour_env_cfg.py @@ -40,7 +40,7 @@ from isaaclab_contrib.coupling import CouplerEntryCfg, CouplerProxyCfg, CouplerProxyMappingCfg -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG from . import mdp from .geometry import ( @@ -182,7 +182,7 @@ def spawn_franka_with_arm_collisions( orientation: tuple[float, float, float, float] | None = None, **kwargs, ): - """Spawn the canonical Franka with the intended mimic and arm-collision schemas.""" + """Spawn the canonical Franka with writable convex-hull arm colliders.""" from pxr import Usd, UsdPhysics # noqa: PLC0415 robot_prim = sim_utils.spawn_from_usd(prim_path, cfg, translation, orientation, **kwargs) @@ -191,29 +191,6 @@ def spawn_franka_with_arm_collisions( if not self_collision or not self_collision.Set(True): raise RuntimeError(f"Franka asset at {root_prim.GetPath()} has no writable Newton self-collision flag.") - finger_joints = { - prim.GetName(): prim - for prim in Usd.PrimRange(root_prim, Usd.TraverseInstanceProxies()) - if prim.GetName() in {"panda_finger_joint1", "panda_finger_joint2"} - } - if finger_joints.keys() != {"panda_finger_joint1", "panda_finger_joint2"}: - missing = sorted({"panda_finger_joint1", "panda_finger_joint2"}.difference(finger_joints)) - raise RuntimeError(f"Franka asset at {root_prim.GetPath()} is missing finger joints: {missing}.") - - leader_schemas = finger_joints["panda_finger_joint1"].GetMetadata("apiSchemas") - follower_schemas = finger_joints["panda_finger_joint2"].GetMetadata("apiSchemas") - leader_schema_names = [] if leader_schemas is None else list(leader_schemas.GetAppliedItems()) - follower_schema_names = [] if follower_schemas is None else list(follower_schemas.GetAppliedItems()) - if "NewtonMimicAPI" not in leader_schema_names or "PhysxMimicJointAPI:linear" not in follower_schema_names: - raise RuntimeError( - "The pinned Franka physics payload no longer has the expected duplicate finger-mimic schemas. " - "Update the asset hash and task-side override together." - ) - if not finger_joints["panda_finger_joint1"].RemoveAppliedSchema("NewtonMimicAPI"): - raise RuntimeError("Failed to remove the redundant Franka Newton finger-mimic schema.") - if finger_joints["panda_finger_joint1"].HasAPI("NewtonMimicAPI"): - raise RuntimeError("The redundant Franka Newton finger-mimic schema is still composed after removal.") - proxy_roots = { prim.GetName(): prim.GetParent().GetPath() for prim in Usd.PrimRange(root_prim, Usd.TraverseInstanceProxies()) @@ -337,9 +314,9 @@ class PourSceneCfg(InteractiveSceneCfg): prim_path="/World/light", spawn=sim_utils.DomeLightCfg(color=(0.75, 0.75, 0.75), intensity=3000.0), ) - robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") robot.spawn.usd_path = FRANKA_POUR_ROBOT_USD_PATH - robot.spawn.variants = {"Colliders": "convex_hulls"} + robot.spawn.variants = {"Physics": "mujoco", "Colliders": "convex_hulls"} robot.spawn.func = spawn_franka_with_arm_collisions # The pouring asset relies on arm self-collision; author it in both namespaces so whichever # backend resolves the articulation sees the flag. @@ -355,16 +332,10 @@ class PourSceneCfg(InteractiveSceneCfg): ) for name, actuator_cfg in robot.actuators.items() } - robot.actuators["panda_shoulder"].stiffness = { - key: FRANKA_POUR_ARM_DRIVE_STIFFNESS[key] for key in ("panda_joint[1-2]", "panda_joint[3-4]") - } - robot.actuators["panda_shoulder"].damping = { - key: FRANKA_POUR_ARM_DRIVE_DAMPING[key] for key in ("panda_joint[1-2]", "panda_joint[3-4]") - } - robot.actuators["panda_forearm"].stiffness = { - "panda_joint[5-7]": FRANKA_POUR_ARM_DRIVE_STIFFNESS["panda_joint[5-7]"] - } - robot.actuators["panda_forearm"].damping = {"panda_joint[5-7]": FRANKA_POUR_ARM_DRIVE_DAMPING["panda_joint[5-7]"]} + robot.actuators["panda_arm"].stiffness = dict(FRANKA_POUR_ARM_DRIVE_STIFFNESS) + robot.actuators["panda_arm"].damping = dict(FRANKA_POUR_ARM_DRIVE_DAMPING) + robot.actuators["panda_finger2_passive"].stiffness = 0.0 + robot.actuators["panda_finger2_passive"].damping = 0.0 robot.spawn.joint_drive_props = MujocoJointCfg(actuatorgravcomp=True) robot.init_state.joint_pos.update(dict(zip(_ARM_JOINT_NAMES, _ARM_HOME, strict=True))) robot.init_state.joint_pos["panda_finger_joint.*"] = _GRIPPER_OPEN_POSITION diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py index 8bee40e4b2be..3a6521e107f9 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip ## @@ -28,7 +28,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py index 4869b30b8521..ff44c6c2c9a5 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -23,7 +23,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py index 5935bb95c19c..aabd132f7154 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py @@ -19,7 +19,7 @@ # Pre-defined configs ## from isaaclab.markers.config import FRAME_MARKER_CFG # isort: skip -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # isort: skip @configclass @@ -29,7 +29,7 @@ def __post_init__(self): super().__post_init__() # Set Franka as robot - self.scene.robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = mdp.JointPositionActionCfg( @@ -67,12 +67,12 @@ def __post_init__(self): marker_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) marker_cfg.prim_path = "/Visuals/FrameTransformer" self.scene.ee_frame = FrameTransformerCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", debug_vis=False, visualizer_cfg=marker_cfg, target_frames=[ FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", name="end_effector", offset=OffsetCfg( pos=[0.0, 0.0, 0.1034], diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py index 858c095779aa..8b68516ff17d 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -22,7 +22,7 @@ def __post_init__(self): super().__post_init__() # Set Franka as robot - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py index 5d4e533e98a0..fdcc0587fa31 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py @@ -24,7 +24,7 @@ # Pre-defined configs ## from isaaclab.markers.config import FRAME_MARKER_CFG # isort: skip -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # isort: skip @configclass @@ -96,7 +96,7 @@ def __post_init__(self): self.events = EventCfg() # Set Franka as robot - self.scene.robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") self.scene.robot.spawn.semantic_tags = [("class", "robot")] # Add semantics to table @@ -182,26 +182,26 @@ def __post_init__(self): marker_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) marker_cfg.prim_path = "/Visuals/FrameTransformer" self.scene.ee_frame = FrameTransformerCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", debug_vis=False, visualizer_cfg=marker_cfg, target_frames=[ FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", name="end_effector", offset=OffsetCfg( pos=(0.0, 0.0, 0.0), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", name="tool_rightfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", name="tool_leftfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py index 7024329b8e57..18e6efc6db2c 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py @@ -18,7 +18,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip def _build_franka_stack_pipeline(): @@ -114,7 +114,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py index 2c74266768ff..74fd959e1d65 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py @@ -31,7 +31,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip def image( @@ -217,7 +217,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") self.scene.robot.spawn.semantic_tags = [("class", "robot")] # Set actions for the specific robot type (franka) diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py index 559058ab8673..18cb199c8a5e 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py @@ -22,7 +22,7 @@ # Pre-defined configs ## from isaaclab_assets.robots.franka import ( # isort: skip - FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, ) @@ -37,7 +37,7 @@ def __post_init__(self): robot_init_state = self.scene.robot.init_state robot_semantic_tags = self.scene.robot.spawn.semantic_tags self.scene.robot = replace( - FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=robot_init_state + FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=robot_init_state ) self.scene.robot.spawn.semantic_tags = robot_semantic_tags diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py index 9563cdc4f2fc..355e91789ccc 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py @@ -16,7 +16,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -107,7 +107,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py index 3ab5af14e90c..e7afec6d6a76 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py @@ -12,7 +12,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip @configclass @@ -25,7 +25,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - self.scene.robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_cosmos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_cosmos_env_cfg.py index 4a923b7d618e..24576ff975b0 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_cosmos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_cosmos_env_cfg.py @@ -115,7 +115,7 @@ def __post_init__(self): # Set cameras # Set wrist camera self.scene.wrist_cam = CameraCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand/wrist_cam", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand/wrist_cam", update_period=0.0, height=200, width=200, diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py index 3d5572611523..163008d2d4de 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py @@ -28,7 +28,7 @@ # Pre-defined configs ## from isaaclab.markers.config import FRAME_MARKER_CFG # isort: skip -from isaaclab_assets.robots.franka import FRANKA_PANDA_HIGH_PD_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip # Default arm + gripper joint pose _FRANKA_STACK_IK_REL_INIT_JOINT_POS: dict[str, float] = { @@ -221,7 +221,7 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. self.scene.robot = replace( - FRANKA_PANDA_HIGH_PD_CFG, + FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=ArticulationCfg.InitialStateCfg(joint_pos=_FRANKA_STACK_IK_REL_INIT_JOINT_POS), ) @@ -304,26 +304,26 @@ def __post_init__(self): marker_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) marker_cfg.prim_path = "/Visuals/FrameTransformer" self.scene.ee_frame = FrameTransformerCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", debug_vis=False, visualizer_cfg=marker_cfg, target_frames=[ FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", name="end_effector", offset=OffsetCfg( pos=[0.0, 0.0, 0.1034], ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", name="tool_rightfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", name="tool_leftfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), @@ -335,7 +335,7 @@ def __post_init__(self): # Set cameras # Set wrist camera self.scene.wrist_cam = CameraCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand/wrist_cam", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand/wrist_cam", update_period=0.0, height=200, width=200, diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py index b384e71293b9..639eeb00341e 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py @@ -17,7 +17,7 @@ ## # Pre-defined configs ## -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # isort: skip # Default arm + gripper joint pose _FRANKA_STACK_IK_REL_INIT_JOINT_POS: dict[str, float] = { @@ -51,7 +51,7 @@ def __post_init__(self): # Set Franka as robot self.scene.robot = replace( - FRANKA_PANDA_CFG, + FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=ArticulationCfg.InitialStateCfg(joint_pos=_FRANKA_STACK_IK_REL_INIT_JOINT_POS), ) @@ -76,11 +76,19 @@ def __post_init__(self): # End-effector frame (the shared cubes/spawns come from the base scene). self.scene.ee_frame = make_ee_frame_cfg( - base_prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + base_prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", target_specs=[ - ("{ENV_REGEX_NS}/Robot/panda_hand", "end_effector", (0.0, 0.0, 0.1034)), - ("{ENV_REGEX_NS}/Robot/panda_rightfinger", "tool_rightfinger", (0.0, 0.0, 0.046)), - ("{ENV_REGEX_NS}/Robot/panda_leftfinger", "tool_leftfinger", (0.0, 0.0, 0.046)), + ("{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", "end_effector", (0.0, 0.0, 0.1034)), + ( + "{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", + "tool_rightfinger", + (0.0, 0.0, 0.046), + ), + ( + "{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", + "tool_leftfinger", + (0.0, 0.0, 0.046), + ), ], marker_scale=(0.1, 0.1, 0.1), ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py index c9700331c462..07b483953cd9 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py @@ -25,7 +25,7 @@ # Pre-defined configs ## from isaaclab.markers.config import FRAME_MARKER_CFG # isort: skip -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG # isort: skip +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG # isort: skip @configclass @@ -73,7 +73,7 @@ def __post_init__(self): self.events = EventCfg() # Set Franka as robot - self.scene.robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Set actions for the specific robot type (franka) self.actions.arm_action = mdp.JointPositionActionCfg( @@ -175,26 +175,26 @@ def __post_init__(self): marker_cfg.markers["frame"].scale = (0.1, 0.1, 0.1) marker_cfg.prim_path = "/Visuals/FrameTransformer" self.scene.ee_frame = FrameTransformerCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", debug_vis=False, visualizer_cfg=marker_cfg, target_frames=[ FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", name="end_effector", offset=OffsetCfg( pos=[0.0, 0.0, 0.1034], ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", name="tool_rightfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", name="tool_leftfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/cabinet_direct_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/cabinet_direct_env_cfg.py index b6f5f3e16ef0..5c924518d1af 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/cabinet_direct_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/cabinet_direct_env_cfg.py @@ -9,7 +9,9 @@ from isaaclab.utils import configclass, replace -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG +from isaaclab_tasks.utils import preset + +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG from ...cabinet_direct_env_cfg import CabinetDirectEnvCfg, CabinetDirectSceneCfg @@ -18,7 +20,12 @@ class FrankaCabinetDirectSceneCfg(CabinetDirectSceneCfg): """Direct-workflow cabinet scene configured for the Franka robot.""" - robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + # Drawer interaction only requires hand and fingertip contacts. + robot.spawn.variants = { + "Physics": preset(default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx"), + "Colliders": preset(default="gripper_only", arm_collisions="primitives"), + } @configclass diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/joint_pos_env_cfg.py index 11fb2caee420..63fa550dce65 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/cabinet/config/franka/joint_pos_env_cfg.py @@ -9,7 +9,9 @@ from isaaclab.sensors.frame_transformer import OffsetCfg from isaaclab.utils import configclass, replace -from isaaclab_assets.robots.franka import FRANKA_PANDA_CFG +from isaaclab_tasks.utils import preset + +from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_CFG from ... import mdp from ...cabinet_env_cfg import FRAME_MARKER_SMALL_CFG, CabinetEnvCfg, CabinetSceneCfg @@ -19,28 +21,33 @@ class FrankaCabinetSceneCfg(CabinetSceneCfg): """Cabinet scene configured for the Franka robot.""" - robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + # Drawer interaction only requires hand and fingertip contacts. + robot.spawn.variants = { + "Physics": preset(default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx"), + "Colliders": preset(default="gripper_only", arm_collisions="primitives"), + } ee_frame = FrameTransformerCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_link0", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", debug_vis=False, visualizer_cfg=replace(FRAME_MARKER_SMALL_CFG, prim_path="/Visuals/EndEffectorFrameTransformer"), target_frames=[ FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_hand", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", name="ee_tcp", offset=OffsetCfg( pos=(0.0, 0.0, 0.1034), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", name="tool_leftfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), ), ), FrameTransformerCfg.FrameCfg( - prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger", + prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", name="tool_rightfinger", offset=OffsetCfg( pos=(0.0, 0.0, 0.046), diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py index 1fb5f4847ea5..95059747f04a 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py @@ -24,13 +24,19 @@ from isaaclab.devices.keyboard import Se3KeyboardCfg from isaaclab.devices.spacemouse import Se3SpaceMouseCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg +from isaaclab.managers import RewardTermCfg as RewTerm +from isaaclab.managers import SceneEntityCfg +from isaaclab.managers import TerminationTermCfg as DoneTerm from isaaclab.utils import configclass, replace from isaaclab_tasks.utils import PresetCfg, preset -from isaaclab_assets import FRANKA_PANDA_CFG, FRANKA_PANDA_MENAGERIE_CFG +## +# Pre-defined configs +## +from isaaclab_assets import FRANKA_PANDA_FLAT_CFG # isort: skip -from ...reach_env_cfg import ReachEnvCfg +from ...reach_env_cfg import ReachEnvCfg, RewardsCfg, TerminationsCfg ## # Environment configuration @@ -61,7 +67,9 @@ class FrankaArmActionCfg(PresetCfg): diffik, controller=replace(diffik.controller, use_relative_mode=False, ik_params={"lambda_val": 0.45}), body_offset=None, - scale=1.0, + # Normalize position actions around the center and half-spans of the commanded workspace. + scale=(0.15, 0.2, 0.175, 1.0, 1.0, 1.0, 1.0), + offset=(0.5, 0.0, 0.325, 0.0, 0.0, 0.0, 0.0), ) newton_ik: NewtonInverseKinematicsActionCfg = NewtonInverseKinematicsActionCfg( asset_name="robot", @@ -82,10 +90,32 @@ class FrankaArmActionCfg(PresetCfg): default: mdp.JointPositionActionCfg = joint_pos +@configclass +class FrankaReachRewardsCfg(RewardsCfg): + """Keep continuous pose-tracking rewards specific to Franka Reach.""" + + end_effector_position_tracking_fine_grained = RewTerm( + func=mdp.position_command_error_tanh, + weight=0.1, + params={"asset_cfg": SceneEntityCfg("robot", body_names="panda_hand"), "std": 0.1, "command_name": "ee_pose"}, + ) + success: RewTerm | None = None + + +@configclass +class FrankaReachTerminationsCfg(TerminationsCfg): + """Track Franka Reach success without ending the episode early.""" + + success: DoneTerm | None = None + + @configclass class FrankaReachEnvCfg(ReachEnvCfg): """Franka Reach configuration with selectable arm and physics presets.""" + rewards: FrankaReachRewardsCfg = FrankaReachRewardsCfg() + terminations: FrankaReachTerminationsCfg = FrankaReachTerminationsCfg() + def validate_config(self) -> None: """Validate the selected controller and physics backend.""" if isinstance(self.actions.arm_action, NewtonInverseKinematicsActionCfg) and not isinstance( @@ -96,14 +126,12 @@ def validate_config(self) -> None: def __post_init__(self): super().__post_init__() - # Use the collision-complete legacy asset in PhysX until the Menagerie asset is corrected. - self.scene.robot = replace(FRANKA_PANDA_MENAGERIE_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.usd_path = preset( - default=self.scene.robot.spawn.usd_path, - isaacsim_physx=FRANKA_PANDA_CFG.spawn.usd_path, - physx=FRANKA_PANDA_CFG.spawn.usd_path, - ovphysx=FRANKA_PANDA_CFG.spawn.usd_path, - ) + # Reach has no robot-scene contact objective, so use the fast gripper collider preset. + self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = { + "Physics": preset(default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx"), + "Colliders": preset(default="gripper_only", arm_collisions="primitives"), + } # IK targets need backend-native gravity control to hold steady between commands. self.scene.robot.spawn.rigid_props = [ PhysxRigidBodyCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_osc_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_osc_env_cfg.py index 09c6d8fab2cd..63739cafde7e 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_osc_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_osc_env_cfg.py @@ -42,13 +42,18 @@ def __post_init__(self): super().__post_init__() # Use an explicit actuator to enforce the USD-authored effort limits for effort control. Keep the - # asset's solver velocity limit: the Menagerie USD authors none, so dropping it leaves the arm unbounded. + # asset's solver velocity limit: the canonical USD authors none, so dropping it leaves the arm unbounded. arm_actuator = self.scene.robot.actuators["panda_arm"] self.scene.robot.actuators["panda_arm"] = IdealPDActuatorCfg( joint_names_expr=arm_actuator.joint_names_expr, + joint_effort_limit=arm_actuator.joint_effort_limit, joint_velocity_limit=arm_actuator.joint_velocity_limit, stiffness=0.0, damping=0.0, + armature=arm_actuator.armature, + friction=arm_actuator.friction, + dynamic_friction=arm_actuator.dynamic_friction, + viscous_friction=arm_actuator.viscous_friction, ) for rigid_props in self.scene.robot.spawn.rigid_props: if isinstance(rigid_props, PhysxRigidBodyCfg): diff --git a/source/isaaclab_tasks/test/benchmark/test_render_benchmark_cfg.py b/source/isaaclab_tasks/test/benchmark/test_render_benchmark_cfg.py index 29f4b018c052..e836f2eba01b 100644 --- a/source/isaaclab_tasks/test/benchmark/test_render_benchmark_cfg.py +++ b/source/isaaclab_tasks/test/benchmark/test_render_benchmark_cfg.py @@ -155,18 +155,19 @@ def test_benchmark_mode_orders_joint_updates_and_rendering(mode): @pytest.mark.parametrize( - ("presets", "expected_type"), + ("presets", "expected_type", "expected_asset_physics"), [ - ((), NewtonCfg), - (("physx",), PhysxAutoCfg), - (("isaacsim_physx",), PhysxCfg), - (("ovphysx",), OvPhysxCfg), + ((), NewtonCfg, "mujoco"), + (("physx",), PhysxAutoCfg, "physx"), + (("isaacsim_physx",), PhysxCfg, "physx"), + (("ovphysx",), OvPhysxCfg, "physx"), ], ) -def test_physics_presets_resolve_to_expected_backend(presets, expected_type): +def test_physics_presets_resolve_to_expected_backend(presets, expected_type, expected_asset_physics): cfg = resolve_presets(_load_cfg(), selected=presets) assert isinstance(cfg.sim.physics, expected_type) + assert cfg.scene.robot.spawn.variants["Physics"] == expected_asset_physics @pytest.mark.parametrize("physics_preset", ["ovphysx", "physx"]) diff --git a/source/isaaclab_tasks/test/contrib/test_franka_pour_env_cfg.py b/source/isaaclab_tasks/test/contrib/test_franka_pour_env_cfg.py index 4e80cafc5d71..1728396c2f9a 100644 --- a/source/isaaclab_tasks/test/contrib/test_franka_pour_env_cfg.py +++ b/source/isaaclab_tasks/test/contrib/test_franka_pour_env_cfg.py @@ -113,7 +113,7 @@ def test_reset_dataset_contract_stores_root_relative_robot_asset_path(): robot_asset = _reset_dataset_task_contract(cfg)["robot_asset"] assert robot_asset == "Robots/FrankaEmika/franka_panda.usda" assert f"{ISAACLAB_NUCLEUS_DIR}/{robot_asset}" == FRANKA_POUR_ROBOT_ASSET_ID - assert cfg.scene.robot.spawn.variants == {"Colliders": "convex_hulls"} + assert cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "convex_hulls"} def test_capacity_resolution_only_updates_world_dependent_solver_limits(): diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index dcb0fe7f7728..05f10be6fec6 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -22,11 +22,26 @@ from isaaclab_tasks.utils.preset_cli import enumerate_task_presets from isaaclab_tasks.utils.preset_target import PresetTarget -from isaaclab_assets import FRANKA_PANDA_MENAGERIE_CFG +from isaaclab_assets import FRANKA_PANDA_FLAT_CFG _TASK = "Isaac-Reach-Franka" _OSC_TASK = "Isaac-Reach-Franka-OSC" _CONTRIB_DIFFIK_ABS_TASK = "IsaacContrib-Reach-Franka-IK-Abs" +_RIGID_FRANKA_TASKS = ( + _TASK, + _OSC_TASK, + "Isaac-Open-Drawer-Franka", + "Isaac-Open-Drawer-Franka-Direct", + "Isaac-Lift-Franka", +) +_SOFT_FRANKA_TASKS = ( + "Isaac-Lift-Soft-Franka", + "Isaac-Lift-Cloth-Franka", + "Isaac-Lift-Cable-Franka", + "Isaac-Lift-Soft-Franka-Camera", + "Isaac-Lift-Cloth-Franka-Camera", + "Isaac-Lift-Cable-Franka-Camera", +) def _load_env_cfg(*presets: str): @@ -48,6 +63,28 @@ def _without_controller_dependent_cfg(cfg): return cfg_dict +@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS + _SOFT_FRANKA_TASKS) +def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task): + default_cfg = _load_reach_env_cfg(task) + physx_cfg = _load_reach_env_cfg(task, "isaacsim_physx") + + for cfg, physics_variant in ((default_cfg, "mujoco"), (physx_cfg, "physx")): + assert cfg.scene.robot.spawn.usd_path == FRANKA_PANDA_FLAT_CFG.spawn.usd_path + assert cfg.scene.robot.spawn.variants == { + "Physics": physics_variant, + "Colliders": "gripper_only", + } + + +@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS) +def test_rigid_franka_arm_collisions_are_an_independent_domain_preset(task): + newton_cfg = _load_reach_env_cfg(task, "arm_collisions") + physx_cfg = _load_reach_env_cfg(task, "arm_collisions", "isaacsim_physx") + + assert newton_cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "primitives"} + assert physx_cfg.scene.robot.spawn.variants == {"Physics": "physx", "Colliders": "primitives"} + + def test_reach_diffik_abs_legacy_task_is_a_deprecated_alias(): spec = registry[_CONTRIB_DIFFIK_ABS_TASK] @@ -95,6 +132,10 @@ def test_reach_ur10_physics_presets_change_only_physics(): physx = _load_reach_env_cfg("Isaac-Reach-UR10", "isaacsim_physx") newton = _load_reach_env_cfg("Isaac-Reach-UR10", "newton_mjwarp") + assert physx.rewards.success.func is mdp.is_terminated_term + assert physx.terminations.success.func is mdp.pose_command_success + assert not hasattr(physx.rewards, "end_effector_position_tracking_fine_grained") + physx_cfg = to_dict(physx) newton_cfg = to_dict(newton) physx_cfg["sim"].pop("physics") @@ -136,7 +177,24 @@ def test_reach_diffik_physx_configures_teleop_physics(): assert physx_props.max_depenetration_velocity == pytest.approx(5.0) assert not cfg.scene.robot.spawn.make_uninstanceable assert cfg.scene.robot.spawn.collision_props is None - assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/Legacy/panda_instanceable.usd") + assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") + assert cfg.scene.robot.spawn.variants == {"Physics": "physx", "Colliders": "gripper_only"} + + +def test_reach_diffik_abs_normalizes_position_actions_to_command_workspace(): + cfg = _load_env_cfg("diffik_abs", "isaacsim_physx") + action = cfg.actions.arm_action + ranges = cfg.commands.ee_pose.ranges + + position_scale = torch.tensor(action.scale[:3]) + position_offset = torch.tensor(action.offset[:3]) + expected_lower = torch.tensor([ranges.pos_x[0], ranges.pos_y[0], ranges.pos_z[0]]) + expected_upper = torch.tensor([ranges.pos_x[1], ranges.pos_y[1], ranges.pos_z[1]]) + + torch.testing.assert_close(position_offset - position_scale, expected_lower) + torch.testing.assert_close(position_offset + position_scale, expected_upper) + assert action.scale[3:] == (1.0, 1.0, 1.0, 1.0) + assert action.offset[3:] == (0.0, 0.0, 0.0, 0.0) def test_reach_newton_ik_configures_gravity_compensation(): @@ -146,6 +204,7 @@ def test_reach_newton_ik_configures_gravity_compensation(): mujoco_props = next(props for props in rigid_props if isinstance(props, MujocoRigidBodyCfg)) assert mujoco_props.gravcomp == pytest.approx(1.0) assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") + assert cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "gripper_only"} # Native SE(3) command convention: one relative 6-DoF pose objective. pose_objectives = [ @@ -163,17 +222,17 @@ def test_reach_default_preset_does_not_configure_se3_teleop_devices(): assert cfg.teleop_devices.devices == {} -def test_reach_success_requires_position_and_orientation(): +def test_reach_tracks_success_without_terminating(): cfg = _load_env_cfg() - success = cfg.terminations.success assert cfg.commands.ee_pose.position_success_threshold == pytest.approx(0.05) assert cfg.commands.ee_pose.orientation_success_threshold == pytest.approx(0.2) - assert success.func is mdp.pose_command_success - assert success.params == {"command_name": "ee_pose"} - assert cfg.rewards.success.func.__name__ == "is_terminated_term" - assert cfg.rewards.success.weight == pytest.approx(10.0) - assert cfg.rewards.success.params == {"term_keys": ["success"]} + assert cfg.terminations.success is None + assert cfg.terminations.time_out.func is mdp.time_out + assert cfg.rewards.success is None + assert cfg.rewards.end_effector_position_tracking_fine_grained.func is mdp.position_command_error_tanh + assert cfg.rewards.end_effector_position_tracking_fine_grained.weight == pytest.approx(0.1) + assert cfg.rewards.end_effector_position_tracking_fine_grained.params["std"] == pytest.approx(0.1) angles = torch.tensor([0.19, 0.19, 0.21]) body_quaternions = torch.zeros(3, 1, 4) @@ -197,32 +256,32 @@ def test_reach_success_requires_position_and_orientation(): command._track_success = True command._succeeded = torch.zeros(3, dtype=torch.bool) - class CommandManager: - def get_term(self, name): - assert name == "ee_pose" - return command - - env = SimpleNamespace(command_manager=CommandManager()) - succeeded = mdp.pose_command_success(env, **success.params) + succeeded = command.compute_success() assert torch.equal(succeeded, torch.tensor([True, False, False])) assert torch.equal(command._succeeded, succeeded) command.cfg = replace(command.cfg, orientation_success_threshold=None) command._succeeded.zero_() - position_only_succeeded = mdp.pose_command_success(env, **success.params) + position_only_succeeded = command.compute_success() assert torch.equal(position_only_succeeded, torch.tensor([True, False, True])) -def test_reach_osc_effort_actuator_keeps_menagerie_velocity_limit(): - """The zero-gain effort actuator must keep the asset's solver velocity limit; the USD authors none.""" +def test_reach_osc_effort_actuator_keeps_canonical_solver_properties(): + """Replacing the arm actuator with a zero-gain effort model must preserve its solver properties.""" cfg = _load_reach_env_cfg(_OSC_TASK) arm_actuator = cfg.scene.robot.actuators["panda_arm"] + source_actuator = FRANKA_PANDA_FLAT_CFG.actuators["panda_arm"] assert isinstance(arm_actuator, IdealPDActuatorCfg) assert arm_actuator.stiffness == 0.0 and arm_actuator.damping == 0.0 - assert arm_actuator.joint_velocity_limit == FRANKA_PANDA_MENAGERIE_CFG.actuators["panda_arm"].joint_velocity_limit + assert arm_actuator.joint_effort_limit == source_actuator.joint_effort_limit + assert arm_actuator.joint_velocity_limit == source_actuator.joint_velocity_limit + assert arm_actuator.armature == source_actuator.armature + assert arm_actuator.friction == source_actuator.friction + assert arm_actuator.dynamic_friction == source_actuator.dynamic_friction + assert arm_actuator.viscous_friction == source_actuator.viscous_friction def test_reach_osc_resolves_controller_preset_values_to_defaults(): @@ -240,7 +299,7 @@ def test_reach_osc_resolves_controller_preset_values_to_defaults(): assert physx_props.disable_gravity is True assert mujoco_props.gravcomp == pytest.approx(1.0) assert cfg.teleop_devices.devices == {} - assert domain_presets == {"diffik_abs"} + assert domain_presets == {"arm_collisions", "diffik_abs"} def test_reach_osc_diffik_abs_is_a_deprecated_no_op_alias(): From b0f54b417b7c535586eab14aec2e9afb7e5e72ee Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 19:16:15 +0200 Subject: [PATCH 03/24] Update Franka environment browser presets --- docs/source/_static/css/environment-browser.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/_static/css/environment-browser.js b/docs/source/_static/css/environment-browser.js index dadfd2dca455..4fd9d622d605 100644 --- a/docs/source/_static/css/environment-browser.js +++ b/docs/source/_static/css/environment-browser.js @@ -30,11 +30,11 @@ ["Isaac-Lift-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}], ["Isaac-Lift-Soft-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"], ["Isaac-Lift-Soft-Franka-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"], - ["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], - ["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], + ["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"], + ["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"], ["Isaac-Pendulum-MARL-Direct", "rl_games,skrl", "isaacsim_physx,newton_kamino,newton_mjwarp,ovphysx", "", "", "tasks/classic/cart_double_pendulum.jpg", false, {}, {"skrl": "MAPPO"}], - ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], - ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], + ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], + ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], ["Isaac-Reach-UR10", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/ur10_reach.jpg", true], ["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}], ["Isaac-Reorient-Cube-Allegro-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/allegro_cube.jpg", true], @@ -92,12 +92,12 @@ ["IsaacContrib-Lift-Cube-Franka-IK-Abs", "", "", "", "", "tasks/manipulation/franka_lift.jpg"], ["IsaacContrib-Lift-Cube-Franka-IK-Rel", "", "", "", "", "tasks/manipulation/franka_lift.jpg"], ["IsaacContrib-Lift-Cube-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_lift.jpg"], - ["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "", "tasks/manipulation/multitask_manipulation.jpg"], + ["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "arm_collisions", "tasks/manipulation/multitask_manipulation.jpg"], ["IsaacContrib-Navigation-3DObstacles-ARL-Robot-1", "rl_games,rsl_rl,skrl", "", "", "", "tasks/drone_arl/arl_robot_1_navigation.jpg"], ["IsaacContrib-Navigation-Flat-AnymalC", "rsl_rl,skrl", "", "", "", "tasks/navigation/anymal_c_nav.jpg"], ["IsaacContrib-NutPour-GR1T2-Pink-IK-Abs", "", "", "", ""], - ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""], - ["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""], + ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"], + ["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"], ["IsaacContrib-Open-Drawer-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_open_drawer.jpg"], ["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"], ["IsaacContrib-PickPlace-G1-InspireFTP-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place.jpg"], From 4f84d15452431ac50d075559faf65a637ecf696a Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 19:19:44 +0200 Subject: [PATCH 04/24] Verify backend payload selection for cabinet IK --- .../test/core/test_preset_kit_decision.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source/isaaclab_tasks/test/core/test_preset_kit_decision.py b/source/isaaclab_tasks/test/core/test_preset_kit_decision.py index 5d9a125df4f4..544a8c888b6b 100644 --- a/source/isaaclab_tasks/test/core/test_preset_kit_decision.py +++ b/source/isaaclab_tasks/test/core/test_preset_kit_decision.py @@ -23,7 +23,7 @@ import isaaclab_tasks # noqa: F401 from isaaclab_tasks.utils import resolve_task_config -from isaaclab_tasks.utils.hydra import collect_presets +from isaaclab_tasks.utils.hydra import collect_presets, resolve_presets from isaaclab_tasks.utils.parse_cfg import load_cfg_from_registry from isaaclab_tasks.utils.preset_cli import enumerate_task_presets from isaaclab_tasks.utils.preset_target import PresetTarget @@ -127,6 +127,20 @@ def test_registered_task_physx_presets_keep_auto_selection_explicit(): assert fields.get("isaacsim_physx") == fields["physx"], location +@pytest.mark.parametrize( + "task_id", ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "IsaacContrib-Open-Drawer-Franka-IK-Rel"] +) +@pytest.mark.parametrize( + ("physics_preset", "expected_asset_physics"), + [("newton_mjwarp", "mujoco"), ("isaacsim_physx", "physx"), ("ovphysx", "physx")], +) +def test_franka_cabinet_ik_asset_variant_matches_backend(task_id, physics_preset, expected_asset_physics): + """The IK robot override retains the cabinet task's backend-aware asset selection.""" + cfg = resolve_presets(load_cfg_from_registry(task_id, "env_cfg_entry_point"), selected=(physics_preset,)) + + assert cfg.scene.robot.spawn.variants["Physics"] == expected_asset_physics + + def test_registered_manager_based_configs_name_their_env_class(): """A manager-based task's ``class_type`` constructs the env class its registration names.""" From e1ffab9a8bb962fbd6e37686ccb4c452133548ab Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 19:24:01 +0200 Subject: [PATCH 05/24] Scope shared-asset tests to migrated rigid tasks --- .../test/core/test_reach_franka_presets.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index 05f10be6fec6..21794de95c49 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -32,15 +32,6 @@ _OSC_TASK, "Isaac-Open-Drawer-Franka", "Isaac-Open-Drawer-Franka-Direct", - "Isaac-Lift-Franka", -) -_SOFT_FRANKA_TASKS = ( - "Isaac-Lift-Soft-Franka", - "Isaac-Lift-Cloth-Franka", - "Isaac-Lift-Cable-Franka", - "Isaac-Lift-Soft-Franka-Camera", - "Isaac-Lift-Cloth-Franka-Camera", - "Isaac-Lift-Cable-Franka-Camera", ) @@ -63,7 +54,7 @@ def _without_controller_dependent_cfg(cfg): return cfg_dict -@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS + _SOFT_FRANKA_TASKS) +@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS) def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task): default_cfg = _load_reach_env_cfg(task) physx_cfg = _load_reach_env_cfg(task, "isaacsim_physx") From c40b2adf1955806f0bce7389e1536b48fbc3ad7f Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 23:31:54 +0200 Subject: [PATCH 06/24] Preserve Franka compatibility and fix direct clone matching --- source/isaaclab/isaaclab/sim/utils/queries.py | 3 +- source/isaaclab/test/sim/test_cloner.py | 18 +++ .../maximiliank-franka-flat-config.minor.rst | 8 +- .../isaaclab_assets/__init__.pyi | 2 - .../isaaclab_assets/robots/__init__.pyi | 2 - .../isaaclab_assets/robots/franka.py | 122 +++++++++--------- .../test/test_valid_configs.py | 6 +- .../test/assets/test_articulation.py | 4 +- .../frame_transformer/frame_transformer.py | 6 +- .../test/assets/test_articulation.py | 2 +- .../frame_transformer/frame_transformer.py | 6 +- 11 files changed, 100 insertions(+), 79 deletions(-) diff --git a/source/isaaclab/isaaclab/sim/utils/queries.py b/source/isaaclab/isaaclab/sim/utils/queries.py index b73ae060289a..dc5c973ba033 100644 --- a/source/isaaclab/isaaclab/sim/utils/queries.py +++ b/source/isaaclab/isaaclab/sim/utils/queries.py @@ -471,6 +471,7 @@ def resolve_matching_prims_from_source( path = prim.GetPath().pathString if path == instance_root or path.startswith(instance_root + "/"): results.append((prim, instance_expr + path[len(instance_root) :])) + direct_source_paths = {source.GetPath().pathString for source, _ in results} if prefer_direct_matches else set() if predicate is not None: # Whole-path regexes can select both a prim and its ancestors; their descendant sets overlap. unique_matches = {} @@ -485,7 +486,7 @@ def resolve_matching_prims_from_source( results = list(unique_matches.values()) if prefer_direct_matches: - direct_matches = [pair for pair in results if re.fullmatch(path_expr, pair[0].GetPath().pathString)] + direct_matches = [pair for pair in results if pair[0].GetPath().pathString in direct_source_paths] if direct_matches: results = direct_matches diff --git a/source/isaaclab/test/sim/test_cloner.py b/source/isaaclab/test/sim/test_cloner.py index 7ea2acef280c..ea45ced6568e 100644 --- a/source/isaaclab/test/sim/test_cloner.py +++ b/source/isaaclab/test/sim/test_cloner.py @@ -293,3 +293,21 @@ def test_resolve_matching_prims_from_source(sim, with_clone_plan): prefer_direct_matches=True, ) assert [prim.GetPath().pathString for prim, _ in matches] == ["/World/envs/env_0/Robot/foo"] + + +def test_resolve_direct_match_from_external_prototype(sim): + """Prefer the requested body even when its prototype is outside the destination namespace.""" + stage = sim_utils.get_current_stage() + stage.DefinePrim("/World/template/Robot/foo/bar", "Xform") + asset = AssetBaseCfg(prim_path="/World/envs/env_[^/]+/Robot", spawn=SpawnerCfg(spawn_path="/World/template/Robot")) + sim.set_clone_plan(make_clone_plan((asset,), ((0,),), 2)) + + matches = queries.resolve_matching_prims_from_source( + r"/World/envs/env_[^/]+/Robot/foo", + predicate=lambda prim: prim.GetName() in {"foo", "bar"}, + expected_num_matches=1, + prefer_direct_matches=True, + ) + assert [(prim.GetPath().pathString, path) for prim, path in matches] == [ + ("/World/template/Robot/foo", "/World/envs/env_[^/]+/Robot/foo") + ] diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst index 6618848f9c25..33ce4a3d797c 100644 --- a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst @@ -9,6 +9,8 @@ Deprecated ^^^^^^^^^^ * Deprecated ``FRANKA_PANDA_CFG``, ``FRANKA_PANDA_HIGH_PD_CFG``, and - ``FRANKA_PANDA_MENAGERIE_CFG``. Their previous asset and actuator contracts remained available - during the deprecation window. Use the corresponding ``FRANKA_PANDA_FLAT_*`` configuration to - migrate to the shared flat asset, and replace shoulder/forearm actuator overrides with ``panda_arm``. + ``FRANKA_PANDA_MENAGERIE_CFG`` for removal in Isaac Lab 4.0. The legacy Panda USD and actuator + groups remain available through the first two names. **Breaking:** the nested Menagerie USD moved + from ``franka_panda.usda`` to ``franka_panda_nestedInstance.usda``; code that reads or overrides + its path must use the new filename. Migrate to the corresponding ``FRANKA_PANDA_FLAT_*`` config, + replace shoulder/forearm actuator overrides with ``panda_arm``, and select the backend's ``Physics`` variant. diff --git a/source/isaaclab_assets/isaaclab_assets/__init__.pyi b/source/isaaclab_assets/isaaclab_assets/__init__.pyi index b38edb800a5f..2c71864ac40e 100644 --- a/source/isaaclab_assets/isaaclab_assets/__init__.pyi +++ b/source/isaaclab_assets/isaaclab_assets/__init__.pyi @@ -25,7 +25,6 @@ __all__ = [ "FRANKA_PANDA_FLAT_CFG", "FRANKA_PANDA_FLAT_HIGH_PD_CFG", "FRANKA_PANDA_HIGH_PD_CFG", - "FRANKA_PANDA_LEGACY_CFG", "FRANKA_PANDA_MENAGERIE_CFG", "FRANKA_ROBOTIQ_GRIPPER_CFG", "FOURBAR_POLE_CFG", @@ -95,7 +94,6 @@ from .robots import ( FRANKA_PANDA_FLAT_CFG, FRANKA_PANDA_FLAT_HIGH_PD_CFG, FRANKA_PANDA_HIGH_PD_CFG, - FRANKA_PANDA_LEGACY_CFG, FRANKA_PANDA_MENAGERIE_CFG, FRANKA_ROBOTIQ_GRIPPER_CFG, FOURBAR_POLE_CFG, diff --git a/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi b/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi index e54481a15ee5..aed6774c314c 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi +++ b/source/isaaclab_assets/isaaclab_assets/robots/__init__.pyi @@ -25,7 +25,6 @@ __all__ = [ "FRANKA_PANDA_FLAT_CFG", "FRANKA_PANDA_FLAT_HIGH_PD_CFG", "FRANKA_PANDA_HIGH_PD_CFG", - "FRANKA_PANDA_LEGACY_CFG", "FRANKA_PANDA_MENAGERIE_CFG", "FRANKA_ROBOTIQ_GRIPPER_CFG", "FOURBAR_POLE_CFG", @@ -88,7 +87,6 @@ from .franka import ( FRANKA_PANDA_FLAT_CFG, FRANKA_PANDA_FLAT_HIGH_PD_CFG, FRANKA_PANDA_HIGH_PD_CFG, - FRANKA_PANDA_LEGACY_CFG, FRANKA_PANDA_MENAGERIE_CFG, FRANKA_ROBOTIQ_GRIPPER_CFG, ) diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index 11849e12b234..dabb72a2025d 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -9,14 +9,14 @@ * :obj:`FRANKA_PANDA_FLAT_CFG`: Shared flat asset for maintained Franka tasks * :obj:`FRANKA_PANDA_FLAT_HIGH_PD_CFG`: Flat asset with stiffer PD control -* :obj:`FRANKA_PANDA_LEGACY_CFG`: Legacy Franka Emika Panda asset configuration * :obj:`FRANKA_PANDA_CFG`: Deprecated alias retaining the legacy asset and actuators * :obj:`FRANKA_PANDA_HIGH_PD_CFG`: Deprecated legacy high-PD configuration * :obj:`FRANKA_PANDA_MENAGERIE_CFG`: Deprecated nested-instance Menagerie configuration * :obj:`FRANKA_ROBOTIQ_GRIPPER_CFG`: Franka robot with Robotiq_2f_85 gripper -The old public names retain their original configuration contracts for the deprecation window. Use -``FRANKA_PANDA_FLAT_CFG`` for new code and select its ``Physics`` variant for the chosen backend. +The old public names remain available during deprecation. Use ``FRANKA_PANDA_FLAT_CFG`` for new code +and select its ``Physics`` variant for the chosen backend. The former Menagerie asset was relocated to +``franka_panda_nestedInstance.usda``; the flat asset now occupies ``franka_panda.usda``. Reference: https://github.com/frankaemika/franka_ros """ @@ -37,7 +37,7 @@ # Configuration ## -FRANKA_PANDA_LEGACY_CFG = ArticulationCfg( +_FRANKA_PANDA_LEGACY_CFG = ArticulationCfg( spawn=sim_utils.UsdFileCfg( usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/Legacy/panda_instanceable.usd", activate_contact_sensors=False, @@ -89,7 +89,7 @@ """Configuration of the legacy Franka Emika Panda robot asset.""" -FRANKA_PANDA_FLAT_CFG = clone(FRANKA_PANDA_LEGACY_CFG) +FRANKA_PANDA_FLAT_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) FRANKA_PANDA_FLAT_CFG.spawn.usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda" FRANKA_PANDA_FLAT_CFG.spawn.variants = {"Physics": "physx", "Colliders": "gripper_only"} next( @@ -142,64 +142,7 @@ """ -_FRANKA_PANDA_COMPAT_CFG = clone(FRANKA_PANDA_LEGACY_CFG) - - -_FRANKA_PANDA_LEGACY_HIGH_PD_CFG = clone(FRANKA_PANDA_LEGACY_CFG) -_FRANKA_PANDA_LEGACY_HIGH_PD_CFG.spawn.rigid_props.disable_gravity = True -for actuator in ("panda_shoulder", "panda_forearm"): - _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].stiffness = 400.0 - _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].damping = 80.0 - - -_FRANKA_PANDA_NESTED_MENAGERIE_CFG = clone(FRANKA_PANDA_LEGACY_CFG) -_FRANKA_PANDA_NESTED_MENAGERIE_CFG.spawn.usd_path = ( - f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda_nestedInstance.usda" -) -_FRANKA_PANDA_NESTED_MENAGERIE_CFG.actuators = { - "panda_arm": ImplicitActuatorCfg( - joint_names_expr=["panda_joint[1-7]"], - joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, - stiffness=None, - damping=None, - ), - "panda_hand": ImplicitActuatorCfg( - joint_names_expr=["panda_finger_joint.*"], - stiffness=None, - damping=None, - ), -} - - -_DEPRECATED_FRANKA_CFGS = { - "FRANKA_PANDA_CFG": (_FRANKA_PANDA_COMPAT_CFG, "FRANKA_PANDA_FLAT_CFG"), - "FRANKA_PANDA_HIGH_PD_CFG": (_FRANKA_PANDA_LEGACY_HIGH_PD_CFG, "FRANKA_PANDA_FLAT_HIGH_PD_CFG"), - "FRANKA_PANDA_MENAGERIE_CFG": (_FRANKA_PANDA_NESTED_MENAGERIE_CFG, "FRANKA_PANDA_FLAT_CFG"), -} - -if TYPE_CHECKING: - FRANKA_PANDA_CFG: ArticulationCfg - FRANKA_PANDA_HIGH_PD_CFG: ArticulationCfg - FRANKA_PANDA_MENAGERIE_CFG: ArticulationCfg - - -def __getattr__(name: str) -> ArticulationCfg: - if name not in _DEPRECATED_FRANKA_CFGS: - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - cfg, replacement = _DEPRECATED_FRANKA_CFGS[name] - warnings.warn( - f"{name} is deprecated; use {replacement} for the flat Franka asset.", - FutureWarning, - stacklevel=2, - ) - return cfg - - -def __dir__() -> list[str]: - return sorted(set(globals()) | _DEPRECATED_FRANKA_CFGS.keys()) - - -FRANKA_ROBOTIQ_GRIPPER_CFG = clone(FRANKA_PANDA_LEGACY_CFG) +FRANKA_ROBOTIQ_GRIPPER_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.usd_path = f"{ISAAC_NUCLEUS_DIR}/Robots/FrankaRobotics/FrankaPanda/franka.usd" FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.variants = {"Gripper": "Robotiq_2F_85"} FRANKA_ROBOTIQ_GRIPPER_CFG.spawn.rigid_props.disable_gravity = True @@ -259,3 +202,56 @@ def __dir__() -> list[str]: """Configuration of Franka Emika Panda robot with Robotiq_2f_85 gripper.""" + + +_FRANKA_PANDA_LEGACY_HIGH_PD_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) +_FRANKA_PANDA_LEGACY_HIGH_PD_CFG.spawn.rigid_props.disable_gravity = True +for actuator in ("panda_shoulder", "panda_forearm"): + _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].stiffness = 400.0 + _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].damping = 80.0 + + +_FRANKA_PANDA_NESTED_MENAGERIE_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) +_FRANKA_PANDA_NESTED_MENAGERIE_CFG.spawn.usd_path = ( + f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda_nestedInstance.usda" +) +_FRANKA_PANDA_NESTED_MENAGERIE_CFG.actuators = { + "panda_arm": ImplicitActuatorCfg( + joint_names_expr=["panda_joint[1-7]"], + joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, + stiffness=None, + damping=None, + ), + "panda_hand": ImplicitActuatorCfg( + joint_names_expr=["panda_finger_joint.*"], + stiffness=None, + damping=None, + ), +} + + +_DEPRECATED_FRANKA_CFGS = { + "FRANKA_PANDA_CFG": (_FRANKA_PANDA_LEGACY_CFG, "FRANKA_PANDA_FLAT_CFG"), + "FRANKA_PANDA_HIGH_PD_CFG": (_FRANKA_PANDA_LEGACY_HIGH_PD_CFG, "FRANKA_PANDA_FLAT_HIGH_PD_CFG"), + "FRANKA_PANDA_MENAGERIE_CFG": (_FRANKA_PANDA_NESTED_MENAGERIE_CFG, "FRANKA_PANDA_FLAT_CFG"), +} + +if TYPE_CHECKING: + FRANKA_PANDA_CFG: ArticulationCfg + FRANKA_PANDA_HIGH_PD_CFG: ArticulationCfg + FRANKA_PANDA_MENAGERIE_CFG: ArticulationCfg + + +def __getattr__(name: str) -> ArticulationCfg: + if name not in _DEPRECATED_FRANKA_CFGS: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + cfg, replacement = _DEPRECATED_FRANKA_CFGS[name] + message = f"{name} is deprecated and will be removed in Isaac Lab 4.0. Use {replacement}." + if name == "FRANKA_PANDA_MENAGERIE_CFG": + message += " The nested asset moved from franka_panda.usda to franka_panda_nestedInstance.usda." + warnings.warn(message, DeprecationWarning, stacklevel=2) + return cfg + + +def __dir__() -> list[str]: + return sorted(set(globals()) | _DEPRECATED_FRANKA_CFGS.keys()) diff --git a/source/isaaclab_assets/test/test_valid_configs.py b/source/isaaclab_assets/test/test_valid_configs.py index b267e4862bd4..e520f072f532 100644 --- a/source/isaaclab_assets/test/test_valid_configs.py +++ b/source/isaaclab_assets/test/test_valid_configs.py @@ -24,18 +24,18 @@ def test_franka_legacy_configs_warn_and_keep_their_contract() -> None: """Deprecated Franka names retain their previous asset and actuator contracts.""" - with pytest.warns(FutureWarning, match="FRANKA_PANDA_CFG.*deprecated"): + with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_CFG.*removed in Isaac Lab 4.0"): legacy_cfg = franka_assets.FRANKA_PANDA_CFG assert legacy_cfg.spawn.usd_path.endswith("/Legacy/panda_instanceable.usd") assert set(legacy_cfg.actuators) == {"panda_shoulder", "panda_forearm", "panda_hand"} - with pytest.warns(FutureWarning, match="FRANKA_PANDA_HIGH_PD_CFG.*deprecated"): + with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_HIGH_PD_CFG.*removed in Isaac Lab 4.0"): high_pd_cfg = franka_assets.FRANKA_PANDA_HIGH_PD_CFG assert high_pd_cfg.spawn.usd_path == legacy_cfg.spawn.usd_path assert high_pd_cfg.actuators["panda_shoulder"].stiffness == 400.0 assert high_pd_cfg.actuators["panda_forearm"].stiffness == 400.0 - with pytest.warns(FutureWarning, match="FRANKA_PANDA_MENAGERIE_CFG.*deprecated"): + with pytest.warns(DeprecationWarning, match="franka_panda_nestedInstance.usda"): menagerie_cfg = franka_assets.FRANKA_PANDA_MENAGERIE_CFG assert menagerie_cfg.spawn.usd_path.endswith("/franka_panda_nestedInstance.usda") assert set(menagerie_cfg.actuators) == {"panda_arm", "panda_hand"} diff --git a/source/isaaclab_newton/test/assets/test_articulation.py b/source/isaaclab_newton/test/assets/test_articulation.py index 9cc6e1787eac..fb8838de2943 100644 --- a/source/isaaclab_newton/test/assets/test_articulation.py +++ b/source/isaaclab_newton/test/assets/test_articulation.py @@ -69,9 +69,9 @@ from isaaclab_assets import ANYMAL_C_CFG, FRANKA_PANDA_FLAT_CFG, FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort:skip from isaaclab_assets.robots.shadow_hand import SHADOW_HAND_NEWTON_CFG -_FRANKA_PANDA_NEWTON_CFG = FRANKA_PANDA_FLAT_CFG.copy() +_FRANKA_PANDA_NEWTON_CFG = clone(FRANKA_PANDA_FLAT_CFG) _FRANKA_PANDA_NEWTON_CFG.spawn.variants = {"Physics": "mujoco", "Colliders": "gripper_only"} -_FRANKA_PANDA_HIGH_PD_NEWTON_CFG = FRANKA_PANDA_FLAT_HIGH_PD_CFG.copy() +_FRANKA_PANDA_HIGH_PD_NEWTON_CFG = clone(FRANKA_PANDA_FLAT_HIGH_PD_CFG) _FRANKA_PANDA_HIGH_PD_NEWTON_CFG.spawn.variants = {"Physics": "mujoco", "Colliders": "gripper_only"} SIM_CFGs = { diff --git a/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py b/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py index f5a001c43eff..f0d393863a0d 100644 --- a/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py +++ b/source/isaaclab_ov/isaaclab_ov/sensors/frame_transformer/frame_transformer.py @@ -178,7 +178,6 @@ def has_rigid_body_api(prim) -> bool: matches = resolve_matching_prims_from_source( prim_path, predicate=has_rigid_body_api, - expected_num_matches=1 if frame_type == "source" else None, raise_if_no_matches=False, prefer_direct_matches=True, ) @@ -187,6 +186,11 @@ def has_rigid_body_api(prim) -> bool: f"Failed to create frame transformer for frame '{frame}' with path '{prim_path}'." " No matching rigid-body prims were found." ) + if frame_type == "source" and len(matches) != 1: + raise ValueError( + f"Expected one source rigid-body prim for frame '{frame}' with path '{prim_path}'," + f" found {len(matches)}." + ) for prim, matching_prim_path in matches: # Get the name of the body: use relative prim path for unique identification body_name = self._get_relative_body_path(matching_prim_path) diff --git a/source/isaaclab_ov/test/assets/test_articulation.py b/source/isaaclab_ov/test/assets/test_articulation.py index 0c7a57456c27..996d8d934cc6 100644 --- a/source/isaaclab_ov/test/assets/test_articulation.py +++ b/source/isaaclab_ov/test/assets/test_articulation.py @@ -530,7 +530,7 @@ def generate_articulation( @pytest.mark.parametrize("device", ["cuda:0"]) @pytest.mark.parametrize("gravity_enabled", [False]) -def test_franka_newton_mimic_constraint_tracks_passive_finger(sim, device, gravity_enabled): +def test_franka_ovphysx_mimic_constraint_tracks_passive_finger(sim, device, gravity_enabled): """Drive only the Franka leader finger and preserve mimic tracking in every clone.""" articulation, _ = generate_articulation(FRANKA_PANDA_FLAT_CFG, 2, device) sim.reset() diff --git a/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py b/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py index 1f17ce8463b2..bd9d6a2a1b56 100644 --- a/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py +++ b/source/isaaclab_physx/isaaclab_physx/sensors/frame_transformer/frame_transformer.py @@ -194,7 +194,6 @@ def has_rigid_body_api(prim) -> bool: matches = resolve_matching_prims_from_source( prim_path, has_rigid_body_api, - expected_num_matches=1 if frame_type == "source" else None, raise_if_no_matches=False, prefer_direct_matches=True, ) @@ -203,6 +202,11 @@ def has_rigid_body_api(prim) -> bool: f"Failed to create frame transformer for frame '{frame}' with path '{prim_path}'." " No matching rigid-body prims were found." ) + if frame_type == "source" and len(matches) != 1: + raise ValueError( + f"Expected one source rigid-body prim for frame '{frame}' with path '{prim_path}'," + f" found {len(matches)}." + ) for prim, matching_prim_path in matches: # Get the name of the body: use relative prim path for unique identification body_name = self._get_relative_body_path(matching_prim_path) From 69031a3f683ded5a99daa6201bb602fa482510b6 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Tue, 29 Sep 2026 23:36:16 +0200 Subject: [PATCH 07/24] Align Reach preset test with preserved Menagerie asset --- .../changelog.d/maximiliank-franka-menagerie-path-test.skip | 0 source/isaaclab_tasks/test/core/test_reach_franka_presets.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip b/source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index dcb0fe7f7728..a3c29be66171 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -145,7 +145,7 @@ def test_reach_newton_ik_configures_gravity_compensation(): mujoco_props = next(props for props in rigid_props if isinstance(props, MujocoRigidBodyCfg)) assert mujoco_props.gravcomp == pytest.approx(1.0) - assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") + assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda_nestedInstance.usda") # Native SE(3) command convention: one relative 6-DoF pose objective. pose_objectives = [ From 6f4affdee0e6838b25d30c12a5edde8fd29546ef Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 00:05:01 +0200 Subject: [PATCH 08/24] Keep published Menagerie URL during Franka migration --- .../maximiliank-franka-flat-config.minor.rst | 11 ++++++----- .../isaaclab_assets/robots/franka.py | 18 +++++++----------- .../isaaclab_assets/test/test_valid_configs.py | 4 ++-- ...maximiliank-franka-menagerie-path-test.skip | 0 .../test/core/test_reach_franka_presets.py | 2 +- 5 files changed, 16 insertions(+), 19 deletions(-) delete mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst index 33ce4a3d797c..9e18484ab1d4 100644 --- a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst @@ -9,8 +9,9 @@ Deprecated ^^^^^^^^^^ * Deprecated ``FRANKA_PANDA_CFG``, ``FRANKA_PANDA_HIGH_PD_CFG``, and - ``FRANKA_PANDA_MENAGERIE_CFG`` for removal in Isaac Lab 4.0. The legacy Panda USD and actuator - groups remain available through the first two names. **Breaking:** the nested Menagerie USD moved - from ``franka_panda.usda`` to ``franka_panda_nestedInstance.usda``; code that reads or overrides - its path must use the new filename. Migrate to the corresponding ``FRANKA_PANDA_FLAT_*`` config, - replace shoulder/forearm actuator overrides with ``panda_arm``, and select the backend's ``Physics`` variant. + ``FRANKA_PANDA_MENAGERIE_CFG`` for removal in Isaac Lab 4.0. Their USD paths and actuator groups + remain available during deprecation. **Breaking:** the published ``franka_panda.usda`` now contains + the flat asset; consumers needing the old nested hierarchy can explicitly select + ``franka_panda_nestedInstance.usda``. Migrate maintained tasks to the corresponding + ``FRANKA_PANDA_FLAT_*`` config, replace shoulder/forearm actuator overrides with ``panda_arm``, + and select the backend's ``Physics`` variant. diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index dabb72a2025d..58c11d833c83 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -11,12 +11,12 @@ * :obj:`FRANKA_PANDA_FLAT_HIGH_PD_CFG`: Flat asset with stiffer PD control * :obj:`FRANKA_PANDA_CFG`: Deprecated alias retaining the legacy asset and actuators * :obj:`FRANKA_PANDA_HIGH_PD_CFG`: Deprecated legacy high-PD configuration -* :obj:`FRANKA_PANDA_MENAGERIE_CFG`: Deprecated nested-instance Menagerie configuration +* :obj:`FRANKA_PANDA_MENAGERIE_CFG`: Deprecated Menagerie actuator configuration * :obj:`FRANKA_ROBOTIQ_GRIPPER_CFG`: Franka robot with Robotiq_2f_85 gripper The old public names remain available during deprecation. Use ``FRANKA_PANDA_FLAT_CFG`` for new code -and select its ``Physics`` variant for the chosen backend. The former Menagerie asset was relocated to -``franka_panda_nestedInstance.usda``; the flat asset now occupies ``franka_panda.usda``. +and select its ``Physics`` variant for the chosen backend. The published ``franka_panda.usda`` is now +the flat asset; the former nested-instance file remains available as an explicit USD-path override. Reference: https://github.com/frankaemika/franka_ros """ @@ -211,11 +211,9 @@ _FRANKA_PANDA_LEGACY_HIGH_PD_CFG.actuators[actuator].damping = 80.0 -_FRANKA_PANDA_NESTED_MENAGERIE_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) -_FRANKA_PANDA_NESTED_MENAGERIE_CFG.spawn.usd_path = ( - f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda_nestedInstance.usda" -) -_FRANKA_PANDA_NESTED_MENAGERIE_CFG.actuators = { +_FRANKA_PANDA_MENAGERIE_COMPAT_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) +_FRANKA_PANDA_MENAGERIE_COMPAT_CFG.spawn.usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda" +_FRANKA_PANDA_MENAGERIE_COMPAT_CFG.actuators = { "panda_arm": ImplicitActuatorCfg( joint_names_expr=["panda_joint[1-7]"], joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, @@ -233,7 +231,7 @@ _DEPRECATED_FRANKA_CFGS = { "FRANKA_PANDA_CFG": (_FRANKA_PANDA_LEGACY_CFG, "FRANKA_PANDA_FLAT_CFG"), "FRANKA_PANDA_HIGH_PD_CFG": (_FRANKA_PANDA_LEGACY_HIGH_PD_CFG, "FRANKA_PANDA_FLAT_HIGH_PD_CFG"), - "FRANKA_PANDA_MENAGERIE_CFG": (_FRANKA_PANDA_NESTED_MENAGERIE_CFG, "FRANKA_PANDA_FLAT_CFG"), + "FRANKA_PANDA_MENAGERIE_CFG": (_FRANKA_PANDA_MENAGERIE_COMPAT_CFG, "FRANKA_PANDA_FLAT_CFG"), } if TYPE_CHECKING: @@ -247,8 +245,6 @@ def __getattr__(name: str) -> ArticulationCfg: raise AttributeError(f"module {__name__!r} has no attribute {name!r}") cfg, replacement = _DEPRECATED_FRANKA_CFGS[name] message = f"{name} is deprecated and will be removed in Isaac Lab 4.0. Use {replacement}." - if name == "FRANKA_PANDA_MENAGERIE_CFG": - message += " The nested asset moved from franka_panda.usda to franka_panda_nestedInstance.usda." warnings.warn(message, DeprecationWarning, stacklevel=2) return cfg diff --git a/source/isaaclab_assets/test/test_valid_configs.py b/source/isaaclab_assets/test/test_valid_configs.py index e520f072f532..7f9a0e4b57d9 100644 --- a/source/isaaclab_assets/test/test_valid_configs.py +++ b/source/isaaclab_assets/test/test_valid_configs.py @@ -35,9 +35,9 @@ def test_franka_legacy_configs_warn_and_keep_their_contract() -> None: assert high_pd_cfg.actuators["panda_shoulder"].stiffness == 400.0 assert high_pd_cfg.actuators["panda_forearm"].stiffness == 400.0 - with pytest.warns(DeprecationWarning, match="franka_panda_nestedInstance.usda"): + with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_MENAGERIE_CFG.*removed in Isaac Lab 4.0"): menagerie_cfg = franka_assets.FRANKA_PANDA_MENAGERIE_CFG - assert menagerie_cfg.spawn.usd_path.endswith("/franka_panda_nestedInstance.usda") + assert menagerie_cfg.spawn.usd_path.endswith("/franka_panda.usda") assert set(menagerie_cfg.actuators) == {"panda_arm", "panda_hand"} diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip b/source/isaaclab_tasks/changelog.d/maximiliank-franka-menagerie-path-test.skip deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index a3c29be66171..dcb0fe7f7728 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -145,7 +145,7 @@ def test_reach_newton_ik_configures_gravity_compensation(): mujoco_props = next(props for props in rigid_props if isinstance(props, MujocoRigidBodyCfg)) assert mujoco_props.gravcomp == pytest.approx(1.0) - assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda_nestedInstance.usda") + assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") # Native SE(3) command convention: one relative 6-DoF pose objective. pose_objectives = [ From b78c6f046d910d344bcce07167cd7bc56c563842 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 15:19:36 +0200 Subject: [PATCH 09/24] Preserve mixed body matches and correct Franka migration defaults --- .../maximiliank-direct-body-prim-resolution.rst | 3 ++- source/isaaclab/isaaclab/sim/utils/queries.py | 17 +++++++---------- source/isaaclab/test/sim/test_cloner.py | 12 ++++++++++++ .../maximiliank-franka-flat-config.minor.rst | 8 +++++--- .../isaaclab_assets/robots/franka.py | 4 ++-- .../isaaclab_assets/test/test_valid_configs.py | 6 +++--- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst index 4ead32834c86..b5f3478e73a5 100644 --- a/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst +++ b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst @@ -1,4 +1,5 @@ Fixed ^^^^^ -* Fixed direct rigid-body path queries so nested rigid-body descendants are not selected when the requested body matches. +* Fixed direct rigid-body path queries so nested rigid-body descendants are not selected when the requested body matches, + while preserving descendant matches below other requested non-rigid prims. diff --git a/source/isaaclab/isaaclab/sim/utils/queries.py b/source/isaaclab/isaaclab/sim/utils/queries.py index dc5c973ba033..1c569dd6c130 100644 --- a/source/isaaclab/isaaclab/sim/utils/queries.py +++ b/source/isaaclab/isaaclab/sim/utils/queries.py @@ -404,7 +404,7 @@ def resolve_matching_prims_from_source( raise_if_no_matches: Whether to raise if no prim matches ``path_expr``. Defaults to True. traverse_instance_prims: Whether to traverse instance prims when applying ``predicate``. prefer_direct_matches: Prefer matching prims named by ``path_expr`` over their matching descendants. - Descendants remain a fallback when no direct prim satisfies ``predicate``. + For each matched prim, descendants remain a fallback if that prim does not satisfy ``predicate``. Returns: A list of ``(source_prim, destination_expr)`` pairs. Empty only when @@ -471,25 +471,22 @@ def resolve_matching_prims_from_source( path = prim.GetPath().pathString if path == instance_root or path.startswith(instance_root + "/"): results.append((prim, instance_expr + path[len(instance_root) :])) - direct_source_paths = {source.GetPath().pathString for source, _ in results} if prefer_direct_matches else set() if predicate is not None: # Whole-path regexes can select both a prim and its ancestors; their descendant sets overlap. unique_matches = {} for source, dest in results: source_path = source.GetPath().pathString - children = get_all_matching_child_prims( - source_path, predicate, traverse_instance_prims=traverse_instance_prims - ) + if prefer_direct_matches and predicate(source): + children = [source] + else: + children = get_all_matching_child_prims( + source_path, predicate, traverse_instance_prims=traverse_instance_prims + ) for child in children: child_path = child.GetPath().pathString unique_matches.setdefault(child_path, (child, dest + child_path[len(source_path) :])) results = list(unique_matches.values()) - if prefer_direct_matches: - direct_matches = [pair for pair in results if pair[0].GetPath().pathString in direct_source_paths] - if direct_matches: - results = direct_matches - if expected_num_matches is not None and len(results) != expected_num_matches: raise RuntimeError(f"Expected {expected_num_matches} prims at '{path_expr}', found {len(results)}.") if raise_if_no_matches and not results: diff --git a/source/isaaclab/test/sim/test_cloner.py b/source/isaaclab/test/sim/test_cloner.py index ea45ced6568e..9ff68c54165d 100644 --- a/source/isaaclab/test/sim/test_cloner.py +++ b/source/isaaclab/test/sim/test_cloner.py @@ -294,6 +294,18 @@ def test_resolve_matching_prims_from_source(sim, with_clone_plan): ) assert [prim.GetPath().pathString for prim, _ in matches] == ["/World/envs/env_0/Robot/foo"] + # A direct match must not hide another matched root's predicate-matching descendants. + matches = queries.resolve_matching_prims_from_source( + r"/World/envs/env_[^/]+/Robot/(foo|other)", + predicate=lambda prim: prim.GetName() in {"foo", "bar"}, + expected_num_matches=2, + prefer_direct_matches=True, + ) + assert [(prim.GetPath().pathString, path) for prim, path in matches] == [ + ("/World/envs/env_0/Robot/foo", "/World/envs/env_[^/]+/Robot/foo"), + ("/World/envs/env_0/Robot/other/bar", "/World/envs/env_[^/]+/Robot/other/bar"), + ] + def test_resolve_direct_match_from_external_prototype(sim): """Prefer the requested body even when its prototype is outside the destination namespace.""" diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst index 9e18484ab1d4..873eb0c06d63 100644 --- a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst @@ -3,14 +3,16 @@ Added * Added ``FRANKA_PANDA_FLAT_CFG`` and ``FRANKA_PANDA_FLAT_HIGH_PD_CFG`` for the shared flat Franka asset. These configurations selected gripper-only colliders and the ``panda_arm`` actuator group; - select the ``Physics`` variant for the target backend. + select the ``Physics`` variant for the target backend. Arm effort limits matched the Panda's + 87 Nm shoulder and 12 Nm forearm limits; checkpoints trained with different limits require requalification. Deprecated ^^^^^^^^^^ * Deprecated ``FRANKA_PANDA_CFG``, ``FRANKA_PANDA_HIGH_PD_CFG``, and - ``FRANKA_PANDA_MENAGERIE_CFG`` for removal in Isaac Lab 4.0. Their USD paths and actuator groups - remain available during deprecation. **Breaking:** the published ``franka_panda.usda`` now contains + ``FRANKA_PANDA_MENAGERIE_CFG`` with visible import warnings for removal in Isaac Lab 4.0. + Their USD paths and actuator groups remain available during deprecation. + **Breaking:** the published ``franka_panda.usda`` now contains the flat asset; consumers needing the old nested hierarchy can explicitly select ``franka_panda_nestedInstance.usda``. Migrate maintained tasks to the corresponding ``FRANKA_PANDA_FLAT_*`` config, replace shoulder/forearm actuator overrides with ``panda_arm``, diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index 58c11d833c83..f5c30772b5c4 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -101,7 +101,7 @@ FRANKA_PANDA_FLAT_CFG.actuators = { "panda_arm": ImplicitActuatorCfg( joint_names_expr=["panda_joint[1-7]"], - joint_effort_limit={"panda_joint[1-4]": 100.0, "panda_joint[5-7]": 12.0}, + joint_effort_limit={"panda_joint[1-4]": 87.0, "panda_joint[5-7]": 12.0}, joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, stiffness=None, damping=None, @@ -245,7 +245,7 @@ def __getattr__(name: str) -> ArticulationCfg: raise AttributeError(f"module {__name__!r} has no attribute {name!r}") cfg, replacement = _DEPRECATED_FRANKA_CFGS[name] message = f"{name} is deprecated and will be removed in Isaac Lab 4.0. Use {replacement}." - warnings.warn(message, DeprecationWarning, stacklevel=2) + warnings.warn(message, FutureWarning, stacklevel=2) return cfg diff --git a/source/isaaclab_assets/test/test_valid_configs.py b/source/isaaclab_assets/test/test_valid_configs.py index 7f9a0e4b57d9..0033be07057d 100644 --- a/source/isaaclab_assets/test/test_valid_configs.py +++ b/source/isaaclab_assets/test/test_valid_configs.py @@ -24,18 +24,18 @@ def test_franka_legacy_configs_warn_and_keep_their_contract() -> None: """Deprecated Franka names retain their previous asset and actuator contracts.""" - with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_CFG.*removed in Isaac Lab 4.0"): + with pytest.warns(FutureWarning, match="FRANKA_PANDA_CFG.*removed in Isaac Lab 4.0"): legacy_cfg = franka_assets.FRANKA_PANDA_CFG assert legacy_cfg.spawn.usd_path.endswith("/Legacy/panda_instanceable.usd") assert set(legacy_cfg.actuators) == {"panda_shoulder", "panda_forearm", "panda_hand"} - with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_HIGH_PD_CFG.*removed in Isaac Lab 4.0"): + with pytest.warns(FutureWarning, match="FRANKA_PANDA_HIGH_PD_CFG.*removed in Isaac Lab 4.0"): high_pd_cfg = franka_assets.FRANKA_PANDA_HIGH_PD_CFG assert high_pd_cfg.spawn.usd_path == legacy_cfg.spawn.usd_path assert high_pd_cfg.actuators["panda_shoulder"].stiffness == 400.0 assert high_pd_cfg.actuators["panda_forearm"].stiffness == 400.0 - with pytest.warns(DeprecationWarning, match="FRANKA_PANDA_MENAGERIE_CFG.*removed in Isaac Lab 4.0"): + with pytest.warns(FutureWarning, match="FRANKA_PANDA_MENAGERIE_CFG.*removed in Isaac Lab 4.0"): menagerie_cfg = franka_assets.FRANKA_PANDA_MENAGERIE_CFG assert menagerie_cfg.spawn.usd_path.endswith("/franka_panda.usda") assert set(menagerie_cfg.actuators) == {"panda_arm", "panda_hand"} From 61584683cfd952f6fbf33f2184867cff082edd21 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 15:29:33 +0200 Subject: [PATCH 10/24] Address Franka task migration review feedback --- .../tutorials/05_controllers/run_diff_ik.py | 6 +- scripts/tutorials/05_controllers/run_osc.py | 1 + .../envs/test_diffik_action_processing.py | 56 ------------------- .../envs/test_diffik_jacobian_aliasing.py | 39 ++++++++++++- .../maximiliank-diffik-zero-agent.rst | 4 ++ .../isaaclab_rl/entrypoints/simple_agents.py | 2 +- source/isaaclab_rl/test/test_entrypoints.py | 4 +- .../maximiliank-franka-reach-drawer.major.rst | 3 + .../cabinet/config/franka/ik_abs_env_cfg.py | 4 +- .../cabinet/config/franka/ik_rel_env_cfg.py | 4 +- .../lift/config/franka/ik_abs_env_cfg.py | 2 + .../lift/config/franka/ik_rel_env_cfg.py | 2 + .../lift/config/franka/joint_pos_env_cfg.py | 1 + .../config/franka/bin_stack_ik_rel_env_cfg.py | 2 + .../franka/bin_stack_joint_pos_env_cfg.py | 2 + .../config/franka/stack_ik_abs_env_cfg.py | 2 + .../franka/stack_ik_rel_blueprint_env_cfg.py | 2 + .../config/franka/stack_ik_rel_env_cfg.py | 2 + .../franka/stack_ik_rel_env_cfg_skillgen.py | 2 + ...stack_ik_rel_instance_randomize_env_cfg.py | 2 + .../franka/stack_ik_rel_visuomotor_env_cfg.py | 2 + .../config/franka/stack_joint_pos_env_cfg.py | 14 ++--- ...ck_joint_pos_instance_randomize_env_cfg.py | 1 + .../test/core/test_reach_franka_presets.py | 16 ++++-- 24 files changed, 97 insertions(+), 78 deletions(-) delete mode 100644 source/isaaclab/test/envs/test_diffik_action_processing.py create mode 100644 source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst diff --git a/scripts/tutorials/05_controllers/run_diff_ik.py b/scripts/tutorials/05_controllers/run_diff_ik.py index 2acd470b6fb6..74c9503e5425 100644 --- a/scripts/tutorials/05_controllers/run_diff_ik.py +++ b/scripts/tutorials/05_controllers/run_diff_ik.py @@ -7,7 +7,10 @@ This script demonstrates how to use the differential inverse kinematics controller with the simulator. The differential IK controller can be configured in different modes. It uses the Jacobians computed by -PhysX. This helps perform parallelized computation of the inverse kinematics. +the selected physics backend. This helps perform parallelized computation of the inverse kinematics. + +The Franka high-PD preset uses the same USD and effort limits as the base preset, with stiffer gains +for tracking IK targets. Other tasks can retain their calibrated actuator gains. .. code-block:: bash @@ -83,6 +86,7 @@ class TableTopSceneCfg(InteractiveSceneCfg): # articulation if args_cli.robot == "franka_panda": robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics in {"newton_mjwarp", "newton_vbd"} else "physx" elif args_cli.robot == "ur10": robot = replace(UR10_CFG, prim_path="{ENV_REGEX_NS}/Robot") else: diff --git a/scripts/tutorials/05_controllers/run_osc.py b/scripts/tutorials/05_controllers/run_osc.py index 03b8e886c75e..a9a02e66eb0d 100644 --- a/scripts/tutorials/05_controllers/run_osc.py +++ b/scripts/tutorials/05_controllers/run_osc.py @@ -98,6 +98,7 @@ class SceneCfg(InteractiveSceneCfg): ) robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics in {"newton_mjwarp", "newton_vbd"} else "physx" robot.actuators["panda_arm"].stiffness = 0.0 robot.actuators["panda_arm"].damping = 0.0 robot.spawn.rigid_props.disable_gravity = True diff --git a/source/isaaclab/test/envs/test_diffik_action_processing.py b/source/isaaclab/test/envs/test_diffik_action_processing.py deleted file mode 100644 index 8a6d9634a9ea..000000000000 --- a/source/isaaclab/test/envs/test_diffik_action_processing.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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 - -"""Unit tests for differential inverse-kinematics action processing.""" - -from types import SimpleNamespace - -import pytest -import torch - -from isaaclab.controllers import DifferentialIKControllerCfg -from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.envs.mdp.actions.task_space_actions import DifferentialInverseKinematicsAction - -pytestmark = pytest.mark.unit - - -def test_process_actions_applies_scale_then_offset(monkeypatch: pytest.MonkeyPatch) -> None: - """DiffIK actions use the configured affine transformation before reaching the controller.""" - num_envs = 2 - controller_cfg = DifferentialIKControllerCfg(command_type="position", use_relative_mode=False, ik_method="dls") - cfg = DifferentialInverseKinematicsActionCfg( - asset_name="robot", - joint_names=[".*"], - body_name="tool", - scale=(0.5, 2.0, -1.0), - offset=(0.1, -0.2, 0.3), - controller=controller_cfg, - ) - asset = SimpleNamespace( - find_joints=lambda _names: ([0, 1, 2], ["joint1", "joint2", "joint3"]), - find_bodies=lambda _name: ([0], ["tool"]), - num_joints=3, - num_base_dofs=0, - is_fixed_base=False, - ) - env = SimpleNamespace(scene={"robot": asset}, num_envs=num_envs, device="cpu") - action = DifferentialInverseKinematicsAction(cfg, env) - ee_pos = torch.zeros(num_envs, 3) - ee_quat = torch.tensor([[0.0, 0.0, 0.0, 1.0]]).repeat(num_envs, 1) - monkeypatch.setattr(action, "_compute_frame_pose", lambda: (ee_pos, ee_quat)) - - raw_actions = torch.tensor([[1.0, -2.0, 0.5], [-1.0, 0.25, -0.5]]) - expected = torch.tensor([[0.6, -4.2, -0.2], [-0.4, 0.3, 0.8]]) - - action.process_actions(raw_actions) - - torch.testing.assert_close(action.raw_actions, raw_actions) - torch.testing.assert_close(action.processed_actions, expected) - torch.testing.assert_close(action._ik_controller.ee_pos_des, expected) - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/source/isaaclab/test/envs/test_diffik_jacobian_aliasing.py b/source/isaaclab/test/envs/test_diffik_jacobian_aliasing.py index f06ef4d368dd..77dac22fd0ea 100644 --- a/source/isaaclab/test/envs/test_diffik_jacobian_aliasing.py +++ b/source/isaaclab/test/envs/test_diffik_jacobian_aliasing.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: BSD-3-Clause -"""Regression tests for task-space body offsets and DiffIK Jacobian aliasing (NVBug 6043099). +"""Tests for task-space action processing, body offsets, and Jacobian aliasing (NVBug 6043099). ``DifferentialInverseKinematicsAction._compute_frame_jacobian`` historically aliased the parent Jacobian and applied the body-offset correction in place. @@ -19,6 +19,8 @@ import pytest import torch +from isaaclab.controllers import DifferentialIKControllerCfg +from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg from isaaclab.envs.mdp.actions.task_space_actions import ( DifferentialInverseKinematicsAction, OperationalSpaceControllerAction, @@ -63,6 +65,41 @@ def _make_stub(num_envs: int, num_joints: int, body_offset_pos, body_offset_rot, return _Stub(num_envs, num_joints, body_offset_pos, body_offset_rot, backing_buffer) +def test_process_actions_applies_scale_then_offset(monkeypatch: pytest.MonkeyPatch) -> None: + """DiffIK actions use the configured affine transformation before reaching the controller.""" + num_envs = 2 + controller_cfg = DifferentialIKControllerCfg(command_type="position", use_relative_mode=False, ik_method="dls") + cfg = DifferentialInverseKinematicsActionCfg( + asset_name="robot", + joint_names=[".*"], + body_name="tool", + scale=(0.5, 2.0, -1.0), + offset=(0.1, -0.2, 0.3), + controller=controller_cfg, + ) + asset = SimpleNamespace( + find_joints=lambda _names: ([0, 1, 2], ["joint1", "joint2", "joint3"]), + find_bodies=lambda _name: ([0], ["tool"]), + num_joints=3, + num_base_dofs=0, + is_fixed_base=False, + ) + env = SimpleNamespace(scene={"robot": asset}, num_envs=num_envs, device="cpu") + action = DifferentialInverseKinematicsAction(cfg, env) + ee_pos = torch.zeros(num_envs, 3) + ee_quat = torch.tensor([[0.0, 0.0, 0.0, 1.0]]).repeat(num_envs, 1) + monkeypatch.setattr(action, "_compute_frame_pose", lambda: (ee_pos, ee_quat)) + + raw_actions = torch.tensor([[1.0, -2.0, 0.5], [-1.0, 0.25, -0.5]]) + expected = torch.tensor([[0.6, -4.2, -0.2], [-0.4, 0.3, 0.8]]) + + action.process_actions(raw_actions) + + torch.testing.assert_close(action.raw_actions, raw_actions) + torch.testing.assert_close(action.processed_actions, expected) + torch.testing.assert_close(action._ik_controller.ee_pos_des, expected) + + def test_compute_frame_jacobian_is_idempotent_within_step(): """Two consecutive calls under the same state must return identical Jacobians. diff --git a/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst b/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst new file mode 100644 index 000000000000..6ff2502931b2 --- /dev/null +++ b/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst @@ -0,0 +1,4 @@ +Fixed +^^^^^ + +* Corrected zero-agent hold actions for absolute differential IK configured with a nonzero action offset. diff --git a/source/isaaclab_rl/isaaclab_rl/entrypoints/simple_agents.py b/source/isaaclab_rl/isaaclab_rl/entrypoints/simple_agents.py index 8134b83d117f..ad84e9223b52 100644 --- a/source/isaaclab_rl/isaaclab_rl/entrypoints/simple_agents.py +++ b/source/isaaclab_rl/isaaclab_rl/entrypoints/simple_agents.py @@ -193,7 +193,7 @@ def pink_policy() -> torch.Tensor: def differential_ik_policy() -> torch.Tensor: ee_pos, ee_quat = term._compute_frame_pose() command = ee_pos if term.cfg.controller.command_type == "position" else torch.cat((ee_pos, ee_quat), dim=-1) - return _unscale_action(command, term._scale) + return _unscale_action(command - term._offset, term._scale) return differential_ik_policy diff --git a/source/isaaclab_rl/test/test_entrypoints.py b/source/isaaclab_rl/test/test_entrypoints.py index 24bc151a8c17..77186bda4068 100644 --- a/source/isaaclab_rl/test/test_entrypoints.py +++ b/source/isaaclab_rl/test/test_entrypoints.py @@ -70,6 +70,7 @@ class DifferentialInverseKinematicsAction: action_dim = 7 cfg = SimpleNamespace(controller=SimpleNamespace(use_relative_mode=False, command_type="pose")) _scale = torch.tensor([2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0]) + _offset = torch.tensor([0.2, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0]) def _compute_frame_pose(self): return torch.tensor([[2.0, 4.0, 6.0]]), torch.tensor([[0.0, 0.0, 0.0, 1.0]]) @@ -147,7 +148,7 @@ class JointAction: ).flatten(start_dim=1) expected = torch.cat( ( - torch.tensor([[1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 1.0]]), + torch.tensor([[0.9, 2.2, 2.7, 0.0, 0.0, 0.0, 1.0]]), torch.tensor([[3.0, 2.0, 1.0, 0.0, 0.0, 1.0, 0.0]]), expected_pink_poses, torch.tensor([[0.2, 0.4]]), @@ -168,6 +169,7 @@ class DifferentialInverseKinematicsAction: action_dim = 7 cfg = SimpleNamespace(controller=SimpleNamespace(use_relative_mode=False, command_type="pose")) _scale = torch.ones(7) + _offset = torch.zeros(7) def _compute_frame_pose(self): return torch.full((1, 3), torch.nan), torch.tensor([[0.0, 0.0, 0.0, 1.0]]) diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst index d3e71b259a74..173559b3a105 100644 --- a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst +++ b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst @@ -4,6 +4,9 @@ Changed * Migrated maintained Franka Reach, Drawer, and related contributed tasks to the shared flat asset with backend-specific physics and gripper-only collisions by default. Select ``arm_collisions`` where arm contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. +* Changed Franka Reach and Reach-OSC to continuous pose tracking: success remained a reported metric, + but no longer ended the episode or awarded the terminal success bonus. Episodes ran until timeout, + matching the qualified tracking checkpoints; reward totals changed accordingly. Fixed ^^^^^ diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py index 8a7da6c667c5..c178a981c4da 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py @@ -23,9 +23,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - physics_variants = self.scene.robot.spawn.variants + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = physics_variants + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py index aae63d444a09..c0807f611133 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py @@ -23,9 +23,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. - physics_variants = self.scene.robot.spawn.variants + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = physics_variants + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py index 3a6521e107f9..dcb73591232a 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py @@ -28,7 +28,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py index ff44c6c2c9a5..6a85be6344f6 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py @@ -23,7 +23,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py index aabd132f7154..3fae72453ee5 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/joint_pos_env_cfg.py @@ -30,6 +30,7 @@ def __post_init__(self): # Set Franka as robot self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants["Physics"] = "physx" # Set actions for the specific robot type (franka) self.actions.arm_action = mdp.JointPositionActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py index 8b68516ff17d..00b49a1717c9 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_ik_rel_env_cfg.py @@ -22,7 +22,9 @@ def __post_init__(self): super().__post_init__() # Set Franka as robot + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py index fdcc0587fa31..44cd1ee423c1 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/bin_stack_joint_pos_env_cfg.py @@ -19,6 +19,7 @@ from isaaclab_tasks.contrib.stack import mdp from isaaclab_tasks.contrib.stack.mdp import franka_stack_events from isaaclab_tasks.contrib.stack.stack_env_cfg import StackEnvCfg +from isaaclab_tasks.utils import preset ## # Pre-defined configs @@ -97,6 +98,7 @@ def __post_init__(self): # Set Franka as robot self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants["Physics"] = preset(default="physx", newton_mjwarp="mujoco") self.scene.robot.spawn.semantic_tags = [("class", "robot")] # Add semantics to table diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py index 18e6efc6db2c..f14849383013 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_abs_env_cfg.py @@ -114,7 +114,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py index 74fd959e1d65..e1f6f6fb7e32 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_blueprint_env_cfg.py @@ -217,7 +217,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants self.scene.robot.spawn.semantic_tags = [("class", "robot")] # Set actions for the specific robot type (franka) diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py index 18cb199c8a5e..ffd594d84997 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py @@ -36,10 +36,12 @@ def __post_init__(self): # Use a stiffer PD controller for better IK tracking. robot_init_state = self.scene.robot.init_state robot_semantic_tags = self.scene.robot.spawn.semantic_tags + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace( FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=robot_init_state ) self.scene.robot.spawn.semantic_tags = robot_semantic_tags + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py index 355e91789ccc..f9a4e0493449 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg_skillgen.py @@ -107,7 +107,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py index e7afec6d6a76..1b48ed1eb32c 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py @@ -25,7 +25,9 @@ def __post_init__(self): # Set Franka as robot # We switch here to a stiffer PD controller for IK tracking to be better. + robot_variants = self.scene.robot.spawn.variants self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants = robot_variants # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py index 163008d2d4de..2768299903fd 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_visuomotor_env_cfg.py @@ -22,6 +22,7 @@ from isaaclab_tasks.contrib.stack import mdp from isaaclab_tasks.contrib.stack.mdp import franka_stack_events from isaaclab_tasks.contrib.stack.stack_env_cfg import StackEnvCfg +from isaaclab_tasks.utils import preset from isaaclab_tasks.utils.presets import set_isaac_rtx_global_settings ## @@ -225,6 +226,7 @@ def __post_init__(self): prim_path="{ENV_REGEX_NS}/Robot", init_state=ArticulationCfg.InitialStateCfg(joint_pos=_FRANKA_STACK_IK_REL_INIT_JOINT_POS), ) + self.scene.robot.spawn.variants["Physics"] = preset(default="physx", newton_mjwarp="mujoco") # Add semantics to table self.scene.table.spawn.semantic_tags = [("class", "table")] diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py index 639eeb00341e..4c5584289f28 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_env_cfg.py @@ -13,6 +13,7 @@ apply_default_semantics, make_ee_frame_cfg, ) +from isaaclab_tasks.utils import preset ## # Pre-defined configs @@ -55,6 +56,7 @@ def __post_init__(self): prim_path="{ENV_REGEX_NS}/Robot", init_state=ArticulationCfg.InitialStateCfg(joint_pos=_FRANKA_STACK_IK_REL_INIT_JOINT_POS), ) + self.scene.robot.spawn.variants["Physics"] = preset(default="physx", newton_mjwarp="mujoco") # Tag the table / ground / robot semantic classes. apply_default_semantics(self.scene) @@ -79,16 +81,8 @@ def __post_init__(self): base_prim_path="{ENV_REGEX_NS}/Robot/(Geometry/)?panda_link0", target_specs=[ ("{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_hand", "end_effector", (0.0, 0.0, 0.1034)), - ( - "{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", - "tool_rightfinger", - (0.0, 0.0, 0.046), - ), - ( - "{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", - "tool_leftfinger", - (0.0, 0.0, 0.046), - ), + ("{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger", "tool_rightfinger", (0.0, 0.0, 0.046)), + ("{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger", "tool_leftfinger", (0.0, 0.0, 0.046)), ], marker_scale=(0.1, 0.1, 0.1), ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py index 07b483953cd9..0f72e9fd3735 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_joint_pos_instance_randomize_env_cfg.py @@ -74,6 +74,7 @@ def __post_init__(self): # Set Franka as robot self.scene.robot = replace(FRANKA_PANDA_FLAT_CFG, prim_path="{ENV_REGEX_NS}/Robot") + self.scene.robot.spawn.variants["Physics"] = "physx" # Set actions for the specific robot type (franka) self.actions.arm_action = mdp.JointPositionActionCfg( diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index 21794de95c49..80ef9cb3f63a 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -54,12 +54,20 @@ def _without_controller_dependent_cfg(cfg): return cfg_dict -@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS) -def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task): - default_cfg = _load_reach_env_cfg(task) +@pytest.mark.parametrize( + ("task", "physics_presets"), + [ + *((task, ()) for task in _RIGID_FRANKA_TASKS), + ("IsaacContrib-Stack-Cube-Franka-IK-Rel-Blueprint", ("newton_mjwarp",)), + ("IsaacContrib-Stack-Cube-Bin-Franka-IK-Rel-Mimic", ("newton_mjwarp",)), + ("IsaacContrib-Stack-Cube-Franka-IK-Rel-Visuomotor", ("newton_mjwarp",)), + ], +) +def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task, physics_presets): + newton_cfg = _load_reach_env_cfg(task, *physics_presets) physx_cfg = _load_reach_env_cfg(task, "isaacsim_physx") - for cfg, physics_variant in ((default_cfg, "mujoco"), (physx_cfg, "physx")): + for cfg, physics_variant in ((newton_cfg, "mujoco"), (physx_cfg, "physx")): assert cfg.scene.robot.spawn.usd_path == FRANKA_PANDA_FLAT_CFG.spawn.usd_path assert cfg.scene.robot.spawn.variants == { "Physics": physics_variant, From a949270305f9113b5f2aa9a922fecf0b92f9de26 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 15:36:17 +0200 Subject: [PATCH 11/24] Select PhysX explicitly in controller tutorials --- scripts/tutorials/05_controllers/run_diff_ik.py | 4 ++-- scripts/tutorials/05_controllers/run_osc.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/tutorials/05_controllers/run_diff_ik.py b/scripts/tutorials/05_controllers/run_diff_ik.py index 74c9503e5425..d12a35991de3 100644 --- a/scripts/tutorials/05_controllers/run_diff_ik.py +++ b/scripts/tutorials/05_controllers/run_diff_ik.py @@ -7,7 +7,7 @@ This script demonstrates how to use the differential inverse kinematics controller with the simulator. The differential IK controller can be configured in different modes. It uses the Jacobians computed by -the selected physics backend. This helps perform parallelized computation of the inverse kinematics. +PhysX. This helps perform parallelized computation of the inverse kinematics. The Franka high-PD preset uses the same USD and effort limits as the base preset, with stiffer gains for tracking IK targets. Other tasks can retain their calibrated actuator gains. @@ -86,7 +86,7 @@ class TableTopSceneCfg(InteractiveSceneCfg): # articulation if args_cli.robot == "franka_panda": robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics in {"newton_mjwarp", "newton_vbd"} else "physx" + robot.spawn.variants["Physics"] = "physx" elif args_cli.robot == "ur10": robot = replace(UR10_CFG, prim_path="{ENV_REGEX_NS}/Robot") else: diff --git a/scripts/tutorials/05_controllers/run_osc.py b/scripts/tutorials/05_controllers/run_osc.py index a9a02e66eb0d..4fcf3e41578c 100644 --- a/scripts/tutorials/05_controllers/run_osc.py +++ b/scripts/tutorials/05_controllers/run_osc.py @@ -98,7 +98,7 @@ class SceneCfg(InteractiveSceneCfg): ) robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics in {"newton_mjwarp", "newton_vbd"} else "physx" + robot.spawn.variants["Physics"] = "physx" robot.actuators["panda_arm"].stiffness = 0.0 robot.actuators["panda_arm"].damping = 0.0 robot.spawn.rigid_props.disable_gravity = True From 691c593ee24abbe60c574538ff72fbd4692d3cda Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 18:34:42 +0200 Subject: [PATCH 12/24] Declare the canonical Franka configuration independently --- .../isaaclab_assets/robots/franka.py | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index f5c30772b5c4..da3674e44f23 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -37,6 +37,20 @@ # Configuration ## +_FRANKA_PANDA_INITIAL_STATE = ArticulationCfg.InitialStateCfg( + joint_pos={ + "panda_joint1": 0.0, + "panda_joint2": -0.569, + "panda_joint3": 0.0, + "panda_joint4": -2.810, + "panda_joint5": 0.0, + "panda_joint6": 3.037, + "panda_joint7": 0.741, + "panda_finger_joint.*": 0.04, + }, +) + + _FRANKA_PANDA_LEGACY_CFG = ArticulationCfg( spawn=sim_utils.UsdFileCfg( usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/Legacy/panda_instanceable.usd", @@ -50,18 +64,7 @@ ], # collision_props=sim_utils.CollisionPropertiesCfg(contact_offset=0.005, rest_offset=0.0), ), - init_state=ArticulationCfg.InitialStateCfg( - joint_pos={ - "panda_joint1": 0.0, - "panda_joint2": -0.569, - "panda_joint3": 0.0, - "panda_joint4": -2.810, - "panda_joint5": 0.0, - "panda_joint6": 3.037, - "panda_joint7": 0.741, - "panda_finger_joint.*": 0.04, - }, - ), + init_state=clone(_FRANKA_PANDA_INITIAL_STATE), actuators={ "panda_shoulder": ImplicitActuatorCfg( joint_names_expr=["panda_joint[1-4]"], @@ -89,39 +92,46 @@ """Configuration of the legacy Franka Emika Panda robot asset.""" -FRANKA_PANDA_FLAT_CFG = clone(_FRANKA_PANDA_LEGACY_CFG) -FRANKA_PANDA_FLAT_CFG.spawn.usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda" -FRANKA_PANDA_FLAT_CFG.spawn.variants = {"Physics": "physx", "Colliders": "gripper_only"} -next( - props for props in FRANKA_PANDA_FLAT_CFG.spawn.articulation_props if isinstance(props, PhysxArticulationCfg) -).enabled_self_collisions = False -next( - props for props in FRANKA_PANDA_FLAT_CFG.spawn.articulation_props if isinstance(props, NewtonArticulationCfg) -).self_collision_enabled = False -FRANKA_PANDA_FLAT_CFG.actuators = { - "panda_arm": ImplicitActuatorCfg( - joint_names_expr=["panda_joint[1-7]"], - joint_effort_limit={"panda_joint[1-4]": 87.0, "panda_joint[5-7]": 12.0}, - joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, - stiffness=None, - damping=None, - viscous_friction=0.0, - ), - "panda_hand": ImplicitActuatorCfg( - joint_names_expr=["panda_finger_joint1"], - joint_effort_limit=200.0, - stiffness=None, - damping=None, - viscous_friction=0.0, - ), - "panda_finger2_passive": ImplicitActuatorCfg( - joint_names_expr=["panda_finger_joint2"], - joint_effort_limit=200.0, - stiffness=0.0, - damping=0.0, - viscous_friction=0.0, +FRANKA_PANDA_FLAT_CFG = ArticulationCfg( + spawn=sim_utils.UsdFileCfg( + usd_path=f"{ISAACLAB_NUCLEUS_DIR}/Robots/FrankaEmika/franka_panda.usda", + variants={"Physics": "physx", "Colliders": "gripper_only"}, + activate_contact_sensors=False, + rigid_props=PhysxRigidBodyCfg(disable_gravity=False, max_depenetration_velocity=5.0), + articulation_props=[ + PhysxArticulationCfg( + enabled_self_collisions=False, solver_position_iteration_count=8, solver_velocity_iteration_count=0 + ), + NewtonArticulationCfg(self_collision_enabled=False), + ], ), -} + init_state=clone(_FRANKA_PANDA_INITIAL_STATE), + actuators={ + "panda_arm": ImplicitActuatorCfg( + joint_names_expr=["panda_joint[1-7]"], + joint_effort_limit={"panda_joint[1-4]": 87.0, "panda_joint[5-7]": 12.0}, + joint_velocity_limit={"panda_joint[1-4]": 20.0, "panda_joint[5-7]": 25.0}, + stiffness=None, + damping=None, + viscous_friction=0.0, + ), + "panda_hand": ImplicitActuatorCfg( + joint_names_expr=["panda_finger_joint1"], + joint_effort_limit=200.0, + stiffness=None, + damping=None, + viscous_friction=0.0, + ), + "panda_finger2_passive": ImplicitActuatorCfg( + joint_names_expr=["panda_finger_joint2"], + joint_effort_limit=200.0, + stiffness=0.0, + damping=0.0, + viscous_friction=0.0, + ), + }, + soft_joint_pos_limit_factor=1.0, +) """Configuration of the Franka Emika Panda robot. The flat asset contains PhysX and MuJoCo physics variants and gripper-only, primitive, and convex-hull From 453e8fbe54e96eef495c75cf9599c45a830b57cc Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Wed, 30 Sep 2026 18:42:23 +0200 Subject: [PATCH 13/24] Simplify inherited Franka IK controller settings --- .../controllers/test_operational_space.py | 4 ++-- .../cabinet/config/franka/ik_abs_env_cfg.py | 16 ++++--------- .../cabinet/config/franka/ik_rel_env_cfg.py | 16 ++++--------- .../lift/config/franka/ik_abs_env_cfg.py | 17 ++++---------- .../lift/config/franka/ik_rel_env_cfg.py | 16 ++++--------- .../config/franka/stack_ik_rel_env_cfg.py | 23 ++++--------------- ...stack_ik_rel_instance_randomize_env_cfg.py | 16 ++++--------- 7 files changed, 32 insertions(+), 76 deletions(-) diff --git a/source/isaaclab/test/controllers/test_operational_space.py b/source/isaaclab/test/controllers/test_operational_space.py index 76ed5a42165f..25fb7acdcdde 100644 --- a/source/isaaclab/test/controllers/test_operational_space.py +++ b/source/isaaclab/test/controllers/test_operational_space.py @@ -50,7 +50,7 @@ subtract_frame_transforms, ) -from isaaclab_assets import FRANKA_PANDA_LEGACY_CFG, G1_29DOF_CFG # isort:skip +from isaaclab_assets import FRANKA_PANDA_CFG, G1_29DOF_CFG # isort:skip pytestmark = pytest.mark.integration @@ -96,7 +96,7 @@ def sim(): cloner.usd_replicate(stage, [env_fmt.format(0)], [env_fmt], env_ids, positions=env_origins) # Keep controller regressions on their original plant; canonical asset parity is tested by each backend. - robot_cfg = replace(FRANKA_PANDA_LEGACY_CFG, prim_path="{ENV_REGEX_NS}/Robot") + robot_cfg = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") # Explicit torque actuators enforce effort limits on the commands sent to the simulator. for actuator_name in ("panda_shoulder", "panda_forearm"): actuator_cfg = robot_cfg.actuators[actuator_name] diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py index c178a981c4da..79101158284c 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_abs_env_cfg.py @@ -5,15 +5,10 @@ from isaaclab.controllers.differential_ik_cfg import DifferentialIKControllerCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from isaaclab_tasks.core.cabinet.config.franka import joint_pos_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip - @configclass class FrankaCabinetEnvCfg(joint_pos_env_cfg.FrankaCabinetEnvCfg): @@ -21,11 +16,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # We switch here to a stiffer PD controller for IK tracking to be better. - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py index c0807f611133..2b458d8f31e2 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/cabinet/config/franka/ik_rel_env_cfg.py @@ -5,15 +5,10 @@ from isaaclab.controllers.differential_ik_cfg import DifferentialIKControllerCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from isaaclab_tasks.core.cabinet.config.franka import joint_pos_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip - @configclass class FrankaCabinetEnvCfg(joint_pos_env_cfg.FrankaCabinetEnvCfg): @@ -21,11 +16,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # We switch here to a stiffer PD controller for IK tracking to be better. - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py index dcb73591232a..d942f1d36ff1 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_abs_env_cfg.py @@ -5,16 +5,10 @@ from isaaclab.controllers.differential_ik_cfg import DifferentialIKControllerCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from isaaclab_tasks.contrib.lift.config.franka import joint_pos_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip - - ## # Rigid object lift environment. ## @@ -26,11 +20,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # We switch here to a stiffer PD controller for IK tracking to be better. - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py index 6a85be6344f6..318fbb780a65 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/lift/config/franka/ik_rel_env_cfg.py @@ -5,15 +5,10 @@ from isaaclab.controllers.differential_ik_cfg import DifferentialIKControllerCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from isaaclab_tasks.contrib.lift.config.franka import joint_pos_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip - @configclass class FrankaCubeLiftEnvCfg(joint_pos_env_cfg.FrankaCubeLiftEnvCfg): @@ -21,11 +16,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # We switch here to a stiffer PD controller for IK tracking to be better. - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py index ffd594d84997..c3927de7f7f0 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_env_cfg.py @@ -12,19 +12,12 @@ ) from isaaclab.managers import SceneEntityCfg from isaaclab.managers import TerminationTermCfg as DoneTerm -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from isaaclab_tasks.contrib.stack.stack_env_cfg import mdp from . import stack_joint_pos_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import ( # isort: skip - FRANKA_PANDA_FLAT_HIGH_PD_CFG, -) - @configclass class FrankaCubeStackEnvCfg(stack_joint_pos_env_cfg.FrankaCubeStackEnvCfg): @@ -32,16 +25,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # Use a stiffer PD controller for better IK tracking. - robot_init_state = self.scene.robot.init_state - robot_semantic_tags = self.scene.robot.spawn.semantic_tags - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace( - FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot", init_state=robot_init_state - ) - self.scene.robot.spawn.semantic_tags = robot_semantic_tags - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py index 1b48ed1eb32c..652273d368b9 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/franka/stack_ik_rel_instance_randomize_env_cfg.py @@ -5,15 +5,10 @@ from isaaclab.controllers.differential_ik_cfg import DifferentialIKControllerCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.utils import configclass, replace +from isaaclab.utils import configclass from . import stack_joint_pos_instance_randomize_env_cfg -## -# Pre-defined configs -## -from isaaclab_assets.robots.franka import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort: skip - @configclass class FrankaCubeStackInstanceRandomizeEnvCfg( @@ -23,11 +18,10 @@ def __post_init__(self): # post init of parent super().__post_init__() - # Set Franka as robot - # We switch here to a stiffer PD controller for IK tracking to be better. - robot_variants = self.scene.robot.spawn.variants - self.scene.robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = robot_variants + # Use stiffer arm gains for IK without replacing the task's robot configuration. + self.scene.robot.spawn.rigid_props.disable_gravity = True + self.scene.robot.actuators["panda_arm"].stiffness = 400.0 + self.scene.robot.actuators["panda_arm"].damping = 80.0 # Set actions for the specific robot type (franka) self.actions.arm_action = DifferentialInverseKinematicsActionCfg( From 2b64e784216ffd288ccafe0294ba37e87bc8351c Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 00:17:11 +0200 Subject: [PATCH 14/24] Migrate Franka changelog fragments to Towncrier --- ...maximiliank-direct-body-prim-resolution.fixed.rst} | 3 --- .../maximiliank-franka-flat-config.added.rst | 4 ++++ ... => maximiliank-franka-flat-config.deprecated.rst} | 11 ----------- .../changelog.d/maximiliank-franka-flat-config.minor | 0 ...imiliank-franka-material-body-selection.fixed.rst} | 3 --- ...miliank-frame-transformer-nested-bodies.fixed.rst} | 3 --- ...miliank-frame-transformer-nested-bodies.fixed.rst} | 3 --- 7 files changed, 4 insertions(+), 23 deletions(-) rename source/isaaclab/changelog.d/{maximiliank-direct-body-prim-resolution.rst => maximiliank-direct-body-prim-resolution.fixed.rst} (93%) create mode 100644 source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.added.rst rename source/isaaclab_assets/changelog.d/{maximiliank-franka-flat-config.minor.rst => maximiliank-franka-flat-config.deprecated.rst} (58%) create mode 100644 source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor rename source/isaaclab_newton/changelog.d/{maximiliank-franka-material-body-selection.rst => maximiliank-franka-material-body-selection.fixed.rst} (90%) rename source/{isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst => isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst} (90%) rename source/{isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst => isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst} (90%) diff --git a/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.fixed.rst similarity index 93% rename from source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst rename to source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.fixed.rst index b5f3478e73a5..57e1244eea39 100644 --- a/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.rst +++ b/source/isaaclab/changelog.d/maximiliank-direct-body-prim-resolution.fixed.rst @@ -1,5 +1,2 @@ -Fixed -^^^^^ - * Fixed direct rigid-body path queries so nested rigid-body descendants are not selected when the requested body matches, while preserving descendant matches below other requested non-rigid prims. diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.added.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.added.rst new file mode 100644 index 000000000000..33cbdd88ed0d --- /dev/null +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.added.rst @@ -0,0 +1,4 @@ +* Added ``FRANKA_PANDA_FLAT_CFG`` and ``FRANKA_PANDA_FLAT_HIGH_PD_CFG`` for the shared flat Franka + asset. These configurations selected gripper-only colliders and the ``panda_arm`` actuator group; + select the ``Physics`` variant for the target backend. Arm effort limits matched the Panda's + 87 Nm shoulder and 12 Nm forearm limits; checkpoints trained with different limits require requalification. diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.deprecated.rst similarity index 58% rename from source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst rename to source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.deprecated.rst index 873eb0c06d63..3062168065c8 100644 --- a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor.rst +++ b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.deprecated.rst @@ -1,14 +1,3 @@ -Added -^^^^^ - -* Added ``FRANKA_PANDA_FLAT_CFG`` and ``FRANKA_PANDA_FLAT_HIGH_PD_CFG`` for the shared flat Franka - asset. These configurations selected gripper-only colliders and the ``panda_arm`` actuator group; - select the ``Physics`` variant for the target backend. Arm effort limits matched the Panda's - 87 Nm shoulder and 12 Nm forearm limits; checkpoints trained with different limits require requalification. - -Deprecated -^^^^^^^^^^ - * Deprecated ``FRANKA_PANDA_CFG``, ``FRANKA_PANDA_HIGH_PD_CFG``, and ``FRANKA_PANDA_MENAGERIE_CFG`` with visible import warnings for removal in Isaac Lab 4.0. Their USD paths and actuator groups remain available during deprecation. diff --git a/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor b/source/isaaclab_assets/changelog.d/maximiliank-franka-flat-config.minor new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst b/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.fixed.rst similarity index 90% rename from source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst rename to source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.fixed.rst index f3763ed81629..ffeafb8d49c8 100644 --- a/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.rst +++ b/source/isaaclab_newton/changelog.d/maximiliank-franka-material-body-selection.fixed.rst @@ -1,4 +1 @@ -Fixed -^^^^^ - * Fixed Newton articulation material randomization for bodies whose shapes are interleaved in the native shape array. diff --git a/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst b/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst similarity index 90% rename from source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst rename to source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst index 02a80fb24471..2b8ebda96109 100644 --- a/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.rst +++ b/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst @@ -1,5 +1,2 @@ -Fixed -^^^^^ - * Fixed frame-transformer path expressions that directly match a rigid body from also selecting nested rigid-body descendants. diff --git a/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst b/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst similarity index 90% rename from source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst rename to source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst index 02a80fb24471..2b8ebda96109 100644 --- a/source/isaaclab_ov/changelog.d/maximiliank-frame-transformer-nested-bodies.rst +++ b/source/isaaclab_physx/changelog.d/maximiliank-frame-transformer-nested-bodies.fixed.rst @@ -1,5 +1,2 @@ -Fixed -^^^^^ - * Fixed frame-transformer path expressions that directly match a rigid body from also selecting nested rigid-body descendants. From 3a7432f3b2ed409e8b741a7e8d8afc39de32ac1f Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 00:18:20 +0200 Subject: [PATCH 15/24] Migrate Franka task changelogs to Towncrier fragments --- ... => maximiliank-diffik-action-offset.added.rst} | 3 --- .../maximiliank-diffik-action-offset.minor | 0 ...rst => maximiliank-diffik-zero-agent.fixed.rst} | 3 --- .../maximiliank-franka-reach-drawer.changed.rst | 6 ++++++ .../maximiliank-franka-reach-drawer.fixed.rst | 1 + .../maximiliank-franka-reach-drawer.major | 0 .../maximiliank-franka-reach-drawer.major.rst | 14 -------------- 7 files changed, 7 insertions(+), 20 deletions(-) rename source/isaaclab/changelog.d/{maximiliank-diffik-action-offset.minor.rst => maximiliank-diffik-action-offset.added.rst} (93%) create mode 100644 source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor rename source/isaaclab_rl/changelog.d/{maximiliank-diffik-zero-agent.rst => maximiliank-diffik-zero-agent.fixed.rst} (89%) create mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst create mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.fixed.rst create mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major delete mode 100644 source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst diff --git a/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst b/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.added.rst similarity index 93% rename from source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst rename to source/isaaclab/changelog.d/maximiliank-diffik-action-offset.added.rst index 2af70b827142..91e4e0e728c9 100644 --- a/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor.rst +++ b/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.added.rst @@ -1,5 +1,2 @@ -Added -^^^^^ - * Added an ``offset`` to ``DifferentialInverseKinematicsActionCfg`` so normalized policies can use an affine task-space action transform. The default is zero and preserves existing configurations. diff --git a/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor b/source/isaaclab/changelog.d/maximiliank-diffik-action-offset.minor new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst b/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.fixed.rst similarity index 89% rename from source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst rename to source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.fixed.rst index 6ff2502931b2..fd41ae7bbab3 100644 --- a/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.rst +++ b/source/isaaclab_rl/changelog.d/maximiliank-diffik-zero-agent.fixed.rst @@ -1,4 +1 @@ -Fixed -^^^^^ - * Corrected zero-agent hold actions for absolute differential IK configured with a nonzero action offset. diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst new file mode 100644 index 000000000000..44a6bf29e2dd --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst @@ -0,0 +1,6 @@ +* **Breaking:** Migrated maintained Franka Reach, Drawer, and related contributed tasks to the shared flat asset + with backend-specific physics and gripper-only collisions by default. Select ``arm_collisions`` where arm + contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. +* **Breaking:** Changed Franka Reach and Reach-OSC to continuous pose tracking: success remained a reported metric, + but no longer ended the episode or awarded the terminal success bonus. Episodes ran until timeout, + matching the qualified tracking checkpoints; reward totals changed accordingly. diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.fixed.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.fixed.rst new file mode 100644 index 000000000000..55e51ecf9d8e --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.fixed.rst @@ -0,0 +1 @@ +* Corrected the Reach action and controller contracts for the shared asset. diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst deleted file mode 100644 index 173559b3a105..000000000000 --- a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.major.rst +++ /dev/null @@ -1,14 +0,0 @@ -Changed -^^^^^^^ - -* Migrated maintained Franka Reach, Drawer, and related contributed tasks to the shared flat asset with - backend-specific physics and gripper-only collisions by default. Select ``arm_collisions`` where arm - contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. -* Changed Franka Reach and Reach-OSC to continuous pose tracking: success remained a reported metric, - but no longer ended the episode or awarded the terminal success bonus. Episodes ran until timeout, - matching the qualified tracking checkpoints; reward totals changed accordingly. - -Fixed -^^^^^ - -* Corrected the Reach action and controller contracts for the shared asset. From 81088357ebad47cafd2c126c303bed85ccda5e3b Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Wed, 30 Sep 2026 23:25:46 -0700 Subject: [PATCH 16/24] Clarify Franka migration names and retain behavioral alias coverage --- .../changelog.d/maximiliank-franka-reach-drawer.changed.rst | 6 +++--- .../isaaclab_tasks/test/core/test_reach_franka_presets.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst index 44a6bf29e2dd..28dd894489ac 100644 --- a/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst +++ b/source/isaaclab_tasks/changelog.d/maximiliank-franka-reach-drawer.changed.rst @@ -1,6 +1,6 @@ -* **Breaking:** Migrated maintained Franka Reach, Drawer, and related contributed tasks to the shared flat asset - with backend-specific physics and gripper-only collisions by default. Select ``arm_collisions`` where arm - contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. +* **Breaking:** Migrated maintained Franka Reach, Drawer, and related contributed tasks to the main + ``FRANKA_PANDA_CFG`` shared flat asset with backend-specific physics and gripper-only collisions by default. + Select ``arm_collisions`` where arm contacts are required. Existing checkpoints should be requalified against the changed robot dynamics. * **Breaking:** Changed Franka Reach and Reach-OSC to continuous pose tracking: success remained a reported metric, but no longer ended the episode or awarded the terminal success bonus. Episodes ran until timeout, matching the qualified tracking checkpoints; reward totals changed accordingly. diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index 149ed7219b89..c4d9324e9632 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -88,8 +88,7 @@ def test_reach_diffik_abs_legacy_task_is_a_deprecated_alias(): spec = registry[_CONTRIB_DIFFIK_ABS_TASK] assert spec.kwargs["deprecated"] == {"alias": "--task Isaac-Reach-Franka physics=isaacsim_physx presets=diffik_abs"} - with pytest.warns(FutureWarning, match="presets=diffik_abs"): - legacy_cfg = load_cfg_from_registry(_CONTRIB_DIFFIK_ABS_TASK, "env_cfg_entry_point") + legacy_cfg = load_cfg_from_registry(_CONTRIB_DIFFIK_ABS_TASK, "env_cfg_entry_point") canonical_cfg = _load_env_cfg("diffik_abs", "isaacsim_physx") legacy_cfg = resolve_presets(legacy_cfg) From e58a1f576bf4b462511e1ab620dadd03ad88292e Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 11:45:19 +0200 Subject: [PATCH 17/24] Separate Franka asset migration and add explicit minimal Reach task --- .../source/_static/css/environment-browser.js | 15 ++-- docs/source/setup/environments.rst | 25 ++++++ .../franka-collision-configs.changed.rst | 3 + .../franka-collision-configs.minor | 0 .../isaaclab_assets/__init__.pyi | 2 + .../isaaclab_assets/robots/__init__.pyi | 2 + .../isaaclab_assets/robots/franka.py | 15 +++- .../franka-minimal-reach.added.rst | 2 + ...aximiliank-franka-reach-drawer.changed.rst | 9 +-- .../config/franka/cabinet_direct_env_cfg.py | 6 +- .../config/franka/joint_pos_env_cfg.py | 6 +- .../core/lift/config/franka/franka_env_cfg.py | 33 ++++---- .../config/franka_soft/franka_soft_env_cfg.py | 40 ++++------ .../isaaclab_tasks/core/lift/mdp/utils.py | 10 ++- .../core/reach/config/franka/__init__.py | 13 ++++ .../config/franka/franka_reach_env_cfg.py | 46 ++++------- .../test/core/test_lift_env_cfg.py | 32 ++++++-- .../test/core/test_reach_franka_presets.py | 77 ++++--------------- 18 files changed, 165 insertions(+), 171 deletions(-) create mode 100644 source/isaaclab_assets/changelog.d/franka-collision-configs.changed.rst create mode 100644 source/isaaclab_assets/changelog.d/franka-collision-configs.minor create mode 100644 source/isaaclab_tasks/changelog.d/franka-minimal-reach.added.rst diff --git a/docs/source/_static/css/environment-browser.js b/docs/source/_static/css/environment-browser.js index 6ef9788869c6..8e47d4b00c68 100644 --- a/docs/source/_static/css/environment-browser.js +++ b/docs/source/_static/css/environment-browser.js @@ -30,11 +30,12 @@ ["Isaac-Lift-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}], ["Isaac-Lift-Soft-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"], ["Isaac-Lift-Soft-Franka-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"], - ["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"], - ["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"], + ["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], + ["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], ["Isaac-Pendulum-MARL-Direct", "rl_games,skrl", "isaacsim_physx,newton_kamino,newton_mjwarp,ovphysx", "", "", "tasks/classic/cart_double_pendulum.jpg", false, {}, {"skrl": "MAPPO"}], - ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], - ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], + ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], + ["Isaac-Reach-Franka-Minimal", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], + ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], ["Isaac-Reach-UR10", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/ur10_reach.jpg", true], ["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}], ["Isaac-Reorient-Cube-Allegro-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/allegro_cube.jpg", true], @@ -91,12 +92,12 @@ ["IsaacContrib-Lift-Cube-Franka-IK-Abs", "", "", "", "", "tasks/manipulation/franka_lift.jpg"], ["IsaacContrib-Lift-Cube-Franka-IK-Rel", "", "", "", "", "tasks/manipulation/franka_lift.jpg"], ["IsaacContrib-Lift-Cube-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_lift.jpg"], - ["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "arm_collisions", "tasks/manipulation/multitask_manipulation.jpg"], + ["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "", "tasks/manipulation/multitask_manipulation.jpg"], ["IsaacContrib-Navigation-3DObstacles-ARL-Robot-1", "rl_games,rsl_rl,skrl", "", "", "", "tasks/drone_arl/arl_robot_1_navigation.jpg"], ["IsaacContrib-Navigation-Flat-AnymalC", "rsl_rl,skrl", "", "", "", "tasks/navigation/anymal_c_nav.jpg"], ["IsaacContrib-NutPour-GR1T2-Pink-IK-Abs", "", "", "", ""], - ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"], - ["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"], + ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""], + ["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""], ["IsaacContrib-Open-Drawer-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_open_drawer.jpg"], ["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "isaacsim_rtx,newton_renderer,ovrtx", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"], ["IsaacContrib-PickPlace-G1-InspireFTP-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place.jpg"], diff --git a/docs/source/setup/environments.rst b/docs/source/setup/environments.rst index c19f7f280062..5d2df87808ca 100644 --- a/docs/source/setup/environments.rst +++ b/docs/source/setup/environments.rst @@ -102,6 +102,31 @@ Task Preview Benchmarks ---------- +Franka collision scope +^^^^^^^^^^^^^^^^^^^^^^ + +The standard Franka core tasks use full arm and gripper collisions. The +``Isaac-Reach-Franka-Minimal`` example uses ``FRANKA_MINIMAL_CFG``: the same USD, authored +inertials, controls, and Reach MDP with only hand and fingertip colliders. Use this configuration +when arm contacts are not required. Removing unused colliders can reduce simulation work; +measure the gain for your backend and environment count, and requalify policies when changing scope. + +Compare the two tasks with the same physics backend, environment count, seed and explicit checkpoint. +The minimal task does not have a separate published checkpoint. For example, pass the public Reach +checkpoint explicitly: + +.. code-block:: bash + + uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka-Minimal \ + --checkpoint https://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/6.1/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Reach-Franka_newtonmjwarp_none_rsl_rl.pt \ + --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp + +Repeat with ``--task Isaac-Reach-Franka`` for the full-collision comparison. Keep backend selectors +independent of collision scope; neither task exposes an ``arm_collisions`` preset. + +Measured environment benchmarks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. raw:: html
dict[int, trimesh.Trimesh]: - """Collect collision meshes under ``root_prim``, grouped in caller-selected frames. + """Collect enabled collision meshes under ``root_prim``, grouped in caller-selected frames. + + Disabled colliders and visual-only geometry are excluded from reset clearance checks. Args: root_prim: Prim whose subtree is searched for collision meshes. @@ -311,7 +313,11 @@ def collect_collision_meshes(root_prim, owner_frame_fn: Callable) -> dict[int, t mesh_types = PRIMITIVE_MESH_TYPES + ["Mesh"] mesh_prims = sim_utils.get_all_matching_child_prims( root_prim.GetPath(), - lambda prim: prim.GetTypeName() in mesh_types and prim.HasAPI(UsdPhysics.CollisionAPI), + lambda prim: ( + prim.GetTypeName() in mesh_types + and prim.HasAPI(UsdPhysics.CollisionAPI) + and UsdPhysics.CollisionAPI(prim).GetCollisionEnabledAttr().Get() + ), ) meshes_by_owner: dict[int, list[trimesh.Trimesh]] = {} diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py index ec9e27e89d53..a86a6e485886 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py @@ -26,6 +26,19 @@ }, ) +gym.register( + id="Isaac-Reach-Franka-Minimal", + entry_point="isaaclab.envs:ManagerBasedRLEnv", + disable_env_checker=True, + kwargs={ + "env_cfg_entry_point": f"{__name__}.franka_reach_env_cfg:FrankaReachMinimalEnvCfg", + "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_ppo_cfg.yaml", + "rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:FrankaReachPPORunnerCfg", + "default_agent": "rsl_rl", + "skrl_cfg_entry_point": f"{agents.__name__}:skrl_ppo_cfg.yaml", + }, +) + gym.register( id="Isaac-Reach-Franka-OSC", entry_point="isaaclab.envs:ManagerBasedRLEnv", diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py index e3b9f53f1e2f..87b4feba3c6f 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py @@ -24,9 +24,6 @@ from isaaclab.devices.keyboard import Se3KeyboardCfg from isaaclab.devices.spacemouse import Se3SpaceMouseCfg from isaaclab.envs.mdp.actions.actions_cfg import DifferentialInverseKinematicsActionCfg -from isaaclab.managers import RewardTermCfg as RewTerm -from isaaclab.managers import SceneEntityCfg -from isaaclab.managers import TerminationTermCfg as DoneTerm from isaaclab.utils import configclass, replace from isaaclab_tasks.utils import PresetCfg, preset @@ -34,9 +31,9 @@ ## # Pre-defined configs ## -from isaaclab_assets import FRANKA_PANDA_CFG # isort: skip +from isaaclab_assets import FRANKA_MINIMAL_CFG, FRANKA_PANDA_CFG # isort: skip -from ...reach_env_cfg import ReachEnvCfg, RewardsCfg, TerminationsCfg +from ...reach_env_cfg import ReachEnvCfg ## # Environment configuration @@ -90,32 +87,10 @@ class FrankaArmActionCfg(PresetCfg): default: mdp.JointPositionActionCfg = joint_pos -@configclass -class FrankaReachRewardsCfg(RewardsCfg): - """Keep continuous pose-tracking rewards specific to Franka Reach.""" - - end_effector_position_tracking_fine_grained = RewTerm( - func=mdp.position_command_error_tanh, - weight=0.1, - params={"asset_cfg": SceneEntityCfg("robot", body_names="panda_hand"), "std": 0.1, "command_name": "ee_pose"}, - ) - success: RewTerm | None = None - - -@configclass -class FrankaReachTerminationsCfg(TerminationsCfg): - """Track Franka Reach success without ending the episode early.""" - - success: DoneTerm | None = None - - @configclass class FrankaReachEnvCfg(ReachEnvCfg): """Franka Reach configuration with selectable arm and physics presets.""" - rewards: FrankaReachRewardsCfg = FrankaReachRewardsCfg() - terminations: FrankaReachTerminationsCfg = FrankaReachTerminationsCfg() - def validate_config(self) -> None: """Validate the selected controller and physics backend.""" if isinstance(self.actions.arm_action, NewtonInverseKinematicsActionCfg) and not isinstance( @@ -126,12 +101,10 @@ def validate_config(self) -> None: def __post_init__(self): super().__post_init__() - # Reach has no robot-scene contact objective, so use the fast gripper collider preset. self.scene.robot = replace(FRANKA_PANDA_CFG, prim_path="{ENV_REGEX_NS}/Robot") - self.scene.robot.spawn.variants = { - "Physics": preset(default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx"), - "Colliders": preset(default="gripper_only", arm_collisions="primitives"), - } + self.scene.robot.spawn.variants["Physics"] = preset( + default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx" + ) # IK targets need backend-native gravity control to hold steady between commands. self.scene.robot.spawn.rigid_props = [ PhysxRigidBodyCfg( @@ -168,3 +141,12 @@ def __post_init__(self): # end-effector is along z-direction self.commands.ee_pose.body_name = "panda_hand" self.commands.ee_pose.ranges.pitch = (math.pi, math.pi) + + +@configclass +class FrankaReachMinimalEnvCfg(FrankaReachEnvCfg): + """Franka Reach with gripper-only collisions for collision-scope performance comparisons.""" + + def __post_init__(self): + super().__post_init__() + self.scene.robot.spawn.variants["Colliders"] = FRANKA_MINIMAL_CFG.spawn.variants["Colliders"] diff --git a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py index 59f4bc4e40f8..31ea08aac6cc 100644 --- a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py +++ b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py @@ -11,11 +11,11 @@ import torch import warp as wp -from pxr import Usd +from pxr import Usd, UsdGeom, UsdPhysics from isaaclab.assets import Asset from isaaclab.managers import CommandTerm, ObservationTermCfg, SceneEntityCfg -from isaaclab.sim import select_usd_variants +from isaaclab.sim import select_usd_variants, use_stage from isaaclab.utils.warp import ProxyArray from isaaclab_tasks.core.lift import mdp @@ -27,6 +27,7 @@ DeformableUniformPoseCommand, ObjectUniformPoseCommand, ) +from isaaclab_tasks.core.lift.mdp.utils import collect_collision_meshes from isaaclab_tasks.utils.hydra import resolve_presets @@ -63,11 +64,11 @@ def test_franka_soft_robot_physics_variant_matches_backend( """The Franka USD physics payload must match the selected simulation backend.""" cfg = resolve_presets(FrankaSoftEnvCfg(), selected=selected_presets) - assert cfg.scene.robot.spawn.variants == {"Physics": expected_physics} + assert cfg.scene.robot.spawn.variants == {"Physics": expected_physics, "Colliders": "primitives"} def test_franka_rigid_task_selects_collision_meshes_for_reset_clearance() -> None: - """Reset validation keeps the original arm meshes when the asset defaults to capsules.""" + """Rigid Lift inherits the canonical asset's full primitive colliders.""" cfg = FrankaLiftEnvCfg() stage = Usd.Stage.CreateInMemory() robot = stage.DefinePrim("/Robot", "Xform") @@ -82,10 +83,27 @@ def test_franka_rigid_task_selects_collision_meshes_for_reset_clearance() -> Non stage.DefinePrim(prim_path, prim_type) colliders.SetVariantSelection("primitives") - select_usd_variants("/Robot", cfg.scene.robot.spawn.variants or {}, stage=stage) + select_usd_variants("/Robot", {"Colliders": cfg.scene.robot.spawn.variants["Colliders"]}, stage=stage) - assert stage.GetPrimAtPath("/Robot/link1_c/link1_c").IsValid() - assert not stage.GetPrimAtPath("/Robot/link1_capsule").IsValid() + assert not stage.GetPrimAtPath("/Robot/link1_c/link1_c").IsValid() + assert stage.GetPrimAtPath("/Robot/link1_capsule").IsValid() + + +def test_reset_clearance_ignores_disabled_collision_geometry() -> None: + """Disabled colliders and visual-only geometry must not reject reset candidates.""" + stage = Usd.Stage.CreateInMemory() + root = stage.DefinePrim("/Object", "Xform") + for name, enabled in (("default_enabled", None), ("explicit_enabled", True), ("disabled", False)): + prim = UsdGeom.Cube.Define(stage, f"/Object/{name}").GetPrim() + collision = UsdPhysics.CollisionAPI.Apply(prim) + if enabled is not None: + collision.CreateCollisionEnabledAttr(enabled) + UsdGeom.Cube.Define(stage, "/Object/visual_only") + + with use_stage(stage): + meshes = collect_collision_meshes(root, lambda prim: (prim.GetName(), root)) + + assert set(meshes) == {"default_enabled", "explicit_enabled"} def _make_vision_camera(data_type: str, images: torch.Tensor) -> tuple[mdp.vision_camera, SimpleNamespace]: diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index c4d9324e9632..693f84a129bb 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -from types import SimpleNamespace - import pytest import torch from gymnasium.envs.registration import registry @@ -14,7 +12,7 @@ import isaaclab.envs.mdp as mdp from isaaclab.actuators import IdealPDActuatorCfg -from isaaclab.utils import replace, to_dict, validate +from isaaclab.utils import to_dict, validate import isaaclab_tasks # noqa: F401 from isaaclab_tasks.utils.hydra import PresetCfg, resolve_presets @@ -22,9 +20,10 @@ from isaaclab_tasks.utils.preset_cli import enumerate_task_presets from isaaclab_tasks.utils.preset_target import PresetTarget -from isaaclab_assets import FRANKA_PANDA_CFG +from isaaclab_assets import FRANKA_MINIMAL_CFG, FRANKA_PANDA_CFG _TASK = "Isaac-Reach-Franka" +_MINIMAL_TASK = "Isaac-Reach-Franka-Minimal" _OSC_TASK = "Isaac-Reach-Franka-OSC" _CONTRIB_DIFFIK_ABS_TASK = "IsaacContrib-Reach-Franka-IK-Abs" _RIGID_FRANKA_TASKS = ( @@ -71,17 +70,21 @@ def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task, physi assert cfg.scene.robot.spawn.usd_path == FRANKA_PANDA_CFG.spawn.usd_path assert cfg.scene.robot.spawn.variants == { "Physics": physics_variant, - "Colliders": "gripper_only", + "Colliders": "primitives", } -@pytest.mark.parametrize("task", _RIGID_FRANKA_TASKS) -def test_rigid_franka_arm_collisions_are_an_independent_domain_preset(task): - newton_cfg = _load_reach_env_cfg(task, "arm_collisions") - physx_cfg = _load_reach_env_cfg(task, "arm_collisions", "isaacsim_physx") +@pytest.mark.parametrize("physics", ("newton_mjwarp", "isaacsim_physx", "ovphysx")) +def test_minimal_reach_changes_only_collision_scope(physics): + full = to_dict(_load_reach_env_cfg(_TASK, physics)) + minimal = to_dict(_load_reach_env_cfg(_MINIMAL_TASK, physics)) - assert newton_cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "primitives"} - assert physx_cfg.scene.robot.spawn.variants == {"Physics": "physx", "Colliders": "primitives"} + assert FRANKA_MINIMAL_CFG.spawn.usd_path == FRANKA_PANDA_CFG.spawn.usd_path + assert full["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "primitives" + assert minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "gripper_only" + minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] = "primitives" + assert minimal == full + assert "arm_collisions" not in enumerate_task_presets(_TASK)[PresetTarget.DOMAIN] def test_reach_diffik_abs_legacy_task_is_a_deprecated_alias(): @@ -176,7 +179,7 @@ def test_reach_diffik_physx_configures_teleop_physics(): assert not cfg.scene.robot.spawn.make_uninstanceable assert cfg.scene.robot.spawn.collision_props is None assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") - assert cfg.scene.robot.spawn.variants == {"Physics": "physx", "Colliders": "gripper_only"} + assert cfg.scene.robot.spawn.variants == {"Physics": "physx", "Colliders": "primitives"} def test_reach_diffik_abs_normalizes_position_actions_to_command_workspace(): @@ -202,7 +205,7 @@ def test_reach_newton_ik_configures_gravity_compensation(): mujoco_props = next(props for props in rigid_props if isinstance(props, MujocoRigidBodyCfg)) assert mujoco_props.gravcomp == pytest.approx(1.0) assert cfg.scene.robot.spawn.usd_path.endswith("/FrankaEmika/franka_panda.usda") - assert cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "gripper_only"} + assert cfg.scene.robot.spawn.variants == {"Physics": "mujoco", "Colliders": "primitives"} # Native SE(3) command convention: one relative 6-DoF pose objective. pose_objectives = [ @@ -220,52 +223,6 @@ def test_reach_default_preset_does_not_configure_se3_teleop_devices(): assert cfg.teleop_devices.devices == {} -def test_reach_tracks_success_without_terminating(): - cfg = _load_env_cfg() - - assert cfg.commands.ee_pose.position_success_threshold == pytest.approx(0.05) - assert cfg.commands.ee_pose.orientation_success_threshold == pytest.approx(0.2) - assert cfg.terminations.success is None - assert cfg.terminations.time_out.func is mdp.time_out - assert cfg.rewards.success is None - assert cfg.rewards.end_effector_position_tracking_fine_grained.func is mdp.position_command_error_tanh - assert cfg.rewards.end_effector_position_tracking_fine_grained.weight == pytest.approx(0.1) - assert cfg.rewards.end_effector_position_tracking_fine_grained.params["std"] == pytest.approx(0.1) - - angles = torch.tensor([0.19, 0.19, 0.21]) - body_quaternions = torch.zeros(3, 1, 4) - body_quaternions[:, 0, 2] = torch.sin(angles / 2) - body_quaternions[:, 0, 3] = torch.cos(angles / 2) - command_values = torch.zeros(3, 7) - command_values[:, 6] = 1.0 - robot_data = SimpleNamespace( - root_pos_w=SimpleNamespace(torch=torch.zeros(3, 3)), - root_quat_w=SimpleNamespace(torch=torch.tensor([[0.0, 0.0, 0.0, 1.0]]).repeat(3, 1)), - body_pos_w=SimpleNamespace(torch=torch.tensor([[[0.04, 0.0, 0.0]], [[0.06, 0.0, 0.0]], [[0.04, 0.0, 0.0]]])), - body_quat_w=SimpleNamespace(torch=body_quaternions), - ) - command = object.__new__(mdp.UniformPoseCommand) - command.robot = SimpleNamespace(data=robot_data) - command.body_idx = 0 - command.pose_command_b = command_values - command.pose_command_w = torch.zeros_like(command_values) - command.cfg = cfg.commands.ee_pose - command._env = SimpleNamespace(num_envs=3, device=torch.device("cpu")) - command._track_success = True - command._succeeded = torch.zeros(3, dtype=torch.bool) - - succeeded = command.compute_success() - - assert torch.equal(succeeded, torch.tensor([True, False, False])) - assert torch.equal(command._succeeded, succeeded) - - command.cfg = replace(command.cfg, orientation_success_threshold=None) - command._succeeded.zero_() - position_only_succeeded = command.compute_success() - - assert torch.equal(position_only_succeeded, torch.tensor([True, False, True])) - - def test_reach_osc_effort_actuator_keeps_canonical_solver_properties(): """Replacing the arm actuator with a zero-gain effort model must preserve its solver properties.""" cfg = _load_reach_env_cfg(_OSC_TASK) @@ -297,7 +254,7 @@ def test_reach_osc_resolves_controller_preset_values_to_defaults(): assert physx_props.disable_gravity is True assert mujoco_props.gravcomp == pytest.approx(1.0) assert cfg.teleop_devices.devices == {} - assert domain_presets == {"arm_collisions", "diffik_abs"} + assert domain_presets == {"diffik_abs"} def test_reach_osc_diffik_abs_is_a_deprecated_no_op_alias(): From 25ad1ecfc5c9c6e5736d1793f042da01cafdca65 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 12:44:20 +0200 Subject: [PATCH 18/24] Document the full-collision Franka configuration migration --- .../changelog.d/franka-collision-configs.added.rst | 2 ++ .../changelog.d/franka-collision-configs.changed.rst | 6 +++--- ...llision-configs.minor => franka-collision-configs.major} | 0 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 source/isaaclab_assets/changelog.d/franka-collision-configs.added.rst rename source/isaaclab_assets/changelog.d/{franka-collision-configs.minor => franka-collision-configs.major} (100%) diff --git a/source/isaaclab_assets/changelog.d/franka-collision-configs.added.rst b/source/isaaclab_assets/changelog.d/franka-collision-configs.added.rst new file mode 100644 index 000000000000..96bf616c60a6 --- /dev/null +++ b/source/isaaclab_assets/changelog.d/franka-collision-configs.added.rst @@ -0,0 +1,2 @@ +* Added ``FRANKA_MINIMAL_CFG`` using the same USD and actuator settings as ``FRANKA_PANDA_CFG`` with only + hand and fingertip colliders for applications that do not need arm contacts. diff --git a/source/isaaclab_assets/changelog.d/franka-collision-configs.changed.rst b/source/isaaclab_assets/changelog.d/franka-collision-configs.changed.rst index 9ee527923392..8b01bedc5921 100644 --- a/source/isaaclab_assets/changelog.d/franka-collision-configs.changed.rst +++ b/source/isaaclab_assets/changelog.d/franka-collision-configs.changed.rst @@ -1,3 +1,3 @@ -* Enabled full primitive arm and gripper collisions in ``FRANKA_PANDA_CFG`` and its high-PD derivative. - Added ``FRANKA_MINIMAL_CFG`` using the same USD and actuator settings with only hand and fingertip - colliders for applications that do not need arm contacts. Requalify policies when changing collision scope. +* **Breaking:** Enabled full primitive arm and gripper collisions in ``FRANKA_PANDA_CFG`` and its high-PD + derivative. Use ``FRANKA_MINIMAL_CFG`` or select ``Colliders=gripper_only`` to retain the previous reduced + collision scope. Requalify policies against the chosen robot configuration. diff --git a/source/isaaclab_assets/changelog.d/franka-collision-configs.minor b/source/isaaclab_assets/changelog.d/franka-collision-configs.major similarity index 100% rename from source/isaaclab_assets/changelog.d/franka-collision-configs.minor rename to source/isaaclab_assets/changelog.d/franka-collision-configs.major From 90960d45114edab0759f28740839662aff306d6e Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 19:40:10 +0200 Subject: [PATCH 19/24] Fix Franka migration CI regressions --- .../changelog.d/franka-minimal-frontend.skip | 0 .../test/envs/test_frontend_cfg_conversion.py | 1 + .../changelog.d/franka-curobo-world.fixed.rst | 1 + .../isaaclab_mimic/motion_planners/curobo/curobo_planner.py | 1 + source/isaaclab_tasks/test/rendering_test_utils.py | 6 +++++- 5 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip create mode 100644 source/isaaclab_mimic/changelog.d/franka-curobo-world.fixed.rst diff --git a/source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip b/source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py b/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py index 7496d4c7824f..33e52d7d480c 100644 --- a/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py +++ b/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py @@ -52,6 +52,7 @@ "Isaac-Cartpole", "Isaac-Humanoid", "Isaac-Reach-Franka", + "Isaac-Reach-Franka-Minimal", "Isaac-Reach-UR10", "Isaac-Velocity-Flat-AnymalD", "Isaac-Velocity-Flat-Cassie", diff --git a/source/isaaclab_mimic/changelog.d/franka-curobo-world.fixed.rst b/source/isaaclab_mimic/changelog.d/franka-curobo-world.fixed.rst new file mode 100644 index 000000000000..af413df18d43 --- /dev/null +++ b/source/isaaclab_mimic/changelog.d/franka-curobo-world.fixed.rst @@ -0,0 +1 @@ +* Excluded the robot subtree from cuRobo world obstacles even when custom world ignore substrings were configured. diff --git a/source/isaaclab_mimic/isaaclab_mimic/motion_planners/curobo/curobo_planner.py b/source/isaaclab_mimic/isaaclab_mimic/motion_planners/curobo/curobo_planner.py index 8f750469ced9..bbc888d33b6b 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/motion_planners/curobo/curobo_planner.py +++ b/source/isaaclab_mimic/isaaclab_mimic/motion_planners/curobo/curobo_planner.py @@ -358,6 +358,7 @@ def _initialize_static_world(self) -> None: self._static_world_config = self.usd_helper.get_obstacles_from_stage( only_paths=[env_prim_path], + ignore_paths=[robot_prim_path], reference_prim_path=robot_prim_path, ignore_substring=ignore_list, ) diff --git a/source/isaaclab_tasks/test/rendering_test_utils.py b/source/isaaclab_tasks/test/rendering_test_utils.py index 85474622395a..dbd83c27f1b3 100644 --- a/source/isaaclab_tasks/test/rendering_test_utils.py +++ b/source/isaaclab_tasks/test/rendering_test_utils.py @@ -2474,6 +2474,9 @@ def rendering_test_franka_cable( if env_cfg.curriculum is not None: env_cfg.curriculum.gravity = None + # Settling the USD pose must not trigger randomized RL resets during golden capture. + env_cfg.terminations.joint_vel_out_of_limit = None + _maybe_enable_physx_determinism_for_motion(env_cfg, physics_backend, _motion_data_type(data_types)) test_name = "franka_cable" @@ -2496,7 +2499,8 @@ def rendering_test_franka_cable( return # Let the cable settle under gravity so golden frames are not first-frame spawn poses. - env.step(zero_actions) + _, _, terminated, truncated, _ = env.step(zero_actions) + assert not torch.any(terminated | truncated), "Cable golden capture unexpectedly reset the scene." validate_camera_outputs( test_name, From 817b5bf105f4a8bc99fe4c5f1073d83d8b8cea07 Mon Sep 17 00:00:00 2001 From: Maximilian Krause Date: Thu, 1 Oct 2026 22:52:33 +0200 Subject: [PATCH 20/24] Move Franka collision guidance out of the environment browser --- .../api/lab_assets/isaaclab_assets.robots.rst | 22 ++++++++++++++++ docs/source/setup/environments.rst | 25 ------------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/docs/source/api/lab_assets/isaaclab_assets.robots.rst b/docs/source/api/lab_assets/isaaclab_assets.robots.rst index 91e2e96ae653..a621b7777013 100644 --- a/docs/source/api/lab_assets/isaaclab_assets.robots.rst +++ b/docs/source/api/lab_assets/isaaclab_assets.robots.rst @@ -2,3 +2,25 @@ ======================= .. automodule:: isaaclab_assets.robots + +Franka collision scope +---------------------- + +The standard Franka core tasks use full arm and gripper collisions. The +``Isaac-Reach-Franka-Minimal`` example uses ``FRANKA_MINIMAL_CFG``: the same USD, authored +inertials, controls, and Reach MDP with only hand and fingertip colliders. Use this configuration +when arm contacts are not required. Removing unused colliders can reduce simulation work; +measure the gain for your backend and environment count, and requalify policies when changing scope. + +Compare the two tasks with the same physics backend, environment count, seed and explicit checkpoint. +The minimal task does not have a separate published checkpoint. For example, pass the public Reach +checkpoint explicitly: + +.. code-block:: bash + + uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka-Minimal \ + --checkpoint https://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/6.1/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Reach-Franka_newtonmjwarp_none_rsl_rl.pt \ + --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp + +Repeat with ``--task Isaac-Reach-Franka`` for the full-collision comparison. Keep backend selectors +independent of collision scope; neither task exposes an ``arm_collisions`` preset. diff --git a/docs/source/setup/environments.rst b/docs/source/setup/environments.rst index 5d2df87808ca..c19f7f280062 100644 --- a/docs/source/setup/environments.rst +++ b/docs/source/setup/environments.rst @@ -102,31 +102,6 @@ Task Preview Benchmarks ---------- -Franka collision scope -^^^^^^^^^^^^^^^^^^^^^^ - -The standard Franka core tasks use full arm and gripper collisions. The -``Isaac-Reach-Franka-Minimal`` example uses ``FRANKA_MINIMAL_CFG``: the same USD, authored -inertials, controls, and Reach MDP with only hand and fingertip colliders. Use this configuration -when arm contacts are not required. Removing unused colliders can reduce simulation work; -measure the gain for your backend and environment count, and requalify policies when changing scope. - -Compare the two tasks with the same physics backend, environment count, seed and explicit checkpoint. -The minimal task does not have a separate published checkpoint. For example, pass the public Reach -checkpoint explicitly: - -.. code-block:: bash - - uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka-Minimal \ - --checkpoint https://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/6.1/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Reach-Franka_newtonmjwarp_none_rsl_rl.pt \ - --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp - -Repeat with ``--task Isaac-Reach-Franka`` for the full-collision comparison. Keep backend selectors -independent of collision scope; neither task exposes an ``arm_collisions`` preset. - -Measured environment benchmarks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. raw:: html
Date: Thu, 1 Oct 2026 13:56:41 -0700 Subject: [PATCH 21/24] Replace minimal Franka task with Reach and Lift presets --- .../source/_static/css/environment-browser.js | 7 +++--- .../changelog.d/franka-minimal-frontend.skip | 0 .../test/envs/test_frontend_cfg_conversion.py | 1 - .../franka-minimal-preset.added.rst | 2 ++ .../franka-minimal-reach.added.rst | 2 -- .../core/lift/config/franka/franka_env_cfg.py | 6 ++++- .../core/reach/config/franka/__init__.py | 13 ----------- .../config/franka/franka_reach_env_cfg.py | 13 ++++------- .../test/core/test_lift_env_cfg.py | 2 +- .../test/core/test_reach_franka_presets.py | 23 +++++++++++++------ 10 files changed, 31 insertions(+), 38 deletions(-) delete mode 100644 source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip create mode 100644 source/isaaclab_tasks/changelog.d/franka-minimal-preset.added.rst delete mode 100644 source/isaaclab_tasks/changelog.d/franka-minimal-reach.added.rst diff --git a/docs/source/_static/css/environment-browser.js b/docs/source/_static/css/environment-browser.js index 8e47d4b00c68..472ac168f50a 100644 --- a/docs/source/_static/css/environment-browser.js +++ b/docs/source/_static/css/environment-browser.js @@ -25,7 +25,7 @@ ["Isaac-Lift-Cable-Franka-Camera", "rsl_rl", "newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "tasks/manipulation/franka_lift_cable.jpg", false, {"*": ["joint"]}], ["Isaac-Lift-Cloth-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "tasks/manipulation/franka_lift_cloth.jpg", false, {"*": ["joint"]}], ["Isaac-Lift-Cloth-Franka-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "tasks/manipulation/franka_lift_cloth.jpg", false, {"*": ["joint"]}], - ["Isaac-Lift-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "", false, {"*": ["shapes"]}], + ["Isaac-Lift-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,minimal,shapes", "", false, {"*": ["shapes"]}], ["Isaac-Lift-KukaAllegro", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["shapes"]}], ["Isaac-Lift-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}], ["Isaac-Lift-Soft-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"], @@ -33,9 +33,8 @@ ["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], ["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"], ["Isaac-Pendulum-MARL-Direct", "rl_games,skrl", "isaacsim_physx,newton_kamino,newton_mjwarp,ovphysx", "", "", "tasks/classic/cart_double_pendulum.jpg", false, {}, {"skrl": "MAPPO"}], - ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], - ["Isaac-Reach-Franka-Minimal", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], - ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], + ["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,minimal,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}], + ["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs,minimal", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}], ["Isaac-Reach-UR10", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/ur10_reach.jpg", true], ["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}], ["Isaac-Reorient-Cube-Allegro-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/allegro_cube.jpg", true], diff --git a/source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip b/source/isaaclab_experimental/changelog.d/franka-minimal-frontend.skip deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py b/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py index 33e52d7d480c..7496d4c7824f 100644 --- a/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py +++ b/source/isaaclab_experimental/test/envs/test_frontend_cfg_conversion.py @@ -52,7 +52,6 @@ "Isaac-Cartpole", "Isaac-Humanoid", "Isaac-Reach-Franka", - "Isaac-Reach-Franka-Minimal", "Isaac-Reach-UR10", "Isaac-Velocity-Flat-AnymalD", "Isaac-Velocity-Flat-Cassie", diff --git a/source/isaaclab_tasks/changelog.d/franka-minimal-preset.added.rst b/source/isaaclab_tasks/changelog.d/franka-minimal-preset.added.rst new file mode 100644 index 000000000000..3cfa59d5b0df --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/franka-minimal-preset.added.rst @@ -0,0 +1,2 @@ +* Added ``presets=minimal`` to Franka Reach and rigid Lift, selecting the ``FRANKA_MINIMAL_CFG`` + gripper-only colliders while preserving task controls and independent physics backend selection. diff --git a/source/isaaclab_tasks/changelog.d/franka-minimal-reach.added.rst b/source/isaaclab_tasks/changelog.d/franka-minimal-reach.added.rst deleted file mode 100644 index aa7d72c9d693..000000000000 --- a/source/isaaclab_tasks/changelog.d/franka-minimal-reach.added.rst +++ /dev/null @@ -1,2 +0,0 @@ -* Added ``Isaac-Reach-Franka-Minimal`` as a collision-scope performance example. It shared Reach's MDP and - controls, selecting ``FRANKA_MINIMAL_CFG`` gripper-only colliders instead of full arm collisions. diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/lift/config/franka/franka_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/lift/config/franka/franka_env_cfg.py index bf03bf37473b..17d06d825d8a 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/lift/config/franka/franka_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/lift/config/franka/franka_env_cfg.py @@ -16,7 +16,7 @@ from isaaclab_tasks.utils import preset -from isaaclab_assets.robots import FRANKA_PANDA_CFG +from isaaclab_assets.robots import FRANKA_MINIMAL_CFG, FRANKA_PANDA_CFG from ... import lift_env_cfg as lift from ... import mdp @@ -97,6 +97,10 @@ def __post_init__(self): self.robot.spawn.variants["Physics"] = preset( default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx" ) + self.robot.spawn.variants["Colliders"] = preset( + default=FRANKA_PANDA_CFG.spawn.variants["Colliders"], + minimal=FRANKA_MINIMAL_CFG.spawn.variants["Colliders"], + ) self.robot.spawn.activate_contact_sensors = True # the base is rotated by 180 degrees about z so the workspace lies at positive x self.robot.init_state.rot = (0.0, 0.0, 1.0, 0.0) diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py index a86a6e485886..ec9e27e89d53 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/__init__.py @@ -26,19 +26,6 @@ }, ) -gym.register( - id="Isaac-Reach-Franka-Minimal", - entry_point="isaaclab.envs:ManagerBasedRLEnv", - disable_env_checker=True, - kwargs={ - "env_cfg_entry_point": f"{__name__}.franka_reach_env_cfg:FrankaReachMinimalEnvCfg", - "rl_games_cfg_entry_point": f"{agents.__name__}:rl_games_ppo_cfg.yaml", - "rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:FrankaReachPPORunnerCfg", - "default_agent": "rsl_rl", - "skrl_cfg_entry_point": f"{agents.__name__}:skrl_ppo_cfg.yaml", - }, -) - gym.register( id="Isaac-Reach-Franka-OSC", entry_point="isaaclab.envs:ManagerBasedRLEnv", diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py index 87b4feba3c6f..8d61cef9baaa 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/reach/config/franka/franka_reach_env_cfg.py @@ -105,6 +105,10 @@ def __post_init__(self): self.scene.robot.spawn.variants["Physics"] = preset( default="mujoco", isaacsim_physx="physx", physx="physx", ovphysx="physx" ) + self.scene.robot.spawn.variants["Colliders"] = preset( + default=FRANKA_PANDA_CFG.spawn.variants["Colliders"], + minimal=FRANKA_MINIMAL_CFG.spawn.variants["Colliders"], + ) # IK targets need backend-native gravity control to hold steady between commands. self.scene.robot.spawn.rigid_props = [ PhysxRigidBodyCfg( @@ -141,12 +145,3 @@ def __post_init__(self): # end-effector is along z-direction self.commands.ee_pose.body_name = "panda_hand" self.commands.ee_pose.ranges.pitch = (math.pi, math.pi) - - -@configclass -class FrankaReachMinimalEnvCfg(FrankaReachEnvCfg): - """Franka Reach with gripper-only collisions for collision-scope performance comparisons.""" - - def __post_init__(self): - super().__post_init__() - self.scene.robot.spawn.variants["Colliders"] = FRANKA_MINIMAL_CFG.spawn.variants["Colliders"] diff --git a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py index 31ea08aac6cc..40d249fa7f88 100644 --- a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py +++ b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py @@ -69,7 +69,7 @@ def test_franka_soft_robot_physics_variant_matches_backend( def test_franka_rigid_task_selects_collision_meshes_for_reset_clearance() -> None: """Rigid Lift inherits the canonical asset's full primitive colliders.""" - cfg = FrankaLiftEnvCfg() + cfg = resolve_presets(FrankaLiftEnvCfg()) stage = Usd.Stage.CreateInMemory() robot = stage.DefinePrim("/Robot", "Xform") colliders = robot.GetVariantSets().AddVariantSet("Colliders") diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index 693f84a129bb..c0f90602f9a0 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -23,7 +23,6 @@ from isaaclab_assets import FRANKA_MINIMAL_CFG, FRANKA_PANDA_CFG _TASK = "Isaac-Reach-Franka" -_MINIMAL_TASK = "Isaac-Reach-Franka-Minimal" _OSC_TASK = "Isaac-Reach-Franka-OSC" _CONTRIB_DIFFIK_ABS_TASK = "IsaacContrib-Reach-Franka-IK-Abs" _RIGID_FRANKA_TASKS = ( @@ -74,17 +73,27 @@ def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task, physi } -@pytest.mark.parametrize("physics", ("newton_mjwarp", "isaacsim_physx", "ovphysx")) -def test_minimal_reach_changes_only_collision_scope(physics): - full = to_dict(_load_reach_env_cfg(_TASK, physics)) - minimal = to_dict(_load_reach_env_cfg(_MINIMAL_TASK, physics)) +@pytest.mark.parametrize( + ("task", "presets"), + [ + (_TASK, ("newton_mjwarp",)), + (_TASK, ("isaacsim_physx", "diffik")), + (_TASK, ("ovphysx", "diffik_abs")), + (_OSC_TASK, ("newton_mjwarp",)), + ("Isaac-Lift-Franka", ("isaacsim_physx",)), + ], +) +def test_minimal_preset_changes_only_collision_scope(task, presets): + full = to_dict(_load_reach_env_cfg(task, *presets)) + minimal = to_dict(_load_reach_env_cfg(task, *presets, "minimal")) assert FRANKA_MINIMAL_CFG.spawn.usd_path == FRANKA_PANDA_CFG.spawn.usd_path assert full["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "primitives" assert minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "gripper_only" minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] = "primitives" assert minimal == full - assert "arm_collisions" not in enumerate_task_presets(_TASK)[PresetTarget.DOMAIN] + assert "minimal" in enumerate_task_presets(task)[PresetTarget.DOMAIN] + assert "Isaac-Reach-Franka-Minimal" not in registry def test_reach_diffik_abs_legacy_task_is_a_deprecated_alias(): @@ -254,7 +263,7 @@ def test_reach_osc_resolves_controller_preset_values_to_defaults(): assert physx_props.disable_gravity is True assert mujoco_props.gravcomp == pytest.approx(1.0) assert cfg.teleop_devices.devices == {} - assert domain_presets == {"diffik_abs"} + assert domain_presets == {"diffik_abs", "minimal"} def test_reach_osc_diffik_abs_is_a_deprecated_no_op_alias(): From 4123063716fbc841b188de480f40773a0f44937f Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Thu, 1 Oct 2026 14:04:01 -0700 Subject: [PATCH 22/24] Update Franka asset guidance to use the minimal preset --- .../api/lab_assets/isaaclab_assets.robots.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/source/api/lab_assets/isaaclab_assets.robots.rst b/docs/source/api/lab_assets/isaaclab_assets.robots.rst index a621b7777013..3ae5ef3e3f93 100644 --- a/docs/source/api/lab_assets/isaaclab_assets.robots.rst +++ b/docs/source/api/lab_assets/isaaclab_assets.robots.rst @@ -7,20 +7,21 @@ Franka collision scope ---------------------- The standard Franka core tasks use full arm and gripper collisions. The -``Isaac-Reach-Franka-Minimal`` example uses ``FRANKA_MINIMAL_CFG``: the same USD, authored -inertials, controls, and Reach MDP with only hand and fingertip colliders. Use this configuration +``presets=minimal`` option in Franka Reach and rigid Lift uses the collision scope from +``FRANKA_MINIMAL_CFG``: the same USD, authored inertials, and task controls with only hand and +fingertip colliders. Use this configuration when arm contacts are not required. Removing unused colliders can reduce simulation work; measure the gain for your backend and environment count, and requalify policies when changing scope. -Compare the two tasks with the same physics backend, environment count, seed and explicit checkpoint. -The minimal task does not have a separate published checkpoint. For example, pass the public Reach +Compare the two collision scopes with the same physics backend, environment count, seed and explicit checkpoint. +The minimal preset does not have a separate published checkpoint. For example, pass the public Reach checkpoint explicitly: .. code-block:: bash - uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka-Minimal \ + uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka \ --checkpoint https://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/6.1/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Reach-Franka_newtonmjwarp_none_rsl_rl.pt \ - --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp + --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp presets=minimal -Repeat with ``--task Isaac-Reach-Franka`` for the full-collision comparison. Keep backend selectors -independent of collision scope; neither task exposes an ``arm_collisions`` preset. +Omit ``presets=minimal`` for the full-collision comparison. Keep backend selectors independent of +collision scope. From d38266bad823cfe8a65af466f47df25c46c0d2b8 Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Thu, 1 Oct 2026 14:11:12 -0700 Subject: [PATCH 23/24] Remove Franka collision scope documentation --- .../api/lab_assets/isaaclab_assets.robots.rst | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/docs/source/api/lab_assets/isaaclab_assets.robots.rst b/docs/source/api/lab_assets/isaaclab_assets.robots.rst index 3ae5ef3e3f93..91e2e96ae653 100644 --- a/docs/source/api/lab_assets/isaaclab_assets.robots.rst +++ b/docs/source/api/lab_assets/isaaclab_assets.robots.rst @@ -2,26 +2,3 @@ ======================= .. automodule:: isaaclab_assets.robots - -Franka collision scope ----------------------- - -The standard Franka core tasks use full arm and gripper collisions. The -``presets=minimal`` option in Franka Reach and rigid Lift uses the collision scope from -``FRANKA_MINIMAL_CFG``: the same USD, authored inertials, and task controls with only hand and -fingertip colliders. Use this configuration -when arm contacts are not required. Removing unused colliders can reduce simulation work; -measure the gain for your backend and environment count, and requalify policies when changing scope. - -Compare the two collision scopes with the same physics backend, environment count, seed and explicit checkpoint. -The minimal preset does not have a separate published checkpoint. For example, pass the public Reach -checkpoint explicitly: - -.. code-block:: bash - - uv run isaaclab play --rl_library rsl_rl --task Isaac-Reach-Franka \ - --checkpoint https://omniverse-content-production.s3-us-west-2.amazonaws.com/Assets/Isaac/6.1/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Reach-Franka_newtonmjwarp_none_rsl_rl.pt \ - --num_envs 8192 --seed 42 --viz none physics=newton_mjwarp presets=minimal - -Omit ``presets=minimal`` for the full-collision comparison. Keep backend selectors independent of -collision scope. From 6e9075a987aa53ee5d7ead16f828b74f30d2e9f8 Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Thu, 1 Oct 2026 14:17:17 -0700 Subject: [PATCH 24/24] Prune redundant Franka migration test coverage --- .../test/core/test_lift_env_cfg.py | 25 +--------- .../test/core/test_preset_kit_decision.py | 10 ++-- .../test/core/test_reach_franka_presets.py | 49 ++----------------- 3 files changed, 8 insertions(+), 76 deletions(-) diff --git a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py index 40d249fa7f88..f63b71f137d7 100644 --- a/source/isaaclab_tasks/test/core/test_lift_env_cfg.py +++ b/source/isaaclab_tasks/test/core/test_lift_env_cfg.py @@ -15,11 +15,10 @@ from isaaclab.assets import Asset from isaaclab.managers import CommandTerm, ObservationTermCfg, SceneEntityCfg -from isaaclab.sim import select_usd_variants, use_stage +from isaaclab.sim import use_stage from isaaclab.utils.warp import ProxyArray from isaaclab_tasks.core.lift import mdp -from isaaclab_tasks.core.lift.config.franka.franka_env_cfg import FrankaLiftEnvCfg from isaaclab_tasks.core.lift.config.franka_soft.franka_soft_env_cfg import FrankaSoftEnvCfg from isaaclab_tasks.core.lift.mdp.commands import pose_commands from isaaclab_tasks.core.lift.mdp.commands.pose_commands import ( @@ -67,28 +66,6 @@ def test_franka_soft_robot_physics_variant_matches_backend( assert cfg.scene.robot.spawn.variants == {"Physics": expected_physics, "Colliders": "primitives"} -def test_franka_rigid_task_selects_collision_meshes_for_reset_clearance() -> None: - """Rigid Lift inherits the canonical asset's full primitive colliders.""" - cfg = resolve_presets(FrankaLiftEnvCfg()) - stage = Usd.Stage.CreateInMemory() - robot = stage.DefinePrim("/Robot", "Xform") - colliders = robot.GetVariantSets().AddVariantSet("Colliders") - for selection, prim_path, prim_type in ( - ("convex_hulls", "/Robot/link1_c/link1_c", "Mesh"), - ("primitives", "/Robot/link1_capsule", "Capsule"), - ): - colliders.AddVariant(selection) - colliders.SetVariantSelection(selection) - with colliders.GetVariantEditContext(): - stage.DefinePrim(prim_path, prim_type) - colliders.SetVariantSelection("primitives") - - select_usd_variants("/Robot", {"Colliders": cfg.scene.robot.spawn.variants["Colliders"]}, stage=stage) - - assert not stage.GetPrimAtPath("/Robot/link1_c/link1_c").IsValid() - assert stage.GetPrimAtPath("/Robot/link1_capsule").IsValid() - - def test_reset_clearance_ignores_disabled_collision_geometry() -> None: """Disabled colliders and visual-only geometry must not reject reset candidates.""" stage = Usd.Stage.CreateInMemory() diff --git a/source/isaaclab_tasks/test/core/test_preset_kit_decision.py b/source/isaaclab_tasks/test/core/test_preset_kit_decision.py index 544a8c888b6b..632798d0c4d7 100644 --- a/source/isaaclab_tasks/test/core/test_preset_kit_decision.py +++ b/source/isaaclab_tasks/test/core/test_preset_kit_decision.py @@ -130,15 +130,11 @@ def test_registered_task_physx_presets_keep_auto_selection_explicit(): @pytest.mark.parametrize( "task_id", ["IsaacContrib-Open-Drawer-Franka-IK-Abs", "IsaacContrib-Open-Drawer-Franka-IK-Rel"] ) -@pytest.mark.parametrize( - ("physics_preset", "expected_asset_physics"), - [("newton_mjwarp", "mujoco"), ("isaacsim_physx", "physx"), ("ovphysx", "physx")], -) -def test_franka_cabinet_ik_asset_variant_matches_backend(task_id, physics_preset, expected_asset_physics): +def test_franka_cabinet_ik_preserves_newton_asset_variant(task_id): """The IK robot override retains the cabinet task's backend-aware asset selection.""" - cfg = resolve_presets(load_cfg_from_registry(task_id, "env_cfg_entry_point"), selected=(physics_preset,)) + cfg = resolve_presets(load_cfg_from_registry(task_id, "env_cfg_entry_point"), selected=("newton_mjwarp",)) - assert cfg.scene.robot.spawn.variants["Physics"] == expected_asset_physics + assert cfg.scene.robot.spawn.variants["Physics"] == "mujoco" def test_registered_manager_based_configs_name_their_env_class(): diff --git a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py index c0f90602f9a0..5de619997240 100644 --- a/source/isaaclab_tasks/test/core/test_reach_franka_presets.py +++ b/source/isaaclab_tasks/test/core/test_reach_franka_presets.py @@ -10,7 +10,6 @@ from isaaclab_newton.sim.schemas import MujocoRigidBodyCfg from isaaclab_physx.sim.schemas import PhysxRigidBodyCfg -import isaaclab.envs.mdp as mdp from isaaclab.actuators import IdealPDActuatorCfg from isaaclab.utils import to_dict, validate @@ -20,17 +19,11 @@ from isaaclab_tasks.utils.preset_cli import enumerate_task_presets from isaaclab_tasks.utils.preset_target import PresetTarget -from isaaclab_assets import FRANKA_MINIMAL_CFG, FRANKA_PANDA_CFG +from isaaclab_assets import FRANKA_PANDA_CFG _TASK = "Isaac-Reach-Franka" _OSC_TASK = "Isaac-Reach-Franka-OSC" _CONTRIB_DIFFIK_ABS_TASK = "IsaacContrib-Reach-Franka-IK-Abs" -_RIGID_FRANKA_TASKS = ( - _TASK, - _OSC_TASK, - "Isaac-Open-Drawer-Franka", - "Isaac-Open-Drawer-Franka-Direct", -) def _load_env_cfg(*presets: str): @@ -52,48 +45,22 @@ def _without_controller_dependent_cfg(cfg): return cfg_dict -@pytest.mark.parametrize( - ("task", "physics_presets"), - [ - *((task, ()) for task in _RIGID_FRANKA_TASKS), - ("IsaacContrib-Stack-Cube-Franka-IK-Rel-Blueprint", ("newton_mjwarp",)), - ("IsaacContrib-Stack-Cube-Bin-Franka-IK-Rel-Mimic", ("newton_mjwarp",)), - ("IsaacContrib-Stack-Cube-Franka-IK-Rel-Visuomotor", ("newton_mjwarp",)), - ], -) -def test_franka_tasks_select_the_canonical_asset_and_backend_payload(task, physics_presets): - newton_cfg = _load_reach_env_cfg(task, *physics_presets) - physx_cfg = _load_reach_env_cfg(task, "isaacsim_physx") - - for cfg, physics_variant in ((newton_cfg, "mujoco"), (physx_cfg, "physx")): - assert cfg.scene.robot.spawn.usd_path == FRANKA_PANDA_CFG.spawn.usd_path - assert cfg.scene.robot.spawn.variants == { - "Physics": physics_variant, - "Colliders": "primitives", - } - - @pytest.mark.parametrize( ("task", "presets"), [ - (_TASK, ("newton_mjwarp",)), (_TASK, ("isaacsim_physx", "diffik")), - (_TASK, ("ovphysx", "diffik_abs")), (_OSC_TASK, ("newton_mjwarp",)), - ("Isaac-Lift-Franka", ("isaacsim_physx",)), + ("Isaac-Lift-Franka", ("ovphysx",)), ], ) def test_minimal_preset_changes_only_collision_scope(task, presets): full = to_dict(_load_reach_env_cfg(task, *presets)) minimal = to_dict(_load_reach_env_cfg(task, *presets, "minimal")) - assert FRANKA_MINIMAL_CFG.spawn.usd_path == FRANKA_PANDA_CFG.spawn.usd_path assert full["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "primitives" assert minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] == "gripper_only" minimal["scene"]["robot"]["spawn"]["variants"]["Colliders"] = "primitives" assert minimal == full - assert "minimal" in enumerate_task_presets(task)[PresetTarget.DOMAIN] - assert "Isaac-Reach-Franka-Minimal" not in registry def test_reach_diffik_abs_legacy_task_is_a_deprecated_alias(): @@ -142,10 +109,6 @@ def test_reach_ur10_physics_presets_change_only_physics(): physx = _load_reach_env_cfg("Isaac-Reach-UR10", "isaacsim_physx") newton = _load_reach_env_cfg("Isaac-Reach-UR10", "newton_mjwarp") - assert physx.rewards.success.func is mdp.is_terminated_term - assert physx.terminations.success.func is mdp.pose_command_success - assert not hasattr(physx.rewards, "end_effector_position_tracking_fine_grained") - physx_cfg = to_dict(physx) newton_cfg = to_dict(newton) physx_cfg["sim"].pop("physics") @@ -232,8 +195,8 @@ def test_reach_default_preset_does_not_configure_se3_teleop_devices(): assert cfg.teleop_devices.devices == {} -def test_reach_osc_effort_actuator_keeps_canonical_solver_properties(): - """Replacing the arm actuator with a zero-gain effort model must preserve its solver properties.""" +def test_reach_osc_effort_actuator_keeps_canonical_solver_limits(): + """Replacing the arm actuator with a zero-gain effort model must preserve its solver limits.""" cfg = _load_reach_env_cfg(_OSC_TASK) arm_actuator = cfg.scene.robot.actuators["panda_arm"] source_actuator = FRANKA_PANDA_CFG.actuators["panda_arm"] @@ -242,10 +205,6 @@ def test_reach_osc_effort_actuator_keeps_canonical_solver_properties(): assert arm_actuator.stiffness == 0.0 and arm_actuator.damping == 0.0 assert arm_actuator.joint_effort_limit == source_actuator.joint_effort_limit assert arm_actuator.joint_velocity_limit == source_actuator.joint_velocity_limit - assert arm_actuator.armature == source_actuator.armature - assert arm_actuator.friction == source_actuator.friction - assert arm_actuator.dynamic_friction == source_actuator.dynamic_friction - assert arm_actuator.viscous_friction == source_actuator.viscous_friction def test_reach_osc_resolves_controller_preset_values_to_defaults():