From bab210d3d6be6d65a63dc02bbb5678536cfee1e9 Mon Sep 17 00:00:00 2001 From: fan-ziqi Date: Sat, 7 Dec 2024 11:45:49 +0800 Subject: [PATCH] feat: add clip-cfg to ActionTermCfg && add clip to all mdp/actions --- .../isaac/lab/envs/mdp/actions/actions_cfg.py | 2 -- .../envs/mdp/actions/binary_joint_actions.py | 17 ++++++++++++++++- .../isaac/lab/envs/mdp/actions/joint_actions.py | 3 ++- .../envs/mdp/actions/joint_actions_to_limits.py | 15 +++++++++++++++ .../envs/mdp/actions/non_holonomic_actions.py | 16 ++++++++++++++++ .../lab/envs/mdp/actions/task_space_actions.py | 17 +++++++++++++++++ .../omni/isaac/lab/managers/manager_term_cfg.py | 3 +++ .../locomotion/velocity/velocity_env_cfg.py | 8 +++++++- 8 files changed, 76 insertions(+), 5 deletions(-) diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/actions_cfg.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/actions_cfg.py index 76d9fb7818..6d07ceb855 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/actions_cfg.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/actions_cfg.py @@ -29,8 +29,6 @@ class JointActionCfg(ActionTermCfg): """Scale factor for the action (float or dict of regex expressions). Defaults to 1.0.""" offset: float | dict[str, float] = 0.0 """Offset factor for the action (float or dict of regex expressions). Defaults to 0.0.""" - clip: dict[str, tuple] | None = None - """Clip range for the action (dict of regex expressions). Defaults to None.""" preserve_order: bool = False """Whether to preserve the order of the joint names in the action output. Defaults to False.""" diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/binary_joint_actions.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/binary_joint_actions.py index 5c2ba3fa15..7293900061 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/binary_joint_actions.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/binary_joint_actions.py @@ -40,9 +40,10 @@ class BinaryJointAction(ActionTerm): cfg: actions_cfg.BinaryJointActionCfg """The configuration of the action term.""" - _asset: Articulation """The articulation asset on which the action term is applied.""" + _clip: dict[str, tuple] | None = None + """The clip applied to the input action.""" def __init__(self, cfg: actions_cfg.BinaryJointActionCfg, env: ManagerBasedEnv) -> None: # initialize the action term @@ -83,6 +84,13 @@ def __init__(self, cfg: actions_cfg.BinaryJointActionCfg, env: ManagerBasedEnv) ) self._close_command[index_list] = torch.tensor(value_list, device=self.device) + # parse clip + if cfg.clip is not None: + if isinstance(cfg.clip, dict): + self._clip = cfg.clip + else: + raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.") + """ Properties. """ @@ -115,6 +123,13 @@ def process_actions(self, actions: torch.Tensor): binary_mask = actions < 0 # compute the command self._processed_actions = torch.where(binary_mask, self._close_command, self._open_command) + # clip actions + if self._clip is not None: + # resolve the dictionary config + index_list, _, value_list = string_utils.resolve_matching_names_values(self._clip, self._joint_names) + for index in range(len(index_list)): + min_value, max_value = value_list[index] + self._processed_actions[:, index_list[index]].clip_(min_value, max_value) def reset(self, env_ids: Sequence[int] | None = None) -> None: self._raw_actions[env_ids] = 0.0 diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions.py index 864c05dbf2..b7d867a3f5 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions.py @@ -101,7 +101,7 @@ def __init__(self, cfg: actions_cfg.JointActionCfg, env: ManagerBasedEnv) -> Non if isinstance(cfg.clip, dict): self._clip = cfg.clip else: - raise ValueError(f"Unsupported clip type: {type(cfg.scale)}. Supported types are dict.") + raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.") """ Properties. @@ -134,6 +134,7 @@ def process_actions(self, actions: torch.Tensor): index_list, _, value_list = string_utils.resolve_matching_names_values(self._clip, self._joint_names) for index in range(len(index_list)): min_value, max_value = value_list[index] + print(value_list[index]) self._processed_actions[:, index_list[index]].clip_(min_value, max_value) def reset(self, env_ids: Sequence[int] | None = None) -> None: diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions_to_limits.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions_to_limits.py index 3b31c9502a..2434aa87ac 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions_to_limits.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/joint_actions_to_limits.py @@ -44,6 +44,8 @@ class JointPositionToLimitsAction(ActionTerm): """The articulation asset on which the action term is applied.""" _scale: torch.Tensor | float """The scaling factor applied to the input action.""" + _clip: dict[str, tuple] | None = None + """The clip applied to the input action.""" def __init__(self, cfg: actions_cfg.JointPositionToLimitsActionCfg, env: ManagerBasedEnv): # initialize the action term @@ -76,6 +78,12 @@ def __init__(self, cfg: actions_cfg.JointPositionToLimitsActionCfg, env: Manager self._scale[:, index_list] = torch.tensor(value_list, device=self.device) else: raise ValueError(f"Unsupported scale type: {type(cfg.scale)}. Supported types are float and dict.") + # parse clip + if cfg.clip is not None: + if isinstance(cfg.clip, dict): + self._clip = cfg.clip + else: + raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.") """ Properties. @@ -102,6 +110,13 @@ def process_actions(self, actions: torch.Tensor): self._raw_actions[:] = actions # apply affine transformations self._processed_actions = self._raw_actions * self._scale + # clip actions + if self._clip is not None: + # resolve the dictionary config + index_list, _, value_list = string_utils.resolve_matching_names_values(self._clip, self._joint_names) + for index in range(len(index_list)): + min_value, max_value = value_list[index] + self._processed_actions[:, index_list[index]].clip_(min_value, max_value) # rescale the position targets if configured # this is useful when the input actions are in the range [-1, 1] if self.cfg.rescale_to_limits: diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/non_holonomic_actions.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/non_holonomic_actions.py index fc9ed89d6e..1179d8d414 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/non_holonomic_actions.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/non_holonomic_actions.py @@ -11,6 +11,7 @@ import omni.log +import omni.isaac.lab.utils.string as string_utils from omni.isaac.lab.assets.articulation import Articulation from omni.isaac.lab.managers.action_manager import ActionTerm from omni.isaac.lab.utils.math import euler_xyz_from_quat @@ -59,6 +60,8 @@ class NonHolonomicAction(ActionTerm): """The scaling factor applied to the input action. Shape is (1, 2).""" _offset: torch.Tensor """The offset applied to the input action. Shape is (1, 2).""" + _clip: dict[str, tuple] | None = None + """The clip applied to the input action.""" def __init__(self, cfg: actions_cfg.NonHolonomicActionCfg, env: ManagerBasedEnv): # initialize the action term @@ -104,6 +107,12 @@ def __init__(self, cfg: actions_cfg.NonHolonomicActionCfg, env: ManagerBasedEnv) # save the scale and offset as tensors self._scale = torch.tensor(self.cfg.scale, device=self.device).unsqueeze(0) self._offset = torch.tensor(self.cfg.offset, device=self.device).unsqueeze(0) + # parse clip + if cfg.clip is not None: + if isinstance(cfg.clip, dict): + self._clip = cfg.clip + else: + raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.") """ Properties. @@ -129,6 +138,13 @@ def process_actions(self, actions): # store the raw actions self._raw_actions[:] = actions self._processed_actions = self.raw_actions * self._scale + self._offset + # clip actions + if self._clip is not None: + # resolve the dictionary config + index_list, _, value_list = string_utils.resolve_matching_names_values(self._clip, self._joint_names) + for index in range(len(index_list)): + min_value, max_value = value_list[index] + self._processed_actions[:, index_list[index]].clip_(min_value, max_value) def apply_actions(self): # obtain current heading diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/task_space_actions.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/task_space_actions.py index 96154116c8..e6541c4adf 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/task_space_actions.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/envs/mdp/actions/task_space_actions.py @@ -12,6 +12,7 @@ import omni.log import omni.isaac.lab.utils.math as math_utils +import omni.isaac.lab.utils.string as string_utils from omni.isaac.lab.assets.articulation import Articulation from omni.isaac.lab.controllers.differential_ik import DifferentialIKController from omni.isaac.lab.managers.action_manager import ActionTerm @@ -42,6 +43,8 @@ class DifferentialInverseKinematicsAction(ActionTerm): """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).""" + _clip: dict[str, tuple] | None = None + """The clip applied to the input action.""" def __init__(self, cfg: actions_cfg.DifferentialInverseKinematicsActionCfg, env: ManagerBasedEnv): # initialize the action term @@ -101,6 +104,13 @@ def __init__(self, cfg: actions_cfg.DifferentialInverseKinematicsActionCfg, env: else: self._offset_pos, self._offset_rot = None, None + # parse clip + if cfg.clip is not None: + if isinstance(cfg.clip, dict): + self._clip = cfg.clip + else: + raise ValueError(f"Unsupported clip type: {type(cfg.clip)}. Supported types are dict.") + """ Properties. """ @@ -125,6 +135,13 @@ def process_actions(self, actions: torch.Tensor): # store the raw actions self._raw_actions[:] = actions self._processed_actions[:] = self.raw_actions * self._scale + # clip actions + if self._clip is not None: + # resolve the dictionary config + index_list, _, value_list = string_utils.resolve_matching_names_values(self._clip, self._joint_names) + for index in range(len(index_list)): + min_value, max_value = value_list[index] + self._processed_actions[:, index_list[index]].clip_(min_value, max_value) # obtain quantities from simulation ee_pos_curr, ee_quat_curr = self._compute_frame_pose() # set command into controller diff --git a/source/extensions/omni.isaac.lab/omni/isaac/lab/managers/manager_term_cfg.py b/source/extensions/omni.isaac.lab/omni/isaac/lab/managers/manager_term_cfg.py index 1a510159e2..a395c36e3d 100644 --- a/source/extensions/omni.isaac.lab/omni/isaac/lab/managers/manager_term_cfg.py +++ b/source/extensions/omni.isaac.lab/omni/isaac/lab/managers/manager_term_cfg.py @@ -76,6 +76,9 @@ class for more details. debug_vis: bool = False """Whether to visualize debug information. Defaults to False.""" + clip: dict[str, tuple] | None = None + """Clip range for the action (dict of regex expressions). Defaults to None.""" + ## # Command manager. diff --git a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/locomotion/velocity/velocity_env_cfg.py b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/locomotion/velocity/velocity_env_cfg.py index 200a76753e..d9e653ba0f 100644 --- a/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/locomotion/velocity/velocity_env_cfg.py +++ b/source/extensions/omni.isaac.lab_tasks/omni/isaac/lab_tasks/manager_based/locomotion/velocity/velocity_env_cfg.py @@ -109,7 +109,13 @@ class CommandsCfg: class ActionsCfg: """Action specifications for the MDP.""" - joint_pos = mdp.JointPositionActionCfg(asset_name="robot", joint_names=[".*"], scale=0.5, use_default_offset=True) + joint_pos = mdp.JointPositionActionCfg( + asset_name="robot", + joint_names=[".*"], + scale=0.5, + use_default_offset=True, + clip={".*": (-100.0, 100.0)}, # only for test + ) @configclass