URDF / MJCF -> USD Conversion
SkillDev toolsConvert URDF/MJCF to USD for Isaac Sim and Isaac Lab. Use when importing a new robot description.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the URDF / MJCF -> USD Conversion skill
What this skill tells your AI
The instructions your AI receives, as published by isaac-sim/isaacsim in skills/urdf-mjcf-to-usd-conversion/SKILL.md and read by ahel’s review.
Purpose
Import URDF and MJCF robot descriptions to USD with modern importer APIs, instanceable meshes, and drive configuration for RL or teleop.
Prerequisites
- Built Isaac Sim (
$ISAAC_SIM_DIRor_build/linux-x86_64/release). - NVIDIA GPU with a current driver (
nvidia-smi). - Shell env contract from
isaac-sim-orchestrator:$ISAAC_SIM_DIR,$ISAAC_LAB_DIR,$WORKSPACE_DIR.
Limitations
- Targets Isaac Sim 6 / Kit 110 unless a section states otherwise.
- Does not replace official NVIDIA documentation for unsupported edge cases.
Troubleshooting
| Error / symptom | Cause | Solution |
|---|---|---|
| Extension or import not found | Wrong $ISAAC_SIM_DIR or stale build | Point env vars at _build/linux-x86_64/release or rebuild |
| Black or empty frames | Missing lights or non-RTX render mode | Add dome/key light; confirm RTX / PathTracing settings |
| Hang on stage load or first render | MDL compile or oversized stage | Follow isolation steps in isaac-sim-troubleshooting |
Two conversion paths and one export path.
| Path | When | Driver |
|---|---|---|
| 1. Full Isaac Sim import (CLI) | RL/Lab asset, scripted batch | isaacsim.asset.importer.urdf / .mjcf via urdf_import.py / mjcf_import.py |
| 2. Isaac Lab convert script | Isaac Lab-native config.yaml workflow | $ISAAC_LAB_DIR/scripts/tools/convert_urdf.py / convert_mjcf.py |
| Export | USD -> URDF round-trip | isaacsim.asset.exporter.urdf via urdf_export.py |
Available Scripts
| Script | Purpose | Arguments |
|---|---|---|
scripts/urdf_importer_ros.py | Import URDF from a live ROS 2 robot_state_publisher via URDFImporter | see script --help |
Running scripts
From agent runtimes that expose skill execution helpers, invoke helpers with run_script():
run_script("scripts/urdf_importer_ros.py", args=["--help"])
From a built Isaac Sim tree, run the same file with ./python.sh (Linux) or python.bat (Windows) from _build/*/release, or execute shell helpers directly when they do not require the simulator.
XACRO inputs
The URDFImporter core does not parse XACRO. Two supported paths:
Recommended — import directly from a running ROS 2 node
isaacsim.ros2.urdf adds a dedicated import path that queries the robot_description parameter on any node (typically robot_state_publisher) via the standard GetParameters service, resolves package:// URLs, writes the URDF to a temp file, and feeds it to URDFImporter. The node is responsible for XACRO expansion, so this also covers launch-file-only distributions that never ship a static URDF.
UI: File -> Import from ROS2 URDF Node (opens an import window with the same collider / robot-type / mesh options as the standard URDF importer).
Python (preferred over the deprecated URDFImportFromROS2Node Kit command):
import_urdf_from_ros(usd_out_path, merge_fixed_joints, fix_base, robot_type) — subscribe to robot_state_publisher, resolve package:// URLs, and import URDF when the description is received.
See scripts/urdf_importer_ros.py.
Requires the isaacsim.ros2.urdf extension (depends on isaacsim.ros2.bridge for the ROS 2 runtime), a reachable node publishing robot_description, and Isaac Sim launched from a terminal where the robot workspace is sourced. The sourced workspace must include the robot description package and every package referenced by package:// mesh/resource URLs; the bundled ROS 2 runtime does not provide robot-specific packages. The reader runs asynchronously — the callback fires once the GetParameters service replies.
Fallback — offline xacro CLI
Use when there is no live ROS graph. Requires only the xacro package (pip install xacro or apt install ros-$ROS_DISTRO-xacro):
xacro robot.xacro > robot.urdf
xacro robot.xacro arm_id:=fr3 hand:=true > robot.urdf
# Inside a sourced ROS 2 workspace so package:// / $(find-pkg-share) work:
source /opt/ros/$ROS_DISTRO/setup.bash
source install/setup.bash
xacro $(ros2 pkg prefix --share my_robot_description)/urdf/robot.xacro \
> robot.urdf
Pass the resulting .urdf to Path 1 or Path 2.
Path 1 — Isaac Sim importer (recommended for RL/Lab)
Modern public API: isaacsim.asset.importer.urdf.URDFImporter + URDFImporterConfig (dataclass) and the matching isaacsim.asset.importer.mjcf pair. The post-import isaacsim.asset.transformer runs by default and restructures the USD output (collects dependencies, runs registered rules for physics conversion, materials routing, etc.).
from isaacsim.asset.importer.urdf import URDFImporter, URDFImporterConfig
config = URDFImporterConfig(
urdf_path="/path/robot.urdf",
usd_path="/path/out",
merge_fixed_joints=True,
fix_base=False,
collision_from_visuals=True,
collision_type="Convex Decomposition",
joint_drive_type="force",
joint_target_type="position",
override_joint_stiffness=800.0,
override_joint_damping=40.0,
robot_type="Manipulator", # robot-schema token
run_asset_transformer=True, # default True; applies transformer profile
run_multi_physics_conversion=True, # URDF -> PhysX/MuJoCo physics
)
output_usd = URDFImporter(config).import_urdf()
URDFImporterConfig fields (defaults)
| Field | Default | Notes |
|---|---|---|
urdf_path, usd_path | None | input/output |
merge_fixed_joints | False | collapse fixed joints |
merge_mesh | False | merge meshes per link |
debug_mode | False | extra logging + intermediates |
collision_from_visuals | False | derive collision geom from visuals |
collision_type | "Convex Hull" | Convex Hull / Convex Decomposition / Bounding Sphere / Bounding Cube |
allow_self_collision | False | leave off for training |
ros_package_paths | [] | resolve package:// URLs |
robot_type | "Default" | robot-schema token; see below |
fix_base | False | adds fixed joint world -> root; relocates ArticulationRootAPI |
link_density | None | kg/m^3 fallback when URDF has no mass |
joint_drive_type | None | force / acceleration; or {regex: value} per-joint |
joint_target_type | None | none / position / velocity; or per-joint dict |
override_joint_stiffness | None | Nm/rad (rev) or N/m (pris); or per-joint dict |
override_joint_damping | None | Nms/rad / Ns/m; or per-joint dict |
run_asset_transformer | True | run transformer profile post-import |
run_multi_physics_conversion | True | URDF -> PhysX joint attr conversion |
CLI (Isaac Sim)
source/standalone_examples/api/isaacsim.asset.importer.urdf/urdf_import.py auto-enables omni.scene.optimizer.core and isaacsim.robot.schema, then applies the config.
"$ISAAC_SIM_DIR/python.sh" \
"$ISAAC_SIM_DIR/source/standalone_examples/api/isaacsim.asset.importer.urdf/urdf_import.py" \
--urdf /path/robot.urdf \
--usd-path /path/out \
--merge-fixed-joints \
--fix-base \
--joint-drive-type force \
--joint-target-type position \
--collision-from-visuals --collision-type "Convex Decomposition" \
--robot-type Manipulator \
--ros-package my_pkg:/abs/path/to/my_pkg
# --no-run-asset-transformer to skip the transformer profile.
--robot-type choices come from usd.schema.isaac.robot_schema.get_allowed_tokens(Attributes.ROBOT_TYPE): Default, End Effector, Manipulator, Humanoid, Wheeled, Holonomic, Quadruped, Mobile Manipulators, Aerial.
MJCF import (parallel API)
from isaacsim.asset.importer.mjcf import MJCFImporter, MJCFImporterConfig
config = MJCFImporterConfig(
mjcf_path="/path/robot.xml",
usd_path="/path/out",
import_scene=True, # include MJCF scene settings
merge_mesh=True,
robot_type="Quadruped",
override_gain_type="fixed", # MuJoCo actuator gain type
override_bias_type="affine", # MuJoCo actuator bias type
override_gain_prm=[kp, 0, 0, 0, 0, 0, 0, 0, 0, 0], # position control
override_bias_prm=[0, -kp, -kd, 0, 0, 0, 0, 0, 0, 0], # position control
)
output_usd = MJCFImporter(config).import_mjcf()
CLI: source/standalone_examples/api/isaacsim.asset.importer.mjcf/mjcf_import.py (mirrors URDF: --mjcf, --usd-path, --import-scene, --robot-type, --override-gain-type, --override-bias-type, etc.).
Legacy MJCF commands MJCFCreateAsset / MJCFCreateImportConfig are deprecated; use MJCFImporter directly.
Migration: for the broader
omni.importer.mjcf/omni.importer.urdf→isaacsim.asset.importer.*rename map, see Renaming Extensions.
Asset Transformer (what run_asset_transformer=True runs)
isaacsim.asset.transformer executes ordered USD rule pipelines. Default post-import rules include UrdfToMjcPhysxConversionRule / MjcToPhysxConversionRule and material routing. To run manually on an existing USD:
from isaacsim.asset.transformer import AssetTransformerManager, RuleProfile
manager = AssetTransformerManager()
profile = RuleProfile.from_json("path/to/profile.json")
report = manager.run("input.usd", profile, package_root="/tmp/out")
CLI: source/standalone_examples/api/isaacsim.asset.transformer/run_asset_transformer.py (--input, --profile, --output).
Robot Schema applied during import
The importer applies the modern usd.schema.isaac.robot_schema:
IsaacRobotAPIon the robot root prim (storesrobot_type, ordered link/joint relations, named-pose container).IsaacLinkAPIon rigid links.IsaacJointAPIon joints.IsaacSiteAPIon sites (replaces deprecatedIsaacReferencePointAPI).IsaacNamedPoseprims for named poses; manage via theisaacsim.robot.posermodule (seemanipulation-ik).
Validate after import:
from pxr import Usd
from usd.schema.isaac.robot_schema import Classes, get_allowed_tokens, Attributes
stage = Usd.Stage.Open("/path/out/robot.usd")
robot = next(p for p in stage.Traverse() if p.HasAPI(Classes.ROBOT_API))
print(robot.GetAttribute(Attributes.ROBOT_TYPE).Get())
Path 2 — Isaac Lab convert_urdf.py / convert_mjcf.py (config.yaml)
For Isaac Lab-native workflows you have a config.yaml per robot under assets/isaaclab/Robots/<Robot>/:
asset_path: /path/to/robot.urdf # pre-expand XACRO first
usd_file_name: robot_name.usd
force_usd_conversion: true
make_instanceable: true # critical for parallel envs
import_inertia_tensor: true # use URDF inertia
merge_fixed_joints: true
self_collision: false
fix_base: false
default_drive_type: none # "none" | "position" | "velocity"
default_drive_stiffness: 0.0
default_drive_damping: 0.0
link_density: 0.0
convex_decompose_mesh: false
Run:
cd "$ISAAC_LAB_DIR"
./isaaclab.sh -p scripts/tools/convert_urdf.py \
--config /path/MyRobot/config.yaml --output /path/MyRobot/
# MJCF equivalent:
./isaaclab.sh -p scripts/tools/convert_mjcf.py \
--config /path/MyRobot/config.yaml --output /path/MyRobot/
Drive presets
| Use case | Drive config |
|---|---|
| RL training (agent controls torques) | default_drive_type: none, stiffness 0.0, damping 0.0 |
| Position-controlled teleop | default_drive_type: position, stiffness 800.0, damping 40.0 |
| Assembly / manipulation objects (AutoMate) | default_drive_type: force, joint_drive.target_type: position, gains: {stiffness: 100, damping: 1}, collider_type: convex_hull |
make_instanceable: true
GPU mesh instancing. Without it, 4096 envs * full mesh = VRAM blow-up. With it, parallel envs share one mesh in VRAM. Always set for RL.
fix_base by robot type
| Robot type | fix_base |
|---|---|
| Manipulator arm (table/wall mounted) | true |
| Mobile robot (wheels) | false |
| Humanoid / legged | false |
| Aerial (drone) | false |
URDF export (USD -> URDF round-trip)
isaacsim.asset.exporter.urdf is the inverse path; useful for sharing imported USD assets back to ROS or other URDF-consumers.
from pxr import Usd
from isaacsim.asset.exporter.urdf import UsdToUrdfConverter
stage = Usd.Stage.Open("/path/robot.usd")
converter = UsdToUrdfConverter(
stage,
root_prim_path="/World/robot",
mesh_dir_name="meshes",
mesh_path_prefix="./",
visualize_collision_meshes=False,
variant_selections=None,
)
converter.export("/path/urdf_out")
CLI: source/standalone_examples/api/isaacsim.asset.exporter.urdf/urdf_export.py (--usd-path, --output-dir, --root-prim, --mesh-prefix, --variant SET=SELECTION).
Common pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| OOM during training | make_instanceable: false | set true |
| Robot flies apart | merge_fixed_joints: false + stiff PD | set true or reduce gains |
| Wrong masses | import_inertia_tensor: false + bad geometry | set true |
| Self-collision slowdown | self_collision: true during training | set false |
| XACRO not converting | URDFImporter core does not parse XACRO | import from a running node via isaacsim.ros2.urdf (RobotDefinitionReader / File -> Import from ROS2 URDF Node), or pre-expand offline with xacro robot.xacro > robot.urdf |
package:// URLs unresolved | missing mapping | pass ros_package_paths=[{"name":..., "path":...}] or --ros-package NAME:PATH |
| MJCF actuators behave wrong | gain/bias type left at MJCF default | set override_gain_type / override_bias_type / override_gain_prm / override_bias_prm |
| Transformer output ignored | running an old test asset | delete usd_path and re-import with run_asset_transformer=True |
Pip-wheel availability (standalone usage)
Each importer/exporter is also published as a standalone pip wheel for non-Kit consumers. See .cursor/rules/pip_packaging.mdc for the design.
| Extension | Wheel |
|---|---|
isaacsim.asset.importer.urdf | isaacsim-asset-importer-urdf (deps: isaacsim-asset-transformer, isaacsim-asset-transformer-rules, urdf-usd-converter) |
isaacsim.asset.importer.mjcf | isaacsim-asset-importer-mjcf (deps: mujoco-usd-converter) |
isaacsim.asset.exporter.urdf | isaacsim-asset-exporter-urdf |
isaacsim.asset.transformer | isaacsim-asset-transformer |
isaacsim.asset.transformer.rules | isaacsim-asset-transformer-rules |
isaacsim.robot.schema | isaacsim-robot-schema |
Build via ./repo.sh build_standalone_wheels --ext <name>.
Signals
- GitHub stars
- 4k
- Forks
- 539
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
urdf-mjcf-to-usd-conversion- Source
- github.com/isaac-sim/isaacsim