Add an MJCF->URDF conversion workflow and a uv-served urdf-loader demo so the walker can be inspected outside MuJoCo. Include playback kinematics, anchor diagnostics, and docs to speed up linkage debugging in Isaac-oriented workflows.
79 lines
2.7 KiB
Python
79 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Convert MuJoCo MJCF assets to Isaac Sim USD assets.
|
|
|
|
Run this with Isaac Sim's Python launcher, for example:
|
|
./python.sh sim/isaac/convert_mjcf_to_usd.py \
|
|
--input sim/mujoco/model/walker.xml \
|
|
--output sim/isaac/model/walker.usd
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import pathlib
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
repo_root = pathlib.Path(__file__).resolve().parents[2]
|
|
default_input = repo_root / "sim" / "mujoco" / "model" / "walker.xml"
|
|
default_output = repo_root / "sim" / "isaac" / "model" / "walker.usd"
|
|
|
|
parser = argparse.ArgumentParser(description="Convert MJCF to USD using Isaac Sim")
|
|
parser.add_argument("--input", type=pathlib.Path, default=default_input, help="Path to MJCF file")
|
|
parser.add_argument("--output", type=pathlib.Path, default=default_output, help="Path to USD output")
|
|
parser.add_argument("--prim-path", default="/World/walker", help="Root prim path for imported robot")
|
|
parser.add_argument("--fix-base", action="store_true", help="Import articulation with fixed base")
|
|
parser.add_argument("--headless", action="store_true", help="Run Isaac Sim headless")
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
|
|
input_path = args.input.resolve()
|
|
output_path = args.output.resolve()
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
if not input_path.exists():
|
|
raise FileNotFoundError(f"MJCF file not found: {input_path}")
|
|
|
|
from isaacsim import SimulationApp
|
|
|
|
app = SimulationApp({"headless": args.headless})
|
|
try:
|
|
import omni.kit.commands
|
|
import omni.usd
|
|
from omni.isaac.core.utils.extensions import enable_extension
|
|
|
|
enable_extension("omni.importer.mjcf")
|
|
|
|
ok, import_config = omni.kit.commands.execute("MJCFCreateImportConfig")
|
|
if not ok:
|
|
raise RuntimeError("Failed to create MJCF import config")
|
|
|
|
import_config.fix_base = args.fix_base
|
|
import_config.make_default_prim = True
|
|
import_config.self_collision = True
|
|
import_config.create_physics_scene = True
|
|
|
|
ok, _ = omni.kit.commands.execute(
|
|
"MJCFCreateAsset",
|
|
mjcf_path=str(input_path),
|
|
import_config=import_config,
|
|
prim_path=args.prim_path,
|
|
)
|
|
if not ok:
|
|
raise RuntimeError("MJCF import failed")
|
|
|
|
usd_context = omni.usd.get_context()
|
|
if not usd_context.save_as_stage(str(output_path)):
|
|
raise RuntimeError(f"Failed to save USD: {output_path}")
|
|
|
|
print(f"Converted MJCF -> USD: {input_path} -> {output_path}")
|
|
finally:
|
|
app.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|