From b4c20a0579a5067c87154e5253e309eabc35bb14 Mon Sep 17 00:00:00 2001 From: alltheseas Date: Sat, 21 Feb 2026 00:50:34 -0600 Subject: [PATCH 1/3] fix: correct inverted preserve_order docstring in resolve_matching_names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docstring for `resolve_matching_names` incorrectly described the behavior of the `preserve_order` parameter — the descriptions for True and False were swapped. Fixes #4493 Signed-off-by: alltheseas --- source/isaaclab/isaaclab/utils/string.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/isaaclab/isaaclab/utils/string.py b/source/isaaclab/isaaclab/utils/string.py index dc1cdaf53477..f78c8de31366 100644 --- a/source/isaaclab/isaaclab/utils/string.py +++ b/source/isaaclab/isaaclab/utils/string.py @@ -183,17 +183,18 @@ def resolve_matching_names( When a list of query regular expressions is provided, the function checks each target string against each query regular expression and returns the indices of the matched strings and the matched strings. - If the :attr:`preserve_order` is True, the ordering of the matched indices and names is the same as the order - of the provided list of strings. This means that the ordering is dictated by the order of the target strings - and not the order of the query regular expressions. + If the :attr:`preserve_order` is False (default), the ordering of the matched indices and names follows + the order of the provided list of strings. This means that the ordering is dictated by the order of the + target strings and not the order of the query regular expressions. - If the :attr:`preserve_order` is False, the ordering of the matched indices and names is the same as the order - of the provided list of query regular expressions. + If the :attr:`preserve_order` is True, the ordering of the matched indices and names follows the order + of the query regular expressions. For example, consider the list of strings is ['a', 'b', 'c', 'd', 'e'] and the regular expressions are ['a|c', 'b']. - If :attr:`preserve_order` is False, then the function will return the indices of the matched strings and the - strings as: ([0, 1, 2], ['a', 'b', 'c']). When :attr:`preserve_order` is True, it will return them as: - ([0, 2, 1], ['a', 'c', 'b']). + If :attr:`preserve_order` is False (default), then the function will return the indices of the matched strings and + the strings as: ([0, 1, 2], ['a', 'b', 'c']) - following the order of list_of_strings. When + :attr:`preserve_order` is True, it will return them as: + ([0, 2, 1], ['a', 'c', 'b']) - following the order of the regex keys. Note: The function does not sort the indices. It returns the indices in the order they are found. From 3e0f7023141f754774b40e07ae77574a15fb3e26 Mon Sep 17 00:00:00 2001 From: alltheseas Date: Sat, 21 Feb 2026 01:23:25 -0600 Subject: [PATCH 2/3] fix: correct misleading comments and docs in BinaryJointAction The inline comments in process_actions stated "true: close, false: open" which describes the binary_mask variable but reads as describing the action convention, contradicting actual behavior. Also fix class docstring: "positive" -> "non-negative" for float actions, since zero maps to open (the mask uses < 0, not <= 0). Fixes #4670 Signed-off-by: alltheseas --- .../isaaclab/envs/mdp/actions/binary_joint_actions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/isaaclab/isaaclab/envs/mdp/actions/binary_joint_actions.py b/source/isaaclab/isaaclab/envs/mdp/actions/binary_joint_actions.py index 289045bd37ba..0ad8489b8170 100644 --- a/source/isaaclab/isaaclab/envs/mdp/actions/binary_joint_actions.py +++ b/source/isaaclab/isaaclab/envs/mdp/actions/binary_joint_actions.py @@ -34,7 +34,7 @@ class BinaryJointAction(ActionTerm): Based on above, we follow the following convention for the binary action: - 1. Open action: 1 (bool) or positive values (float). + 1. Open action: 1 (bool) or non-negative values (float). 2. Close action: 0 (bool) or negative values (float). The action term can mostly be used for gripper actions, where the gripper is either open or closed. This @@ -133,10 +133,10 @@ def process_actions(self, actions: torch.Tensor): self._raw_actions[:] = actions # compute the binary mask if actions.dtype == torch.bool: - # true: close, false: open + # action=True (1) -> open, action=False (0) -> close binary_mask = actions == 0 else: - # true: close, false: open + # action >= 0 -> open, action < 0 -> close binary_mask = actions < 0 # compute the command self._processed_actions = torch.where(binary_mask, self._close_command, self._open_command) From c3c33f80a4ddb1d9c54281c3499383f629105a05 Mon Sep 17 00:00:00 2001 From: alltheseas Date: Sat, 21 Feb 2026 01:42:06 -0600 Subject: [PATCH 3/3] fix: correct joint position sampling range in dexterous hand envs The reset sampling logic used `sample_uniform(-1, 1)` with `delta_min + (delta_max - delta_min) * 0.5 * noise`, which produces a range of [1.5*delta_min - 0.5*delta_max, midpoint] instead of the intended [delta_min, delta_max]. This could push joints past their lower limits and never sample near the upper limits. Use `sample_uniform(0, 1)` with standard linear interpolation `delta_min + (delta_max - delta_min) * noise` to correctly sample the full [delta_min, delta_max] range. Applied to all 3 occurrences: - InHandManipulationEnv._reset_idx - ShadowHandOverEnv._reset_idx (right hand) - ShadowHandOverEnv._reset_idx (left hand) Fixes #4404 Signed-off-by: alltheseas --- .../direct/inhand_manipulation/inhand_manipulation_env.py | 4 ++-- .../direct/shadow_hand_over/shadow_hand_over_env.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/inhand_manipulation/inhand_manipulation_env.py b/source/isaaclab_tasks/isaaclab_tasks/direct/inhand_manipulation/inhand_manipulation_env.py index c8d4fbf9e2d0..37584fddca3d 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/inhand_manipulation/inhand_manipulation_env.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/inhand_manipulation/inhand_manipulation_env.py @@ -229,8 +229,8 @@ def _reset_idx(self, env_ids: Sequence[int] | None): delta_max = self.hand_dof_upper_limits[env_ids] - self.hand.data.default_joint_pos[env_ids] delta_min = self.hand_dof_lower_limits[env_ids] - self.hand.data.default_joint_pos[env_ids] - dof_pos_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) - rand_delta = delta_min + (delta_max - delta_min) * 0.5 * dof_pos_noise + dof_pos_noise = sample_uniform(0.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) + rand_delta = delta_min + (delta_max - delta_min) * dof_pos_noise dof_pos = self.hand.data.default_joint_pos[env_ids] + self.cfg.reset_dof_pos_noise * rand_delta dof_vel_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand_over/shadow_hand_over_env.py b/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand_over/shadow_hand_over_env.py index 09bbff6e97c0..54334eb8d5fb 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand_over/shadow_hand_over_env.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand_over/shadow_hand_over_env.py @@ -330,8 +330,8 @@ def _reset_idx(self, env_ids: Sequence[int] | torch.Tensor | None): delta_max = self.hand_dof_upper_limits[env_ids] - self.right_hand.data.default_joint_pos[env_ids] delta_min = self.hand_dof_lower_limits[env_ids] - self.right_hand.data.default_joint_pos[env_ids] - dof_pos_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) - rand_delta = delta_min + (delta_max - delta_min) * 0.5 * dof_pos_noise + dof_pos_noise = sample_uniform(0.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) + rand_delta = delta_min + (delta_max - delta_min) * dof_pos_noise dof_pos = self.right_hand.data.default_joint_pos[env_ids] + self.cfg.reset_dof_pos_noise * rand_delta dof_vel_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) @@ -348,8 +348,8 @@ def _reset_idx(self, env_ids: Sequence[int] | torch.Tensor | None): delta_max = self.hand_dof_upper_limits[env_ids] - self.left_hand.data.default_joint_pos[env_ids] delta_min = self.hand_dof_lower_limits[env_ids] - self.left_hand.data.default_joint_pos[env_ids] - dof_pos_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) - rand_delta = delta_min + (delta_max - delta_min) * 0.5 * dof_pos_noise + dof_pos_noise = sample_uniform(0.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device) + rand_delta = delta_min + (delta_max - delta_min) * dof_pos_noise dof_pos = self.left_hand.data.default_joint_pos[env_ids] + self.cfg.reset_dof_pos_noise * rand_delta dof_vel_noise = sample_uniform(-1.0, 1.0, (len(env_ids), self.num_hand_dofs), device=self.device)