Skip to content

Commit b2e3a3d

Browse files
kellyguo11ooctipus
andauthored
Fix Pink IK USD-to-URDF conversion on aarch64 (#6177) (#6181)
# Description - Remove the Pink IK runtime dependency on `nvidia.srl` and use Isaac Sim's built-in `isaacsim.asset.exporter.urdf` converter. - Normalize generated URDF joint limits so Pinocchio accepts Isaac Sim exporter output (`effort`/`velocity` defaults and `inf` cleanup). - Align affected GR1T2 and G1-Inspire Pink IK frame names with the link/frame names produced by the Isaac Sim exporter. - Remove the `nvidia-srl-usd-to-urdf` dependency from `isaaclab_mimic`. - `python -m py_compile docs/conf.py source/isaaclab/isaaclab/controllers/utils.py source/isaaclab/test/controllers/test_controller_utils.py source/isaaclab_tasks/isaaclab_tasks/contrib/pick_place/nutpour_gr1t2_pink_ik_env_cfg.py source/isaaclab_tasks/isaaclab_tasks/contrib/pick_place/exhaustpipe_gr1t2_pink_ik_env_cfg.py source/isaaclab_tasks/isaaclab_tasks/contrib/pick_place/pickplace_gr1t2_env_cfg.py source/isaaclab_tasks/isaaclab_tasks/contrib/pick_place/pickplace_unitree_g1_inspire_hand_env_cfg.py` - `git diff --check` - Direct mocked smoke test of `convert_usd_to_urdf()` using Isaac Sim exporter modules. - Generated GR1T2 and G1-Inspire URDFs with `isaacsim.asset.exporter.urdf`, sanitized them with the new utility, and verified Pinocchio can load them and contains the adjusted target frames: - `GR1T2_fourier_hand_6dof.urdf nq 54 nv 54 missing frames []` - `g1_29dof_inspire_hand.urdf nq 53 nv 53 missing frames []` - Attempted focused pytest through `./isaaclab.sh -p -m pytest source/isaaclab/test/controllers/test_controller_utils.py -k convert_usd_to_urdf_uses_isaacsim_exporter -q`, but this worktree uses system Python and is missing `lazy_loader`. - Attempted Ruff on touched files, but no local Python environment had Ruff installed. ## 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) - New feature (non-breaking change which adds functionality) - Breaking change (existing functionality will not work without user modification) - Documentation update ## 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 - [ ] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [ ] 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 - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [ ] 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 --> Co-authored-by: ooctipus <zhengyuz@nvidia.com>
1 parent a78f0ff commit b2e3a3d

12 files changed

Lines changed: 121 additions & 55 deletions

File tree

docs/conf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@
233233
"pink",
234234
"pinocchio",
235235
"qpsolvers",
236-
"nvidia.srl",
237236
"flatdict",
238237
"filelock",
239238
"IPython",
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed
2+
^^^^^
3+
4+
* Fixed Pink IK USD-to-URDF conversion to use Isaac Sim's URDF exporter instead of the unavailable ``nvidia.srl`` package.

source/isaaclab/isaaclab/controllers/utils.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import os
1515
import re
1616
import sys
17+
import xml.etree.ElementTree as ET
1718

1819
# import logger
1920
logger = logging.getLogger(__name__)
@@ -42,48 +43,41 @@ def convert_usd_to_urdf(usd_path: str, output_path: str, force_conversion: bool
4243

4344
enable_extension("isaacsim.asset.exporter.urdf")
4445

45-
from nvidia.srl.from_usd.to_urdf import UsdToUrdf
46-
47-
usd_to_urdf_kwargs = {
48-
"node_names_to_remove": None,
49-
"edge_names_to_remove": None,
50-
"root": None,
51-
"parent_link_is_body_1": None,
52-
"log_level": logging.ERROR,
53-
}
54-
5546
urdf_output_dir = os.path.join(output_path, "urdf")
56-
urdf_file_name = os.path.basename(usd_path).split(".")[0] + ".urdf"
57-
urdf_output_path = urdf_output_dir + "/" + urdf_file_name
47+
urdf_file_name = os.path.splitext(os.path.basename(usd_path))[0] + ".urdf"
48+
urdf_output_path = os.path.join(urdf_output_dir, urdf_file_name)
5849
urdf_meshes_output_dir = os.path.join(output_path, "meshes")
5950

6051
if not os.path.exists(urdf_output_path) or not os.path.exists(urdf_meshes_output_dir) or force_conversion:
61-
usd_to_urdf = UsdToUrdf.init_from_file(usd_path, **usd_to_urdf_kwargs)
6252
os.makedirs(urdf_output_dir, exist_ok=True)
6353
os.makedirs(urdf_meshes_output_dir, exist_ok=True)
6454

65-
output_path = usd_to_urdf.save_to_file(
66-
urdf_output_path=urdf_output_path,
55+
from isaacsim.asset.exporter.urdf import UsdToUrdfConverter
56+
57+
usd_to_urdf = UsdToUrdfConverter(
58+
stage=usd_path,
59+
root_prim_path=None,
60+
mesh_dir_name="../meshes",
61+
mesh_path_prefix="../meshes/",
6762
visualize_collision_meshes=False,
68-
mesh_dir=urdf_meshes_output_dir,
69-
mesh_path_prefix="",
7063
)
64+
usd_to_urdf.convert(urdf_output_path)
7165

72-
# The current version of the usd to urdf converter creates "inf" effort,
73-
# This has to be replaced with a max value for the urdf to be valid
74-
# Open the file for reading and writing
75-
with open(urdf_output_path) as file:
76-
# Read the content of the file
77-
content = file.read()
66+
_sanitize_urdf_for_pinocchio(urdf_output_path)
67+
return urdf_output_path, urdf_meshes_output_dir
7868

79-
# Replace all occurrences of 'inf' with '0'
80-
content = content.replace("inf", "0.")
8169

82-
# Open the file again to write the modified content
83-
with open(urdf_output_path, "w") as file:
84-
# Write the modified content back to the file
85-
file.write(content)
86-
return urdf_output_path, urdf_meshes_output_dir
70+
def _sanitize_urdf_for_pinocchio(urdf_path: str) -> None:
71+
"""Fill Pinocchio-required non-kinematic joint-limit fields in exported URDFs."""
72+
tree = ET.parse(urdf_path)
73+
changed = False
74+
for limit in tree.iter("limit"):
75+
for attr in ("effort", "velocity"):
76+
if limit.get(attr) in {None, "inf", "+inf", "-inf"}:
77+
limit.set(attr, "0.")
78+
changed = True
79+
if changed:
80+
tree.write(urdf_path, encoding="unicode")
8781

8882

8983
def change_revolute_to_fixed(urdf_path: str, fixed_joints: list[str], verbose: bool = False):

source/isaaclab/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
]
7474
# Adds OpenUSD dependencies based on architecture for Kit less mode.
7575
INSTALL_REQUIRES += [
76-
f"usd-core==25.11.0 ; ({SUPPORTED_ARCHS})",
76+
f"usd-core>=25.11,<26.0 ; ({SUPPORTED_ARCHS})",
7777
f"usd-exchange>=2.2 ; ({SUPPORTED_ARCHS_ARM})",
7878
]
7979

source/isaaclab/test/controllers/test_controller_utils.py

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@
1313
simulation_app = AppLauncher(headless=True).app
1414

1515
import os
16-
17-
# Import the function to test
16+
import sys
1817
import tempfile
18+
import xml.etree.ElementTree as ET
19+
from types import ModuleType
1920

2021
import pytest
2122
import torch
2223

23-
from isaaclab.controllers.utils import change_revolute_to_fixed, change_revolute_to_fixed_regex
24+
from isaaclab.controllers.utils import (
25+
change_revolute_to_fixed,
26+
change_revolute_to_fixed_regex,
27+
convert_usd_to_urdf,
28+
)
2429
from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR, retrieve_file_path
2530
from isaaclab.utils.io.torchscript import load_torchscript_model
2631

@@ -121,6 +126,66 @@ def test_urdf_file(mock_urdf_content):
121126
shutil.rmtree(test_dir)
122127

123128

129+
def _mock_module(monkeypatch, name: str) -> ModuleType:
130+
module = ModuleType(name)
131+
monkeypatch.setitem(sys.modules, name, module)
132+
return module
133+
134+
135+
def _mock_isaacsim_app(monkeypatch):
136+
for module_name in (
137+
"isaacsim",
138+
"isaacsim.core",
139+
"isaacsim.core.experimental",
140+
"isaacsim.core.experimental.utils",
141+
):
142+
_mock_module(monkeypatch, module_name).__path__ = []
143+
enabled_extensions = []
144+
app_module = _mock_module(monkeypatch, "isaacsim.core.experimental.utils.app")
145+
app_module.enable_extension = enabled_extensions.append
146+
return enabled_extensions
147+
148+
149+
def test_convert_usd_to_urdf_uses_isaacsim_exporter(monkeypatch, tmp_path):
150+
"""Test that USD-to-URDF conversion uses Isaac Sim's URDF exporter."""
151+
enabled_extensions = _mock_isaacsim_app(monkeypatch)
152+
for module_name in ("isaacsim.asset", "isaacsim.asset.exporter"):
153+
_mock_module(monkeypatch, module_name).__path__ = []
154+
155+
converter_args = {}
156+
157+
class MockUsdToUrdfConverter:
158+
def __init__(self, **kwargs):
159+
converter_args.update(kwargs)
160+
161+
def convert(self, output_path):
162+
with open(output_path, "w") as file:
163+
file.write(
164+
'<robot><joint name="j" type="revolute">'
165+
'<limit lower="-inf" upper="inf" velocity="inf"/></joint></robot>'
166+
)
167+
168+
urdf_module = _mock_module(monkeypatch, "isaacsim.asset.exporter.urdf")
169+
urdf_module.UsdToUrdfConverter = MockUsdToUrdfConverter
170+
171+
urdf_path, mesh_path = convert_usd_to_urdf("/assets/gr1.usd", str(tmp_path))
172+
173+
assert enabled_extensions == ["isaacsim.asset.exporter.urdf"]
174+
assert converter_args == {
175+
"stage": "/assets/gr1.usd",
176+
"root_prim_path": None,
177+
"mesh_dir_name": "../meshes",
178+
"mesh_path_prefix": "../meshes/",
179+
"visualize_collision_meshes": False,
180+
}
181+
assert (urdf_path, mesh_path) == (str(tmp_path / "urdf" / "gr1.urdf"), str(tmp_path / "meshes"))
182+
limit = ET.parse(urdf_path).find("joint/limit")
183+
assert limit.attrib["lower"] == "-inf"
184+
assert limit.attrib["upper"] == "inf"
185+
assert limit.attrib["effort"] == "0."
186+
assert limit.attrib["velocity"] == "0."
187+
188+
124189
# =============================================================================
125190
# Test cases for change_revolute_to_fixed function
126191
# =============================================================================
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Removed
2+
^^^^^^^
3+
4+
* Removed the ``nvidia-srl-usd-to-urdf`` dependency now that Pink IK conversion uses Isaac Sim's URDF exporter.

source/isaaclab_mimic/setup.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@
2525
"h5py==3.15.1",
2626
]
2727

28-
# nvidia-srl-usd-to-urdf depends on usd-core which has no aarch64 wheels
29-
if platform.machine() != "aarch64":
30-
INSTALL_REQUIRES.append("nvidia-srl-usd-to-urdf")
31-
3228
# robomimic has no Windows/macOS wheels; only add it on Linux
3329
if platform.system() == "Linux":
3430
INSTALL_REQUIRES.append("robomimic @ git+https://github.com/ARISE-Initiative/robomimic.git@v0.4.0")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed
2+
^^^^^
3+
4+
* Updated GR1T2 and G1-Inspire Pink IK task frame names to match URDFs generated by Isaac Sim's exporter.

source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/pick_place/exhaustpipe_gr1t2_pink_ik_env_cfg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ def __post_init__(self):
8282
fail_on_joint_limit_violation=False,
8383
variable_input_tasks=[
8484
FrameTaskCfg(
85-
frame="GR1T2_fourier_hand_6dof_left_hand_pitch_link",
85+
frame="left_hand_pitch_link",
8686
position_cost=8.0, # [cost] / [m]
8787
orientation_cost=1.0, # [cost] / [rad]
8888
lm_damping=10, # dampening for solver for step jumps
8989
gain=0.5,
9090
),
9191
FrameTaskCfg(
92-
frame="GR1T2_fourier_hand_6dof_right_hand_pitch_link",
92+
frame="right_hand_pitch_link",
9393
position_cost=8.0, # [cost] / [m]
9494
orientation_cost=1.0, # [cost] / [rad]
9595
lm_damping=10, # dampening for solver for step jumps
@@ -102,8 +102,8 @@ def __post_init__(self):
102102
cost=0.2,
103103
lm_damping=1,
104104
controlled_frames=[
105-
"GR1T2_fourier_hand_6dof_left_hand_pitch_link",
106-
"GR1T2_fourier_hand_6dof_right_hand_pitch_link",
105+
"left_hand_pitch_link",
106+
"right_hand_pitch_link",
107107
],
108108
controlled_joints=[
109109
"left_shoulder_pitch_joint",

source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/pick_place/nutpour_gr1t2_pink_ik_env_cfg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ def __post_init__(self):
8080
fail_on_joint_limit_violation=False,
8181
variable_input_tasks=[
8282
FrameTaskCfg(
83-
frame="GR1T2_fourier_hand_6dof_left_hand_pitch_link",
83+
frame="left_hand_pitch_link",
8484
position_cost=8.0, # [cost] / [m]
8585
orientation_cost=1.0, # [cost] / [rad]
8686
lm_damping=10, # dampening for solver for step jumps
8787
gain=0.5,
8888
),
8989
FrameTaskCfg(
90-
frame="GR1T2_fourier_hand_6dof_right_hand_pitch_link",
90+
frame="right_hand_pitch_link",
9191
position_cost=8.0, # [cost] / [m]
9292
orientation_cost=1.0, # [cost] / [rad]
9393
lm_damping=10, # dampening for solver for step jumps
@@ -100,8 +100,8 @@ def __post_init__(self):
100100
cost=0.2,
101101
lm_damping=1,
102102
controlled_frames=[
103-
"GR1T2_fourier_hand_6dof_left_hand_pitch_link",
104-
"GR1T2_fourier_hand_6dof_right_hand_pitch_link",
103+
"left_hand_pitch_link",
104+
"right_hand_pitch_link",
105105
],
106106
controlled_joints=[
107107
"left_shoulder_pitch_joint",

0 commit comments

Comments
 (0)