Skip to content

Commit e3940bc

Browse files
committed
Fixed bug with NullSpacePostureTask. Simplified robot articulation
configuration by moving some config parameters to a common configclass. Removed unused file.
1 parent 995654c commit e3940bc

File tree

16 files changed

+136
-339
lines changed

16 files changed

+136
-339
lines changed

source/isaaclab/docs/CHANGELOG.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Changed
1919
improvements, our unit tests pass position and orientation accuracy test within **(2 mm, 1 degree)**. Previously, the position accuracy tolerances
2020
were set to **(30 mm, 10 degrees)**.
2121
* Including a new config parameter :attr:`fail_on_ik_error` to :class:`~isaaclab.controllers.pink_ik.PinkIKControllerCfg`
22-
to control whether the IK controller should fail if robot joint limits are exceeded. This adds to stability of the controller and avoids
23-
operator experiencing sudden large delays in control.
22+
to control whether the IK controller raise an exception if robot joint limits are exceeded. In the case of an exception, the controller will hold the
23+
last joint position. This adds to stability of the controller and avoids operator experiencing what is perceived as sudden large delays in robot control.
2424

2525

2626
0.45.2 (2025-08-18)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2022-2025, 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+
"""Pink IK controller package for IsaacLab.
7+
8+
This package provides integration between Pink inverse kinematics solver and IsaacLab.
9+
"""
10+
11+
from .null_space_posture_task import NullSpacePostureTask
12+
from .pink_ik import PinkIKController
13+
from .pink_ik_cfg import PinkIKControllerCfg

source/isaaclab/isaaclab/controllers/pink_ik/null_space_posture_task.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -151,31 +151,29 @@ def compute_error(self, configuration: Configuration) -> np.ndarray:
151151
_, root_nv = get_root_joint_dim(configuration.model)
152152

153153
# Compute configuration difference
154-
diff = pin.difference(
154+
return pin.difference(
155155
configuration.model,
156156
self.target_q,
157157
configuration.q,
158158
)[root_nv:]
159159

160-
return diff
161-
162160
def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
163-
r"""Compute the posture task Jacobian (null space projector).
164-
165-
This method computes the sum of the left and right null space projectors,
166-
each defined as :math:`N(q) = I - J^+J`, where :math:`J^+` is the pseudoinverse
167-
of the corresponding end-effector Jacobian. The null space projectors are
168-
masked to only affect the selected controlled joints for each side.
169-
170-
The final Jacobian returned is:
171-
:math:`J(q) = N_{\text{left}}(q) + N_{\text{right}}(q)`
172-
173-
Args:
174-
configuration: Robot configuration :math:`q`.
175-
176-
Returns:
177-
Posture task Jacobian :math:`J(q)`, which is the sum of the left and right
178-
null space projectors, each masked to their respective controlled joints.
161+
r"""Computes the product of left and right null space projectors
162+
:math:`N(q) = I - J^+J`, where :math:`J^+` is the pseudoinverse of the
163+
corresponding end-effector Jacobian. The null space projector ensures
164+
joint velocities in the null space produce zero end-effector velocity
165+
(:math:`J \cdot \dot{q}_{\text{null}} = 0`), allowing posture control
166+
without affecting end-effector motion.
167+
168+
The final Jacobian returned is:
169+
:math:`J(q) = N_{\text{task_1}}(q) * N_{\text{task_2}}(q)`
170+
171+
Args:
172+
configuration: Robot configuration :math:`q`.
173+
174+
Returns:
175+
Posture task Jacobian :math:`J(q)`, which is the sum of the left and right
176+
null space projectors, each masked to their respective controlled joints.
179177
"""
180178
# Initialize joint mapping if needed
181179
if self._joint_name_to_index is None:
@@ -199,19 +197,23 @@ def compute_jacobian(self, configuration: Configuration) -> np.ndarray:
199197
self._jacobian_dim = J_frame_tasks[0].shape[1]
200198

201199
# Initialize null space task matrix
202-
null_space_task = np.zeros((self._jacobian_dim, self._jacobian_dim))
200+
null_space_task = np.eye(self._jacobian_dim)
203201

204-
# Compute null space projectors efficiently
205-
for i, (J_frame_task, selected_indices) in enumerate(zip(J_frame_tasks, self._selected_joint_indices or [])):
206-
# Create mask for selected joints
207-
mask = np.zeros(J_frame_task.shape[1], dtype=bool)
202+
# Create mask for all controlled joints
203+
mask = np.zeros(self._jacobian_dim, dtype=bool)
204+
for selected_indices in self._selected_joint_indices or []:
208205
mask[selected_indices] = True
209206

207+
# Compute null space projectors efficiently
208+
for J_frame_task, selected_indices in zip(J_frame_tasks, self._selected_joint_indices or []):
210209
# Compute pseudoinverse and null space projector
211210
J_pinv = np.linalg.pinv(J_frame_task)
212211
null_space_full = np.eye(J_frame_task.shape[1]) - J_pinv @ J_frame_task
213212

214213
# Only update rows corresponding to selected joints
215-
null_space_task[mask, :] += null_space_full[mask, :]
214+
null_space_task @= null_space_full
215+
216+
# Apply mask to the final result
217+
null_space_task = null_space_task * mask[:, np.newaxis]
216218

217219
return null_space_task

source/isaaclab/isaaclab/controllers/pink_ik/pink_ik_cfg.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,6 @@ class PinkIKControllerCfg:
5959
"""Show warning if IK solver fails to find a solution."""
6060

6161
fail_on_joint_limit_violation: bool = True
62-
"""Fail the IK solver if a joint limit is violated."""
62+
"""If True, the Pink IK solver will fail and raise an error if any joint limit is violated during optimization. PinkIKController
63+
will handle the error by setting the last joint positions. If False, the solver will ignore joint limit violations and return the
64+
closest solution found."""

source/isaaclab/test/controllers/test_pink_ik.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,4 @@ def print_debug_info(errors, test_counter):
360360
for hand in ["left", "right"]:
361361
print(f"Measured {hand} hand position error:", errors[f"{hand}_pos_error"])
362362
print(f"Measured {hand} hand rotation error:", errors[f"{hand}_rot_error"])
363+
print(f"Measured {hand} hand PD error:", errors[f"{hand}_pd_error"])

source/isaaclab_assets/isaaclab_assets/robots/fourier.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
The following configuration parameters are available:
99
1010
* :obj:`GR1T2_CFG`: The GR1T2 humanoid.
11+
* :obj:`GR1T2_PICK_PLACE_CFG`: The GR1T2 humanoid configured for pick-place manipulation tasks.
1112
1213
Reference: https://www.fftai.com/products-gr1
1314
"""
@@ -123,3 +124,54 @@
123124
},
124125
)
125126
"""Configuration for the GR1T2 Humanoid robot."""
127+
128+
129+
GR1T2_PICK_PLACE_CFG = GR1T2_CFG.replace(
130+
actuators={
131+
"trunk": ImplicitActuatorCfg(
132+
joint_names_expr=[
133+
"waist_.*",
134+
],
135+
effort_limit=None,
136+
velocity_limit=None,
137+
stiffness=4400,
138+
damping=40.0,
139+
armature=0.01,
140+
),
141+
"right-arm": ImplicitActuatorCfg(
142+
joint_names_expr=[
143+
"right_shoulder_.*",
144+
"right_elbow_.*",
145+
"right_wrist_.*",
146+
],
147+
stiffness=4400.0,
148+
damping=40.0,
149+
armature=0.01,
150+
),
151+
"left-arm": ImplicitActuatorCfg(
152+
joint_names_expr=[
153+
"left_shoulder_.*",
154+
"left_elbow_.*",
155+
"left_wrist_.*",
156+
],
157+
stiffness=4400.0,
158+
damping=40.0,
159+
armature=0.01,
160+
),
161+
"right-hand": ImplicitActuatorCfg(
162+
joint_names_expr=[
163+
"R_.*",
164+
],
165+
stiffness=None,
166+
damping=None,
167+
),
168+
"left-hand": ImplicitActuatorCfg(
169+
joint_names_expr=[
170+
"L_.*",
171+
],
172+
stiffness=None,
173+
damping=None,
174+
),
175+
},
176+
)
177+
"""Configuration for the GR1T2 Humanoid robot configured for pick-place manipulation tasks."""

