Skip to content

Commit 97062f7

Browse files
authored
Adds strict type checking and clear split between cfg and implementation (#4718)
# Description Adds strict type checking and split between cfg and implementaion Fixes # (issue) <!-- As a practice, it is recommended to open an issue to have discussions on the proposed pull request. This makes it easier for the community to keep track of what is being developed or added, and if a given feature is demanded by more than one party. --> ## Type of change <!-- As you go through the list, delete the ones that are not applicable. --> - Bug fix (non-breaking change which fixes an issue) ## Screenshots Please attach before and after screenshots of the change if applicable. <!-- Example: | Before | After | | ------ | ----- | | _gif/png before_ | _gif/png after_ | To upload images to a PR -- simply drag and drop an image while in edit mode and it should upload the image directly. You can then paste that source into the above before/after sections. --> ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there <!-- As you go through the checklist above, you can mark something as done by putting an x character in it For example, - [x] I have done this task - [ ] I have not done this task -->
1 parent 852d2fd commit 97062f7

File tree

84 files changed

+1318
-851
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1318
-851
lines changed

docs/source/features/hydra.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ are modified.
108108

109109
For example, for the configuration of the Cartpole camera depth environment:
110110

111-
.. literalinclude:: ../../../source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py
111+
.. literalinclude:: ../../../source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env_cfg.py
112112
:language: python
113113
:start-at: class CartpoleDepthCameraEnvCfg
114114
:end-at: tiled_camera.width

source/isaaclab/isaaclab/controllers/config/rmp_flow.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,34 @@
55

66
import os
77

8-
from isaacsim.core.utils.extensions import get_extension_path_from_name
9-
10-
from isaaclab.controllers.rmp_flow import RmpFlowControllerCfg
8+
from isaaclab.controllers.rmp_flow_cfg import RmpFlowControllerCfg
119
from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR
1210

1311
# Directory on Nucleus Server for RMP-Flow assets (URDFs, collision models, etc.)
1412
ISAACLAB_NUCLEUS_RMPFLOW_DIR = os.path.join(ISAACLAB_NUCLEUS_DIR, "Controllers", "RmpFlowAssets")
1513

16-
# Note: RMP-Flow config files for supported robots are stored in the motion_generation extension
17-
# We need to move it here for doc building purposes.
18-
try:
19-
_RMP_CONFIG_DIR = os.path.join(
20-
get_extension_path_from_name("isaacsim.robot_motion.motion_generation"),
21-
"motion_policy_configs",
22-
)
23-
except Exception:
24-
_RMP_CONFIG_DIR = ""
14+
# Sentinel prefix for paths inside the isaacsim.robot_motion.motion_generation extension.
15+
# RmpFlowController resolves these at init time (after enabling the extension) so that
16+
# this cfg file stays free of any isaacsim/Kit imports.
17+
_EXT_MOTION_CFG = "rmpflow_ext:motion_policy_configs/"
2518

2619
# Path to current directory
2720
_CUR_DIR = os.path.dirname(os.path.realpath(__file__))
2821

2922
FRANKA_RMPFLOW_CFG = RmpFlowControllerCfg(
30-
config_file=os.path.join(_RMP_CONFIG_DIR, "franka", "rmpflow", "franka_rmpflow_common.yaml"),
23+
config_file=_EXT_MOTION_CFG + "franka/rmpflow/franka_rmpflow_common.yaml",
3124
urdf_file=os.path.join(_CUR_DIR, "data", "lula_franka_gen.urdf"),
32-
collision_file=os.path.join(_RMP_CONFIG_DIR, "franka", "rmpflow", "robot_descriptor.yaml"),
25+
collision_file=_EXT_MOTION_CFG + "franka/rmpflow/robot_descriptor.yaml",
3326
frame_name="panda_end_effector",
3427
evaluations_per_frame=5,
3528
)
3629
"""Configuration of RMPFlow for Franka arm (default from `isaacsim.robot_motion.motion_generation`)."""
3730

3831

3932
UR10_RMPFLOW_CFG = RmpFlowControllerCfg(
40-
config_file=os.path.join(_RMP_CONFIG_DIR, "ur10", "rmpflow", "ur10_rmpflow_config.yaml"),
41-
urdf_file=os.path.join(_RMP_CONFIG_DIR, "ur10", "ur10_robot.urdf"),
42-
collision_file=os.path.join(_RMP_CONFIG_DIR, "ur10", "rmpflow", "ur10_robot_description.yaml"),
33+
config_file=_EXT_MOTION_CFG + "ur10/rmpflow/ur10_rmpflow_config.yaml",
34+
urdf_file=_EXT_MOTION_CFG + "ur10/ur10_robot.urdf",
35+
collision_file=_EXT_MOTION_CFG + "ur10/rmpflow/ur10_robot_description.yaml",
4336
frame_name="ee_link",
4437
evaluations_per_frame=5,
4538
)

source/isaaclab/isaaclab/controllers/rmp_flow.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
#
44
# SPDX-License-Identifier: BSD-3-Clause
55

6-
from dataclasses import MISSING
6+
import os
77

88
import torch
99

1010
from isaacsim.core.prims import SingleArticulation
1111

1212
# enable motion generation extensions
13-
from isaacsim.core.utils.extensions import enable_extension
13+
from isaacsim.core.utils.extensions import enable_extension, get_extension_path_from_name
1414

1515
enable_extension("isaacsim.robot_motion.lula")
1616
enable_extension("isaacsim.robot_motion.motion_generation")
@@ -19,28 +19,27 @@
1919
from isaacsim.robot_motion.motion_generation.lula.motion_policies import RmpFlow, RmpFlowSmoothed
2020

2121
import isaaclab.sim as sim_utils
22-
from isaaclab.utils import configclass
2322
from isaaclab.utils.assets import retrieve_file_path
2423

24+
from .rmp_flow_cfg import RmpFlowControllerCfg # noqa: F401
2525

26-
@configclass
27-
class RmpFlowControllerCfg:
28-
"""Configuration for RMP-Flow controller (provided through LULA library)."""
26+
_RMPFLOW_EXT_PREFIX = "rmpflow_ext:"
27+
_RMPFLOW_EXT_NAME = "isaacsim.robot_motion.motion_generation"
2928

30-
name: str = "rmp_flow"
31-
"""Name of the controller. Supported: "rmp_flow", "rmp_flow_smoothed". Defaults to "rmp_flow"."""
32-
config_file: str = MISSING
33-
"""Path to the configuration file for the controller."""
34-
urdf_file: str = MISSING
35-
"""Path to the URDF model of the robot."""
36-
collision_file: str = MISSING
37-
"""Path to collision model description of the robot."""
38-
frame_name: str = MISSING
39-
"""Name of the robot frame for task space (must be present in the URDF)."""
40-
evaluations_per_frame: float = MISSING
41-
"""Number of substeps during Euler integration inside LULA world model."""
42-
ignore_robot_state_updates: bool = False
43-
"""If true, then state of the world model inside controller is rolled out. Defaults to False."""
29+
30+
def _resolve_rmpflow_path(path: str) -> str:
31+
"""Resolve a sentinel ``rmpflow_ext:`` path to an absolute filesystem path.
32+
33+
Paths stored in :class:`~isaaclab.controllers.rmp_flow_cfg.RmpFlowControllerCfg`
34+
that begin with ``"rmpflow_ext:"`` are relative to the
35+
``isaacsim.robot_motion.motion_generation`` extension directory. This avoids
36+
importing ``isaacsim`` in the cfg file (which is loaded without Kit).
37+
"""
38+
if path.startswith(_RMPFLOW_EXT_PREFIX):
39+
rel = path[len(_RMPFLOW_EXT_PREFIX) :]
40+
ext_dir = get_extension_path_from_name(_RMPFLOW_EXT_NAME)
41+
return os.path.join(ext_dir, rel)
42+
return path
4443

4544

4645
class RmpFlowController:
@@ -98,9 +97,11 @@ def initialize(self, prim_paths_expr: str):
9897
robot.initialize()
9998
# download files if they are not local
10099

101-
local_urdf_file = retrieve_file_path(self.cfg.urdf_file, force_download=True)
102-
local_collision_file = retrieve_file_path(self.cfg.collision_file, force_download=True)
103-
local_config_file = retrieve_file_path(self.cfg.config_file, force_download=True)
100+
local_urdf_file = retrieve_file_path(_resolve_rmpflow_path(self.cfg.urdf_file), force_download=True)
101+
local_collision_file = retrieve_file_path(
102+
_resolve_rmpflow_path(self.cfg.collision_file), force_download=True
103+
)
104+
local_config_file = retrieve_file_path(_resolve_rmpflow_path(self.cfg.config_file), force_download=True)
104105

105106
# add controller
106107
rmpflow = controller_cls(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2+
# All rights reserved.
3+
#
4+
# SPDX-License-Identifier: BSD-3-Clause
5+
6+
"""Configuration for RMP-Flow controller."""
7+
8+
from __future__ import annotations
9+
10+
from dataclasses import MISSING
11+
12+
from isaaclab.utils import configclass
13+
14+
15+
@configclass
16+
class RmpFlowControllerCfg:
17+
"""Configuration for RMP-Flow controller (provided through LULA library)."""
18+
19+
name: str = "rmp_flow"
20+
"""Name of the controller. Supported: "rmp_flow", "rmp_flow_smoothed". Defaults to "rmp_flow"."""
21+
config_file: str = MISSING
22+
"""Path to the configuration file for the controller."""
23+
urdf_file: str = MISSING
24+
"""Path to the URDF model of the robot."""
25+
collision_file: str = MISSING
26+
"""Path to collision model description of the robot."""
27+
frame_name: str = MISSING
28+
"""Name of the robot frame for task space (must be present in the URDF)."""
29+
evaluations_per_frame: float = MISSING
30+
"""Number of substeps during Euler integration inside LULA world model."""
31+
ignore_robot_state_updates: bool = False
32+
"""If true, then state of the world model inside controller is rolled out. Defaults to False."""

source/isaaclab/isaaclab/devices/gamepad/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55

66
"""Gamepad device for SE(2) and SE(3) control."""
77

8-
from .se2_gamepad import Se2Gamepad, Se2GamepadCfg
9-
from .se3_gamepad import Se3Gamepad, Se3GamepadCfg
8+
from .se2_gamepad import Se2Gamepad
9+
from .se2_gamepad_cfg import Se2GamepadCfg
10+
from .se3_gamepad import Se3Gamepad
11+
from .se3_gamepad_cfg import Se3GamepadCfg

source/isaaclab/isaaclab/devices/gamepad/se2_gamepad.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import weakref
1111
from collections.abc import Callable
12-
from dataclasses import dataclass
12+
from typing import TYPE_CHECKING
1313

1414
import numpy as np
1515
import torch
@@ -20,7 +20,10 @@
2020

2121
from isaaclab.app.settings_manager import get_settings_manager
2222

23-
from ..device_base import DeviceBase, DeviceCfg
23+
from ..device_base import DeviceBase
24+
25+
if TYPE_CHECKING:
26+
from .se2_gamepad_cfg import Se2GamepadCfg
2427

2528

2629
class Se2Gamepad(DeviceBase):
@@ -203,14 +206,3 @@ def _resolve_command_buffer(self, raw_command: np.ndarray) -> np.ndarray:
203206
command[command_sign] *= -1
204207

205208
return command
206-
207-
208-
@dataclass
209-
class Se2GamepadCfg(DeviceCfg):
210-
"""Configuration for SE2 gamepad devices."""
211-
212-
v_x_sensitivity: float = 1.0
213-
v_y_sensitivity: float = 1.0
214-
omega_z_sensitivity: float = 1.0
215-
dead_zone: float = 0.01
216-
class_type: type[DeviceBase] = Se2Gamepad
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2+
# All rights reserved.
3+
#
4+
# SPDX-License-Identifier: BSD-3-Clause
5+
6+
"""Configuration for SE(2) gamepad controller."""
7+
8+
from __future__ import annotations
9+
10+
from dataclasses import dataclass
11+
12+
from ..device_base import DeviceCfg
13+
from .se2_gamepad import Se2Gamepad
14+
15+
16+
@dataclass
17+
class Se2GamepadCfg(DeviceCfg):
18+
"""Configuration for SE2 gamepad devices."""
19+
20+
v_x_sensitivity: float = 1.0
21+
v_y_sensitivity: float = 1.0
22+
omega_z_sensitivity: float = 1.0
23+
dead_zone: float = 0.01
24+
class_type: type | str = Se2Gamepad

source/isaaclab/isaaclab/devices/gamepad/se3_gamepad.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import weakref
1111
from collections.abc import Callable
12-
from dataclasses import dataclass
12+
from typing import TYPE_CHECKING
1313

1414
import numpy as np
1515
import torch
@@ -20,7 +20,10 @@
2020

2121
from isaaclab.app.settings_manager import get_settings_manager
2222

23-
from ..device_base import DeviceBase, DeviceCfg
23+
from ..device_base import DeviceBase
24+
25+
if TYPE_CHECKING:
26+
from .se3_gamepad_cfg import Se3GamepadCfg
2427

2528

2629
class Se3Gamepad(DeviceBase):
@@ -257,14 +260,3 @@ def _resolve_command_buffer(self, raw_command: np.ndarray) -> np.ndarray:
257260
delta_command[delta_command_sign] *= -1
258261

259262
return delta_command
260-
261-
262-
@dataclass
263-
class Se3GamepadCfg(DeviceCfg):
264-
"""Configuration for SE3 gamepad devices."""
265-
266-
gripper_term: bool = True
267-
dead_zone: float = 0.01 # For gamepad devices
268-
pos_sensitivity: float = 1.0
269-
rot_sensitivity: float = 1.6
270-
class_type: type[DeviceBase] = Se3Gamepad
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2+
# All rights reserved.
3+
#
4+
# SPDX-License-Identifier: BSD-3-Clause
5+
6+
"""Configuration for SE(3) gamepad controller."""
7+
8+
from __future__ import annotations
9+
10+
from dataclasses import dataclass
11+
12+
from ..device_base import DeviceCfg
13+
from .se3_gamepad import Se3Gamepad
14+
15+
16+
@dataclass
17+
class Se3GamepadCfg(DeviceCfg):
18+
"""Configuration for SE3 gamepad devices."""
19+
20+
gripper_term: bool = True
21+
dead_zone: float = 0.01
22+
pos_sensitivity: float = 1.0
23+
rot_sensitivity: float = 1.6
24+
class_type: type | str = Se3Gamepad

source/isaaclab/isaaclab/devices/keyboard/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55

66
"""Keyboard device for SE(2) and SE(3) control."""
77

8-
from .se2_keyboard import Se2Keyboard, Se2KeyboardCfg
9-
from .se3_keyboard import Se3Keyboard, Se3KeyboardCfg
8+
from .se2_keyboard import Se2Keyboard
9+
from .se2_keyboard_cfg import Se2KeyboardCfg
10+
from .se3_keyboard import Se3Keyboard
11+
from .se3_keyboard_cfg import Se3KeyboardCfg

0 commit comments

Comments
 (0)