|
13 | 13 | simulation_app = AppLauncher(headless=True).app |
14 | 14 |
|
15 | 15 | import os |
16 | | - |
17 | | -# Import the function to test |
| 16 | +import sys |
18 | 17 | import tempfile |
| 18 | +import xml.etree.ElementTree as ET |
| 19 | +from types import ModuleType |
19 | 20 |
|
20 | 21 | import pytest |
21 | 22 | import torch |
22 | 23 |
|
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 | +) |
24 | 29 | from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR, retrieve_file_path |
25 | 30 | from isaaclab.utils.io.torchscript import load_torchscript_model |
26 | 31 |
|
@@ -121,6 +126,66 @@ def test_urdf_file(mock_urdf_content): |
121 | 126 | shutil.rmtree(test_dir) |
122 | 127 |
|
123 | 128 |
|
| 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 | + |
124 | 189 | # ============================================================================= |
125 | 190 | # Test cases for change_revolute_to_fixed function |
126 | 191 | # ============================================================================= |
|
0 commit comments