source/isaaclab_mimic/isaaclab_mimic/envs/pinocchio_envs/pickplace_gr1t2_mimic_env.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def target_eef_pose_to_action(
3939
target_eef_pose_dict: dict,
4040
gripper_action_dict: dict,
4141
action_noise_dict: dict | None = None,
42-
env_id: int = 0,
42+
env_id: int = 0, # Unused, but required to conform to interface
4343
) -> torch.Tensor:
4444
"""
4545
Takes a target pose and gripper action for the end effector controller and returns an action
@@ -49,8 +49,8 @@ def target_eef_pose_to_action(
4949
Args:
5050
target_eef_pose_dict: Dictionary of 4x4 target eef pose for each end-effector.
5151
gripper_action_dict: Dictionary of gripper actions for each end-effector.
52-
noise: Noise to add to the action. If None, no noise is added.
53-
env_id: Environment index to get the action for.
52+
action_noise_dict: Noise to add to the action. If None, no noise is added.
53+
env_id: Environment index to get the action for. (Unused in this implementation, present for interface compatibility.)
5454
5555
Returns:
5656
An action torch.Tensor that's compatible with env.step().

source/isaaclab_mimic/isaaclab_mimic/envs/pinocchio_envs/pickplace_gr1t2_mimic_env_cfg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __post_init__(self):
1717
super().__post_init__()
1818

1919
# Override the existing values
20-
self.datagen_config.name = "demo_src_gr1t2_demo_task_D0"
20+
self.datagen_config.name = "gr1t2_pick_place_D0"
2121
self.datagen_config.generation_guarantee = True
2222
self.datagen_config.generation_keep_failed = False
2323
self.datagen_config.generation_num_trials = 1000

source/isaaclab_mimic/isaaclab_mimic/envs/pinocchio_envs/pickplace_gr1t2_waist_enabled_mimic_env.py

Lines changed: 0 additions & 129 deletions
This file was deleted.

source/isaaclab_mimic/isaaclab_mimic/envs/pinocchio_envs/pickplace_gr1t2_waist_enabled_mimic_env_cfg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def __post_init__(self):
1919
super().__post_init__()
2020

2121
# Override the existing values
22-
self.datagen_config.name = "demo_src_gr1t2_demo_task_D0"
22+
self.datagen_config.name = "gr1t2_pick_place_waist_enabled_D0"
2323
self.datagen_config.generation_guarantee = True
2424
self.datagen_config.generation_keep_failed = False
2525
self.datagen_config.generation_num_trials = 1000

0 commit comments

Comments
 (0)