Commit 870c3f13 authored by Ashwin Varghese Kuruttukulam's avatar Ashwin Varghese Kuruttukulam Committed by Kelly Guo

Prevents import of pink when running other workflows (#317)

This change prevents importing pink/dex-retargeting when using other
IsaacLab scripts.

* Change the import structure to only import ``pinocchio`` when
``pink-ik`` or ``dex-retargeting`` is being used.
* This also solves for the problem that ``pink-ik`` and
``dex-retargeting`` are not supported in windows.
* Removed ``isaacsim.robot_motion.lula`` and
``isaacsim.robot_motion.motion_generation`` from the default loaded
Isaac Sim extensions and enable them only for RMPFlow
* Moved pink ik action config to a separate file.
* The pick_place task is now blacklisted from being imported
automatically by isaaclab_tasks and have to be imported
  manually by the script.

- Bug fix (non-breaking change which fixes an issue)
- This change requires a documentation update

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [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

---------
Signed-off-by: 's avatarKelly Guo <kellyguo123@hotmail.com>
Co-authored-by: 's avatarchengronglai <chengrongl@nvidia.com>
Co-authored-by: 's avatarKelly Guo <kellyg@nvidia.com>
parent d032b453
......@@ -24,8 +24,6 @@ keywords = ["experience", "app", "usd"]
"isaacsim.gui.menu" = {}
"isaacsim.gui.property" = {}
"isaacsim.replicator.behavior" = {}
"isaacsim.robot_motion.lula" = {}
"isaacsim.robot_motion.motion_generation" = {}
"isaacsim.robot.manipulators" = {}
"isaacsim.robot.policy.examples" = {}
"isaacsim.robot.schema" = {}
......
......@@ -325,7 +325,7 @@ Collect a set of human demonstrations using the command below. We recommend 10 s
--task Isaac-PickPlace-GR1T2-Abs-v0 \
--teleop_device dualhandtracking_abs \
--dataset_file ./datasets/dataset_gr1.hdf5 \
--num_demos 10
--num_demos 10 --enable_pinocchio
Unlike the prior Franka stacking task, the GR-1 pick and place task uses manual annotation to define subtasks.
Each demo requires a single annotation which denotes when the right robot arm finishes the "idle" subtask and begins to
......@@ -337,7 +337,7 @@ move towards the target object. Annotate the demonstrations by running the follo
--device cuda \
--task Isaac-PickPlace-GR1T2-Abs-Mimic-v0 \
--input_file ./datasets/dataset_gr1.hdf5 \
--output_file ./datasets/dataset_annotated_gr1.hdf5
--output_file ./datasets/dataset_annotated_gr1.hdf5 --enable_pinocchio
.. note::
......@@ -366,7 +366,7 @@ Place the file under ``IsaacLab/datasets`` and run the following command to gene
.. code:: bash
./isaaclab.sh -p scripts/imitation_learning/isaaclab_mimic/generate_dataset.py \
--device cuda --headless --num_envs 10 --generation_num_trials 1000 \
--device cuda --headless --num_envs 10 --generation_num_trials 1000 --enable_pinocchio \
--input_file ./datasets/dataset_annotated_gr1.hdf5 --output_file ./datasets/generated_dataset_gr1.hdf5
Train a policy
......@@ -397,6 +397,7 @@ Visualize the results of the trained policy by running the following command, us
./isaaclab.sh -p scripts/imitation_learning/robomimic/play.py \
--device cuda \
--enable_pinocchio \
--task Isaac-PickPlace-GR1T2-Abs-v0 \
--num_rollouts 50 \
--norm_factor_min <NORM_FACTOR_MIN> \
......
......@@ -9,10 +9,6 @@ Script to add mimic annotations to demos to be used as source demos for mimic da
import argparse
# Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controller
import pinocchio # noqa: F401
from isaaclab.app import AppLauncher
# Launching Isaac Sim Simulator first.
......@@ -31,12 +27,23 @@ parser.add_argument(
help="File name of the annotated output dataset file.",
)
parser.add_argument("--auto", action="store_true", default=False, help="Automatically annotate subtasks.")
parser.add_argument(
"--enable_pinocchio",
action="store_true",
default=False,
help="Enable Pinocchio.",
)
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()
if args_cli.enable_pinocchio:
# Import pinocchio before AppLauncher to force the use of the version installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controllers and the GR1T2 retargeter
import pinocchio # noqa: F401
# launch the simulator
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
......@@ -61,6 +68,9 @@ from isaaclab.utils import configclass
from isaaclab.utils.datasets import EpisodeData, HDF5DatasetFileHandler
import isaaclab_tasks # noqa: F401
if args_cli.enable_pinocchio:
import isaaclab_tasks.manager_based.manipulation.pick_place # noqa: F401
from isaaclab_tasks.utils.parse_cfg import parse_env_cfg
is_paused = False
......
......@@ -7,9 +7,6 @@
Main data generation script.
"""
# Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controller
import pinocchio # noqa: F401
"""Launch Isaac Sim Simulator first."""
......@@ -36,11 +33,22 @@ parser.add_argument(
action="store_true",
help="pause after every subtask during generation for debugging - only useful with render flag",
)
parser.add_argument(
"--enable_pinocchio",
action="store_true",
default=False,
help="Enable Pinocchio.",
)
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()
if args_cli.enable_pinocchio:
# Import pinocchio before AppLauncher to force the use of the version installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controllers and the GR1T2 retargeter
import pinocchio # noqa: F401
# launch the simulator
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
......
......@@ -22,10 +22,6 @@ Args:
import argparse
# Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controller
import pinocchio # noqa: F401
from isaaclab.app import AppLauncher
# add argparse arguments
......@@ -44,6 +40,7 @@ parser.add_argument(
parser.add_argument(
"--norm_factor_max", type=float, default=None, help="Optional: maximum value of the normalization factor."
)
parser.add_argument("--enable_pinocchio", default=False, action="store_true", help="Enable Pinocchio.")
# append AppLauncher cli args
......@@ -51,6 +48,11 @@ AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()
if args_cli.enable_pinocchio:
# Import pinocchio before AppLauncher to force the use of the version installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controllers and the GR1T2 retargeter
import pinocchio # noqa: F401
# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
......
......@@ -38,10 +38,6 @@ import torch
# Omniverse logger
import omni.log
# Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controller
import pinocchio # noqa: F401
# Isaac Lab AppLauncher
from isaaclab.app import AppLauncher
......@@ -62,6 +58,12 @@ parser.add_argument(
default=10,
help="Number of continuous steps with task success for concluding a demo as successful. Default is 10.",
)
parser.add_argument(
"--enable_pinocchio",
action="store_true",
default=False,
help="Enable Pinocchio.",
)
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
......@@ -69,6 +71,11 @@ AppLauncher.add_app_launcher_args(parser)
args_cli = parser.parse_args()
app_launcher_args = vars(args_cli)
if args_cli.enable_pinocchio:
# Import pinocchio before AppLauncher to force the use of the version installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controllers and the GR1T2 retargeter
import pinocchio # noqa: F401
if "handtracking" in args_cli.teleop_device.lower():
app_launcher_args["xr"] = True
......@@ -81,7 +88,10 @@ if "handtracking" in args_cli.teleop_device.lower():
# Additional Isaac Lab imports that can only be imported after the simulator is running
from isaaclab.devices import OpenXRDevice, Se3Keyboard, Se3SpaceMouse
from isaaclab.devices.openxr.retargeters.humanoid.fourier.gr1t2_retargeter import GR1T2Retargeter
if args_cli.enable_pinocchio:
from isaaclab.devices.openxr.retargeters.humanoid.fourier.gr1t2_retargeter import GR1T2Retargeter
import isaaclab_tasks.manager_based.manipulation.pick_place # noqa: F401
from isaaclab.devices.openxr.retargeters.manipulator import GripperRetargeter, Se3AbsRetargeter, Se3RelRetargeter
from isaaclab.envs.mdp.recorders.recorders_cfg import ActionStateRecorderManagerCfg
......
......@@ -10,10 +10,6 @@
import argparse
# Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controller
import pinocchio # noqa: F401
from isaaclab.app import AppLauncher
# add argparse arguments
......@@ -37,6 +33,12 @@ parser.add_argument(
" --num_envs is 1."
),
)
parser.add_argument(
"--enable_pinocchio",
action="store_true",
default=False,
help="Enable Pinocchio.",
)
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
......@@ -44,6 +46,11 @@ AppLauncher.add_app_launcher_args(parser)
args_cli = parser.parse_args()
# args_cli.headless = True
if args_cli.enable_pinocchio:
# Import pinocchio before AppLauncher to force the use of the version installed by IsaacLab and not the one installed by Isaac Sim
# pinocchio is required by the Pink IK controllers and the GR1T2 retargeter
import pinocchio # noqa: F401
# launch the simulator
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app
......
[package]
# Note: Semantic Versioning is used: https://semver.org/
version = "0.36.10"
version = "0.36.11"
# Description
title = "Isaac Lab framework for Robot Learning"
......
Changelog
---------
0.36.10 (2025-04-09)
0.36.11 (2025-04-09)
~~~~~~~~~~~~~~~~~~~~
Changed
......@@ -12,8 +12,8 @@ Changed
the cuda device, which results in NCCL errors on distributed setups.
0.36.9 (2025-04-01)
~~~~~~~~~~~~~~~~~~~
0.36.10 (2025-04-01)
~~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
......@@ -21,7 +21,7 @@ Fixed
* Added check in RecorderManager to ensure that the success indicator is only set if the termination manager is present.
0.36.8 (2025-03-24)
0.36.9 (2025-03-24)
~~~~~~~~~~~~~~~~~~~
Changed
......@@ -31,7 +31,7 @@ Changed
the default settings will be used from the experience files and the double definition is removed.
0.36.7 (2025-03-17)
0.36.8 (2025-03-17)
~~~~~~~~~~~~~~~~~~~
Fixed
......@@ -41,6 +41,18 @@ Fixed
:attr:`effort_limit` is set.
0.36.7 (2025-03-14)
~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Changed the import structure to only import ``pinocchio`` when ``pink-ik`` or ``dex-retargeting`` is being used.
This also solves for the problem that ``pink-ik`` and ``dex-retargeting`` are not supported in windows.
* Removed ``isaacsim.robot_motion.lula`` and ``isaacsim.robot_motion.motion_generation`` from the default loaded Isaac Sim extensions.
* Moved pink ik action config to a separate file.
0.36.6 (2025-03-13)
~~~~~~~~~~~~~~~~~~~
......
......@@ -15,5 +15,3 @@ from .differential_ik import DifferentialIKController
from .differential_ik_cfg import DifferentialIKControllerCfg
from .operational_space import OperationalSpaceController
from .operational_space_cfg import OperationalSpaceControllerCfg
from .pink_ik import PinkIKController
from .pink_ik_cfg import PinkIKControllerCfg
......@@ -8,7 +8,14 @@ from dataclasses import MISSING
import isaacsim.core.utils.prims as prim_utils
from isaacsim.core.api.simulation_context import SimulationContext
from isaacsim.core.prims.articulations import Articulation
from isaacsim.core.prims import SingleArticulation
# enable motion generation extensions
from isaacsim.core.utils.extensions import enable_extension
enable_extension("isaacsim.robot_motion.lula")
enable_extension("isaacsim.robot_motion.motion_generation")
from isaacsim.robot_motion.motion_generation import ArticulationMotionPolicy
from isaacsim.robot_motion.motion_generation.lula.motion_policies import RmpFlow, RmpFlowSmoothed
......@@ -86,7 +93,7 @@ class RmpFlowController:
self.articulation_policies = list()
for prim_path in self._prim_paths:
# add robot reference
robot = Articulation(prim_path)
robot = SingleArticulation(prim_path)
robot.initialize()
# add controller
rmpflow = controller_cls(
......
......@@ -4,7 +4,6 @@
# SPDX-License-Identifier: BSD-3-Clause
"""Retargeters for mapping input device data to robot commands."""
from .humanoid.fourier.gr1t2_retargeter import GR1T2Retargeter
from .manipulator.gripper_retargeter import GripperRetargeter
from .manipulator.se3_abs_retargeter import Se3AbsRetargeter
from .manipulator.se3_rel_retargeter import Se3RelRetargeter
......@@ -5,7 +5,7 @@
from dataclasses import MISSING
from isaaclab.controllers import DifferentialIKControllerCfg, OperationalSpaceControllerCfg, PinkIKControllerCfg
from isaaclab.controllers import DifferentialIKControllerCfg, OperationalSpaceControllerCfg
from isaaclab.managers.action_manager import ActionTerm, ActionTermCfg
from isaaclab.utils import configclass
......@@ -250,30 +250,6 @@ class DifferentialInverseKinematicsActionCfg(ActionTermCfg):
"""The configuration for the differential IK controller."""
@configclass
class PinkInverseKinematicsActionCfg(ActionTermCfg):
"""Configuration for Pink inverse kinematics action term.
This configuration is used to define settings for the Pink inverse kinematics action term,
which is a inverse kinematics framework.
"""
class_type: type[ActionTerm] = task_space_actions.PinkInverseKinematicsAction
"""Specifies the action term class type for Pink inverse kinematics action."""
pink_controlled_joint_names: list[str] = MISSING
"""List of joint names or regular expression patterns that specify the joints controlled by pink IK."""
ik_urdf_fixed_joint_names: list[str] = MISSING
"""List of joint names that specify the joints to be locked in URDF."""
hand_joint_names: list[str] = MISSING
"""List of joint names or regular expression patterns that specify the joints controlled by hand retargeting."""
controller: PinkIKControllerCfg = MISSING
"""Configuration for the Pink IK controller that will be used to solve the inverse kinematics."""
@configclass
class OperationalSpaceControllerActionCfg(ActionTermCfg):
"""Configuration for operational space controller action term.
......
# Copyright (c) 2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from dataclasses import MISSING
from isaaclab.controllers.pink_ik_cfg import PinkIKControllerCfg
from isaaclab.managers.action_manager import ActionTerm, ActionTermCfg
from isaaclab.utils import configclass
from . import pink_task_space_actions
@configclass
class PinkInverseKinematicsActionCfg(ActionTermCfg):
"""Configuration for Pink inverse kinematics action term.
This configuration is used to define settings for the Pink inverse kinematics action term,
which is a inverse kinematics framework.
"""
class_type: type[ActionTerm] = pink_task_space_actions.PinkInverseKinematicsAction
"""Specifies the action term class type for Pink inverse kinematics action."""
pink_controlled_joint_names: list[str] = MISSING
"""List of joint names or regular expression patterns that specify the joints controlled by pink IK."""
ik_urdf_fixed_joint_names: list[str] = MISSING
"""List of joint names that specify the joints to be locked in URDF."""
hand_joint_names: list[str] = MISSING
"""List of joint names or regular expression patterns that specify the joints controlled by hand retargeting."""
controller: PinkIKControllerCfg = MISSING
"""Configuration for the Pink IK controller that will be used to solve the inverse kinematics."""
# Copyright (c) 2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import copy
import torch
from collections.abc import Sequence
from typing import TYPE_CHECKING
import isaaclab.utils.math as math_utils
from isaaclab.assets.articulation import Articulation
from isaaclab.controllers.pink_ik import PinkIKController
from isaaclab.managers.action_manager import ActionTerm
if TYPE_CHECKING:
from isaaclab.envs import ManagerBasedEnv
from . import pink_actions_cfg
class PinkInverseKinematicsAction(ActionTerm):
r"""Pink Inverse Kinematics action term.
This action term processes the action tensor and sets these setpoints in the pink IK framework
The action tensor is ordered in the order of the tasks defined in PinkIKControllerCfg
"""
cfg: pink_actions_cfg.PinkInverseKinematicsActionCfg
"""Configuration for the Pink Inverse Kinematics action term."""
_asset: Articulation
"""The articulation asset to which the action term is applied."""
def __init__(self, cfg: pink_actions_cfg.PinkInverseKinematicsActionCfg, env: ManagerBasedEnv):
"""Initialize the Pink Inverse Kinematics action term.
Args:
cfg: The configuration for this action term.
env: The environment in which the action term will be applied.
"""
super().__init__(cfg, env)
# Resolve joint IDs and names based on the configuration
self._pink_controlled_joint_ids, self._pink_controlled_joint_names = self._asset.find_joints(
self.cfg.pink_controlled_joint_names
)
self.cfg.controller.joint_names = self._pink_controlled_joint_names
self._hand_joint_ids, self._hand_joint_names = self._asset.find_joints(self.cfg.hand_joint_names)
self._joint_ids = self._pink_controlled_joint_ids + self._hand_joint_ids
self._joint_names = self._pink_controlled_joint_names + self._hand_joint_names
# Initialize the Pink IK controller
assert env.num_envs > 0, "Number of environments specified are less than 1."
self._ik_controllers = []
for _ in range(env.num_envs):
self._ik_controllers.append(PinkIKController(cfg=copy.deepcopy(self.cfg.controller), device=self.device))
# Create tensors to store raw and processed actions
self._raw_actions = torch.zeros(self.num_envs, self.action_dim, device=self.device)
self._processed_actions = torch.zeros_like(self.raw_actions)
# Get the simulation time step
self._sim_dt = env.sim.get_physics_dt()
self.total_time = 0 # Variable to accumulate the total time
self.num_runs = 0 # Counter for the number of runs
# Save the base_link_frame pose in the world frame as a transformation matrix in
# order to transform the desired pose of the controlled_frame to be with respect to the base_link_frame
# Shape of env.scene[self.cfg.articulation_name].data.body_link_state_w is (num_instances, num_bodies, 13)
base_link_frame_in_world_origin = env.scene[self.cfg.controller.articulation_name].data.body_link_state_w[
:,
env.scene[self.cfg.controller.articulation_name].data.body_names.index(self.cfg.controller.base_link_name),
:7,
]
# Get robot base link frame in env origin frame
base_link_frame_in_env_origin = copy.deepcopy(base_link_frame_in_world_origin)
base_link_frame_in_env_origin[:, :3] -= self._env.scene.env_origins
self.base_link_frame_in_env_origin = math_utils.make_pose(
base_link_frame_in_env_origin[:, :3], math_utils.matrix_from_quat(base_link_frame_in_env_origin[:, 3:7])
)
# """
# Properties.
# """
@property
def hand_joint_dim(self) -> int:
"""Dimension for hand joint positions."""
return self.cfg.controller.num_hand_joints
@property
def position_dim(self) -> int:
"""Dimension for position (x, y, z)."""
return 3
@property
def orientation_dim(self) -> int:
"""Dimension for orientation (w, x, y, z)."""
return 4
@property
def pose_dim(self) -> int:
"""Total pose dimension (position + orientation)."""
return self.position_dim + self.orientation_dim
@property
def action_dim(self) -> int:
"""Dimension of the action space (based on number of tasks and pose dimension)."""
# The tasks for all the controllers are the same, hence just using the first one to calculate the action_dim
return len(self._ik_controllers[0].cfg.variable_input_tasks) * self.pose_dim + self.hand_joint_dim
@property
def raw_actions(self) -> torch.Tensor:
"""Get the raw actions tensor."""
return self._raw_actions
@property
def processed_actions(self) -> torch.Tensor:
"""Get the processed actions tensor."""
return self._processed_actions
# """
# Operations.
# """
def process_actions(self, actions: torch.Tensor):
"""Process the input actions and set targets for each task.
Args:
actions: The input actions tensor.
"""
# Store the raw actions
self._raw_actions[:] = actions
self._processed_actions[:] = self.raw_actions
# Make a copy of actions before modifying so that raw actions are not modified
actions_clone = actions.clone()
# Extract hand joint positions (last 22 values)
self._target_hand_joint_positions = actions_clone[:, -self.hand_joint_dim :]
# The action tensor provides the desired pose of the controlled_frame with respect to the env origin frame
# But the pink IK controller expects the desired pose of the controlled_frame with respect to the base_link_frame
# So we need to transform the desired pose of the controlled_frame to be with respect to the base_link_frame
# Get the controlled_frame pose wrt to the env origin frame
all_controlled_frames_in_env_origin = []
# The contrllers for all envs are the same, hence just using the first one to get the number of variable_input_tasks
for task_index in range(len(self._ik_controllers[0].cfg.variable_input_tasks)):
controlled_frame_in_env_origin_pos = actions_clone[
:, task_index * self.pose_dim : task_index * self.pose_dim + self.position_dim
]
controlled_frame_in_env_origin_quat = actions_clone[
:, task_index * self.pose_dim + self.position_dim : (task_index + 1) * self.pose_dim
]
controlled_frame_in_env_origin = math_utils.make_pose(
controlled_frame_in_env_origin_pos, math_utils.matrix_from_quat(controlled_frame_in_env_origin_quat)
)
all_controlled_frames_in_env_origin.append(controlled_frame_in_env_origin)
# Stack all the controlled_frame poses in the env origin frame. Shape is (num_tasks, num_envs , 4, 4)
all_controlled_frames_in_env_origin = torch.stack(all_controlled_frames_in_env_origin)
# Transform the controlled_frame to be with respect to the base_link_frame using batched matrix multiplication
controlled_frame_in_base_link_frame = math_utils.pose_in_A_to_pose_in_B(
all_controlled_frames_in_env_origin, math_utils.pose_inv(self.base_link_frame_in_env_origin)
)
controlled_frame_in_base_link_frame_pos, controlled_frame_in_base_link_frame_mat = math_utils.unmake_pose(
controlled_frame_in_base_link_frame
)
# Loop through each task and set the target
for env_index, ik_controller in enumerate(self._ik_controllers):
for task_index, task in enumerate(ik_controller.cfg.variable_input_tasks):
target = task.transform_target_to_world
target.translation = controlled_frame_in_base_link_frame_pos[task_index, env_index, :].cpu().numpy()
target.rotation = controlled_frame_in_base_link_frame_mat[task_index, env_index, :].cpu().numpy()
task.set_target(target)
def apply_actions(self):
# start_time = time.time() # Capture the time before the step
"""Apply the computed joint positions based on the inverse kinematics solution."""
all_envs_joint_pos_des = []
for env_index, ik_controller in enumerate(self._ik_controllers):
curr_joint_pos = self._asset.data.joint_pos[:, self._pink_controlled_joint_ids].cpu().numpy()[env_index]
joint_pos_des = ik_controller.compute(curr_joint_pos, self._sim_dt)
all_envs_joint_pos_des.append(joint_pos_des)
all_envs_joint_pos_des = torch.stack(all_envs_joint_pos_des)
# Combine IK joint positions with hand joint positions
all_envs_joint_pos_des = torch.cat((all_envs_joint_pos_des, self._target_hand_joint_positions), dim=1)
self._asset.set_joint_position_target(all_envs_joint_pos_des, self._joint_ids)
def reset(self, env_ids: Sequence[int] | None = None) -> None:
"""Reset the action term for specified environments.
Args:
env_ids: A list of environment IDs to reset. If None, all environments are reset.
"""
self._raw_actions[env_ids] = torch.zeros(self.action_dim, device=self.device)
......@@ -5,7 +5,6 @@
from __future__ import annotations
import copy
import torch
from collections.abc import Sequence
from typing import TYPE_CHECKING
......@@ -18,7 +17,6 @@ import isaaclab.utils.string as string_utils
from isaaclab.assets.articulation import Articulation
from isaaclab.controllers.differential_ik import DifferentialIKController
from isaaclab.controllers.operational_space import OperationalSpaceController
from isaaclab.controllers.pink_ik import PinkIKController
from isaaclab.managers.action_manager import ActionTerm
from isaaclab.sensors import ContactSensor, ContactSensorCfg, FrameTransformer, FrameTransformerCfg
from isaaclab.sim.utils import find_matching_prims
......@@ -29,191 +27,6 @@ if TYPE_CHECKING:
from . import actions_cfg
class PinkInverseKinematicsAction(ActionTerm):
r"""Pink Inverse Kinematics action term.
This action term processes the action tensor and sets these setpoints in the pink IK framework
The action tensor is ordered in the order of the tasks defined in PinkIKControllerCfg
"""
cfg: actions_cfg.PinkInverseKinematicsActionCfg
"""Configuration for the Pink Inverse Kinematics action term."""
_asset: Articulation
"""The articulation asset to which the action term is applied."""
def __init__(self, cfg: actions_cfg.PinkInverseKinematicsActionCfg, env: ManagerBasedEnv):
"""Initialize the Pink Inverse Kinematics action term.
Args:
cfg: The configuration for this action term.
env: The environment in which the action term will be applied.
"""
super().__init__(cfg, env)
# Resolve joint IDs and names based on the configuration
self._pink_controlled_joint_ids, self._pink_controlled_joint_names = self._asset.find_joints(
self.cfg.pink_controlled_joint_names
)
self.cfg.controller.joint_names = self._pink_controlled_joint_names
self._hand_joint_ids, self._hand_joint_names = self._asset.find_joints(self.cfg.hand_joint_names)
self._joint_ids = self._pink_controlled_joint_ids + self._hand_joint_ids
self._joint_names = self._pink_controlled_joint_names + self._hand_joint_names
# Initialize the Pink IK controller
assert env.num_envs > 0, "Number of environments specified are less than 1."
self._ik_controllers = []
for _ in range(env.num_envs):
self._ik_controllers.append(PinkIKController(cfg=copy.deepcopy(self.cfg.controller), device=self.device))
# Create tensors to store raw and processed actions
self._raw_actions = torch.zeros(self.num_envs, self.action_dim, device=self.device)
self._processed_actions = torch.zeros_like(self.raw_actions)
# Get the simulation time step
self._sim_dt = env.sim.get_physics_dt()
self.total_time = 0 # Variable to accumulate the total time
self.num_runs = 0 # Counter for the number of runs
# Save the base_link_frame pose in the world frame as a transformation matrix in
# order to transform the desired pose of the controlled_frame to be with respect to the base_link_frame
# Shape of env.scene[self.cfg.articulation_name].data.body_link_state_w is (num_instances, num_bodies, 13)
base_link_frame_in_world_origin = env.scene[self.cfg.controller.articulation_name].data.body_link_state_w[
:,
env.scene[self.cfg.controller.articulation_name].data.body_names.index(self.cfg.controller.base_link_name),
:7,
]
# Get robot base link frame in env origin frame
base_link_frame_in_env_origin = copy.deepcopy(base_link_frame_in_world_origin)
base_link_frame_in_env_origin[:, :3] -= self._env.scene.env_origins
self.base_link_frame_in_env_origin = math_utils.make_pose(
base_link_frame_in_env_origin[:, :3], math_utils.matrix_from_quat(base_link_frame_in_env_origin[:, 3:7])
)
# """
# Properties.
# """
@property
def hand_joint_dim(self) -> int:
"""Dimension for hand joint positions."""
return self.cfg.controller.num_hand_joints
@property
def position_dim(self) -> int:
"""Dimension for position (x, y, z)."""
return 3
@property
def orientation_dim(self) -> int:
"""Dimension for orientation (w, x, y, z)."""
return 4
@property
def pose_dim(self) -> int:
"""Total pose dimension (position + orientation)."""
return self.position_dim + self.orientation_dim
@property
def action_dim(self) -> int:
"""Dimension of the action space (based on number of tasks and pose dimension)."""
# The tasks for all the controllers are the same, hence just using the first one to calculate the action_dim
return len(self._ik_controllers[0].cfg.variable_input_tasks) * self.pose_dim + self.hand_joint_dim
@property
def raw_actions(self) -> torch.Tensor:
"""Get the raw actions tensor."""
return self._raw_actions
@property
def processed_actions(self) -> torch.Tensor:
"""Get the processed actions tensor."""
return self._processed_actions
# """
# Operations.
# """
def process_actions(self, actions: torch.Tensor):
"""Process the input actions and set targets for each task.
Args:
actions: The input actions tensor.
"""
# Store the raw actions
self._raw_actions[:] = actions
self._processed_actions[:] = self.raw_actions
# Make a copy of actions before modifying so that raw actions are not modified
actions_clone = actions.clone()
# Extract hand joint positions (last 22 values)
self._target_hand_joint_positions = actions_clone[:, -self.hand_joint_dim :]
# The action tensor provides the desired pose of the controlled_frame with respect to the env origin frame
# But the pink IK controller expects the desired pose of the controlled_frame with respect to the base_link_frame
# So we need to transform the desired pose of the controlled_frame to be with respect to the base_link_frame
# Get the controlled_frame pose wrt to the env origin frame
all_controlled_frames_in_env_origin = []
# The contrllers for all envs are the same, hence just using the first one to get the number of variable_input_tasks
for task_index in range(len(self._ik_controllers[0].cfg.variable_input_tasks)):
controlled_frame_in_env_origin_pos = actions_clone[
:, task_index * self.pose_dim : task_index * self.pose_dim + self.position_dim
]
controlled_frame_in_env_origin_quat = actions_clone[
:, task_index * self.pose_dim + self.position_dim : (task_index + 1) * self.pose_dim
]
controlled_frame_in_env_origin = math_utils.make_pose(
controlled_frame_in_env_origin_pos, math_utils.matrix_from_quat(controlled_frame_in_env_origin_quat)
)
all_controlled_frames_in_env_origin.append(controlled_frame_in_env_origin)
# Stack all the controlled_frame poses in the env origin frame. Shape is (num_tasks, num_envs , 4, 4)
all_controlled_frames_in_env_origin = torch.stack(all_controlled_frames_in_env_origin)
# Transform the controlled_frame to be with respect to the base_link_frame using batched matrix multiplication
controlled_frame_in_base_link_frame = math_utils.pose_in_A_to_pose_in_B(
all_controlled_frames_in_env_origin, math_utils.pose_inv(self.base_link_frame_in_env_origin)
)
controlled_frame_in_base_link_frame_pos, controlled_frame_in_base_link_frame_mat = math_utils.unmake_pose(
controlled_frame_in_base_link_frame
)
# Loop through each task and set the target
for env_index, ik_controller in enumerate(self._ik_controllers):
for task_index, task in enumerate(ik_controller.cfg.variable_input_tasks):
target = task.transform_target_to_world
target.translation = controlled_frame_in_base_link_frame_pos[task_index, env_index, :].cpu().numpy()
target.rotation = controlled_frame_in_base_link_frame_mat[task_index, env_index, :].cpu().numpy()
task.set_target(target)
def apply_actions(self):
# start_time = time.time() # Capture the time before the step
"""Apply the computed joint positions based on the inverse kinematics solution."""
all_envs_joint_pos_des = []
for env_index, ik_controller in enumerate(self._ik_controllers):
curr_joint_pos = self._asset.data.joint_pos[:, self._pink_controlled_joint_ids].cpu().numpy()[env_index]
joint_pos_des = ik_controller.compute(curr_joint_pos, self._sim_dt)
all_envs_joint_pos_des.append(joint_pos_des)
all_envs_joint_pos_des = torch.stack(all_envs_joint_pos_des)
# Combine IK joint positions with hand joint positions
all_envs_joint_pos_des = torch.cat((all_envs_joint_pos_des, self._target_hand_joint_positions), dim=1)
self._asset.set_joint_position_target(all_envs_joint_pos_des, self._joint_ids)
def reset(self, env_ids: Sequence[int] | None = None) -> None:
"""Reset the action term for specified environments.
Args:
env_ids: A list of environment IDs to reset. If None, all environments are reset.
"""
self._raw_actions[env_ids] = torch.zeros(self.action_dim, device=self.device)
class DifferentialInverseKinematicsAction(ActionTerm):
r"""Inverse Kinematics action term.
......
......@@ -6,6 +6,7 @@
"""Installation script for the 'isaaclab' python package."""
import os
import platform
import toml
from setuptools import setup
......@@ -39,10 +40,15 @@ INSTALL_REQUIRES = [
# livestream
"starlette==0.46.0",
"flatdict==4.0.1",
"pin-pink==3.1.0", # required by isaaclab.isaaclab.controllers.pink_ik
"dex-retargeting==0.4.6", # required by isaaclab.devices.openxr.retargeters.humanoid.fourier.gr1_t2_dex_retargeting_utils
]
# Additional dependencies that are only available on Linux platforms
if platform.system() == "Linux":
INSTALL_REQUIRES += [
"pin-pink==3.1.0", # required by isaaclab.isaaclab.controllers.pink_ik
"dex-retargeting==0.4.6", # required by isaaclab.devices.openxr.retargeters.humanoid.fourier.gr1_t2_dex_retargeting_utils
]
PYTORCH_INDEX_URL = ["https://download.pytorch.org/whl/cu118"]
# Installation operation
......
[package]
# Note: Semantic Versioning is used: https://semver.org/
version = "0.10.28"
version = "0.10.29"
# Description
title = "Isaac Lab Environments"
......
Changelog
---------
0.10.28 (2025-03-25)
0.10.29 (2025-03-25)
~~~~~~~~~~~~~~~~~~~~
Fixed
......@@ -10,7 +10,7 @@ Fixed
* Fixed environment test failure for ``Isaac-Stack-Cube-Franka-IK-Rel-Blueprint-v0``.
0.10.27 (2025-03-18)
0.10.28 (2025-03-18)
~~~~~~~~~~~~~~~~~~~~
Added
......@@ -19,6 +19,16 @@ Added
* Added Gymnasium spaces showcase tasks (``Isaac-Cartpole-Showcase-*-Direct-v0``, and ``Isaac-Cartpole-Camera-Showcase-*-Direct-v0``).
0.10.27 (2025-03-13)
~~~~~~~~~~~~~~~~~~~~
Fixed
^^^^^
* Blacklisted pick_place task from being imported automatically by isaaclab_tasks. It now has to be imported
manually by the script due to dependencies on the pinocchio import.
0.10.26 (2025-03-10)
~~~~~~~~~~~~~~~~~~~~
......
......@@ -25,6 +25,7 @@ __version__ = ISAACLAB_TASKS_METADATA["package"]["version"]
from .utils import import_packages
# The blacklist is used to prevent importing configs from sub-packages
_BLACKLIST_PKGS = ["utils", ".mdp"]
# TODO(@ashwinvk): Remove pick_place from the blacklist once pinocchio from Isaac Sim is compatibility
_BLACKLIST_PKGS = ["utils", ".mdp", "pick_place"]
# Import all configs in this package
import_packages(__name__, _BLACKLIST_PKGS)
......@@ -11,10 +11,10 @@ import isaaclab.controllers.utils as ControllerUtils
import isaaclab.envs.mdp as base_mdp
import isaaclab.sim as sim_utils
from isaaclab.assets import ArticulationCfg, AssetBaseCfg, RigidObjectCfg
from isaaclab.controllers import PinkIKControllerCfg
from isaaclab.controllers.pink_ik_cfg import PinkIKControllerCfg
from isaaclab.devices.openxr import XrCfg
from isaaclab.envs import ManagerBasedRLEnvCfg
from isaaclab.envs.mdp.actions.actions_cfg import PinkInverseKinematicsActionCfg
from isaaclab.envs.mdp.actions.pink_actions_cfg import PinkInverseKinematicsActionCfg
from isaaclab.managers import EventTermCfg as EventTerm
from isaaclab.managers import ObservationGroupCfg as ObsGroup
from isaaclab.managers import ObservationTermCfg as ObsTerm
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment