Skip to content

Commit

Permalink
Adds support for MJCF converter (isaac-sim#957)
Browse files Browse the repository at this point in the history
# Description

Added command-line MJCF conversion script and corresponding support and
test files.
- `convert_mjcf.py` in `standalone/tools/`
- `mjcf_converter.py` and `mjcf_converter_cfg.py` in
`extensions/omni.isaac.lab/omni/isaac/lab/sim/converters/`
- tests and corresponding tutorial update


## Checklist

- [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 added tests that prove my fix is effective or that my
feature works
- [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: Kelly Guo <kellyg@nvidia.com>
Signed-off-by: Kelly Guo <kellyguo123@hotmail.com>
Co-authored-by: Kelly Guo <kellyg@nvidia.com>
Co-authored-by: Kelly Guo <kellyguo123@hotmail.com>
  • Loading branch information
3 people authored Sep 11, 2024
1 parent eb5500c commit a78c419
Show file tree
Hide file tree
Showing 13 changed files with 511 additions and 30 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Guidelines for modifications:
* Xavier Nal
* Zhengyu Zhang
* Ziqi Fan
* Qian Wan

## Acknowledgements

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 94 additions & 29 deletions docs/source/how-to/import_new_asset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ extensions to Omniverse Kit:

The recommended workflow from NVIDIA is to use the above importers to convert
the asset into its USD representation. Once the asset is in USD format, you can
use the Omniverse Kit to edit the asset and export it to other file formats.
use the Omniverse Kit to edit the asset and export it to other file formats. Isaac Sim includes these importers by default. They can also be enabled manually in Omniverse Kit.


An important note to use assets for large-scale simulation is to ensure that they
are in `instanceable`_ format. This allows the asset to be efficiently loaded
Expand All @@ -32,27 +33,21 @@ For more details on instanceable assets, please check the Isaac Sim `documentati
Using URDF Importer
-------------------

Isaac Sim includes the URDF and MJCF importers by default. These importers support the
option to import assets as instanceable assets. By selecting this option, the
importer will create two USD files: one for all the mesh data and one for
all the non-mesh data (e.g. joints, rigid bodies, etc.). The prims in the mesh data file are
referenced in the non-mesh data file. This allows the mesh data (which is often bulky) to be
loaded into memory only once and used multiple times in a scene.

For using these importers from the GUI, please check the documentation for `MJCF importer`_ and
`URDF importer`_ respectively.

For using the URDF importers from Python scripts, we include a utility tool called ``convert_urdf.py``.
Internally, this script creates an instance of :class:`~sim.converters.UrdfConverterCfg` which
is then passed to the :class:`~sim.converters.UrdfConverter` class. The configuration class specifies
the default values for the importer. The important settings are:

* :attr:`~sim.converters.UrdfConverterCfg.fix_base` - Whether to fix the base of the robot.
This depends on whether you have a floating-base or fixed-base robot.
* :attr:`~sim.converters.UrdfConverterCfg.make_instanceable` - Whether to create instanceable assets.
Usually, this should be set to ``True``.
* :attr:`~sim.converters.UrdfConverterCfg.merge_fixed_joints` - Whether to merge the fixed joints.
Usually, this should be set to ``True`` to reduce the asset complexity.
For using the URDF importer in the GUI, please check the documentation at `URDF importer`_. For using the URDF importer from Python scripts, we include a utility tool called ``convert_urdf.py``. This script creates an instance of :class:`~sim.converters.UrdfConverterCfg` which
is then passed to the :class:`~sim.converters.UrdfConverter` class.

The URDF importer has various configuration parameters that can be set to control the behavior of the importer.
The default values for the importer's configuration parameters are specified are in the :class:`~sim.converters.UrdfConverterCfg` class, and they are listed below. We made a few commonly modified settings to be available as command-line arguments when calling the ``convert_urdf.py``, and they are marked with ``*``` in the list. For a comprehensive list of the configuration parameters, please check the the documentation at `URDF importer`_.

* :attr:`~sim.converters.UrdfConverterCfg.fix_base*` - Whether to fix the base of the robot.
This depends on whether you have a floating-base or fixed-base robot. The command-line flag is
``--fix-base`` where when set, the importer will fix the base of the robot, otherwise it will default to floating-base.
* :attr:`~sim.converters.UrdfConverterCfg.make_instanceable*` - Whether to create instanceable assets.
Usually, this should be set to ``True``. The command-line flag is ``--make-instanceable`` where
when set, the importer will create instanceable assets, otherwise it will default to non-instanceable.
* :attr:`~sim.converters.UrdfConverterCfg.merge_fixed_joints*` - Whether to merge the fixed joints.
Usually, this should be set to ``True`` to reduce the asset complexity. The command-line flag is
``--merge-joints`` where when set, the importer will merge the fixed joints, otherwise it will default to not merging the fixed joints.
* :attr:`~sim.converters.UrdfConverterCfg.default_drive_type` - The drive-type for the joints.
We recommend this to always be ``"none"``. This allows changing the drive configuration using the
actuator models.
Expand All @@ -62,6 +57,13 @@ the default values for the importer. The important settings are:
* :attr:`~sim.converters.UrdfConverterCfg.default_drive_damping` - The drive damping for the joints.
Similar to the stiffness, we recommend this to always be ``0.0``.


Note that when instanceable option is selected, the
importer will create two USD files: one for all the mesh data and one for
all the non-mesh data (e.g. joints, rigid bodies, etc.). The prims in the mesh data file are
referenced in the non-mesh data file. This allows the mesh data (which is often bulky) to be
loaded into memory only once and used multiple times in a scene.

Example Usage
~~~~~~~~~~~~~

Expand All @@ -86,7 +88,7 @@ The following shows the steps to clone the repository and run the converter:
# clone a repository with URDF files
git clone git@github.com:isaac-orbit/anymal_d_simple_description.git
# go to top of the repository
# go to top of the Isaac Lab repository
cd IsaacLab
# run the converter
./isaaclab.sh -p source/standalone/tools/convert_urdf.py \
Expand All @@ -108,13 +110,67 @@ Executing the above script will create two USD files inside the
main asset file even if the ``--make-instanceable`` flag is set. This means that the
``Props/instanceable_assets.usd`` file is created but not used anymore.

You can press play on the opened window to see the asset in the scene. The asset should "collapse"
if everything is working correctly. If it blows up, then it might be that you have self-collisions
present in the URDF.

To run the script headless, you can add the ``--headless`` flag. This will not open the GUI and
exit the script after the conversion is complete.

You can press play on the opened window to see the asset in the scene. The asset should fall under gravity. If it blows up, then it might be that you have self-collisions present in the URDF.


.. figure:: ../_static/tutorials/tutorial_convert_urdf.jpg
:align: center
:figwidth: 100%
:alt: result of convert_urdf.py



Using MJCF Importer
-------------------

Similar to the URDF Importer, the MJCF Importer also has a GUI interface. Please check the documentation at `MJCF importer`_ for more details. For using the MJCF importer from Python scripts, we include a utility tool called ``convert_mjcf.py``. This script creates an instance of :class:`~sim.converters.MjcfConverterCfg` which is then passed to the :class:`~sim.converters.MjcfConverter` class.

The default values for the importer's configuration parameters are specified in the :class:`~sim.converters.MjcfConverterCfg` class. The configuration parameters are listed below. We made a few commonly modified settings to be available as command-line arguments when calling the ``convert_mjcf.py``, and they are marked with ``*`` in the list. For a comprehensive list of the configuration parameters, please check the the documentation at `MJCF importer`_.


* :attr:`~sim.converters.MjcfConverterCfg.fix_base*` - Whether to fix the base of the robot.
This depends on whether you have a floating-base or fixed-base robot. The command-line flag is
``--fix-base`` where when set, the importer will fix the base of the robot, otherwise it will default to floating-base.
* :attr:`~sim.converters.MjcfConverterCfg.make_instanceable*` - Whether to create instanceable assets.
Usually, this should be set to ``True``. The command-line flag is ``--make-instanceable`` where
when set, the importer will create instanceable assets, otherwise it will default to non-instanceable.
* :attr:`~sim.converters.MjcfConverterCfg.import_sites*` - Whether to parse the <site> tag in the MJCF.
Usually, this should be set to ``True``. The command-line flag is ``--import-sites`` where when set, the importer will parse the <site> tag, otherwise it will default to not parsing the <site> tag.


Example Usage
~~~~~~~~~~~~~

In this example, we use the MuJoCo model of the Unitree's H1 humanoid robot in the `mujoco_menagerie`_.

The following shows the steps to clone the repository and run the converter:

.. code-block:: bash
# create a directory to clone
mkdir ~/git && cd ~/git
# clone a repository with URDF files
git clone git@github.com:git@github.com:google-deepmind/mujoco_menagerie.git
# go to top of the Isaac Lab repository
cd IsaacLab
# run the converter
./isaaclab.sh -p source/standalone/tools/convert_mjcf.py \
~/git/mujoco_menagerie/unitree_h1/h1.xml \
source/extensions/omni.isaac.lab_assets/data/Robots/Unitree/h1.usd \
--import-sites \
--make-instanceable
.. figure:: ../_static/tutorials/tutorial_convert_mjcf.jpg
:align: center
:figwidth: 100%
:alt: result of convert_mjcf.py




Using Mesh Importer
-------------------
Expand Down Expand Up @@ -147,7 +203,7 @@ the steps to clone the repository and run the converter:
# clone a repository with URDF files
git clone git@github.com:NVIDIA-Omniverse/IsaacGymEnvs.git
# go to top of the repository
# go to top of the Isaac Lab repository
cd IsaacLab
# run the converter
./isaaclab.sh -p source/standalone/tools/convert_mesh.py \
Expand All @@ -157,7 +213,9 @@ the steps to clone the repository and run the converter:
--collision-approximation convexDecomposition \
--mass 1.0
Similar to the URDF converter, executing the above script will create two USD files inside the
You may need to press 'F' to zoom in on the asset after import.

Similar to the URDF and MJCF converter, executing the above script will create two USD files inside the
``source/extensions/omni.isaac.lab_assets/data/Props/CubeMultiColor/`` directory. Additionally,
if you press play on the opened window, you should see the asset fall down under the influence
of gravity.
Expand All @@ -168,9 +226,16 @@ of gravity.
properties as well and will be imported as a visual asset.


.. figure:: ../_static/tutorials/tutorial_convert_mesh.jpg
:align: center
:figwidth: 100%
:alt: result of convert_mesh.py


.. _instanceable: https://openusd.org/dev/api/_usd__page__scenegraph_instancing.html
.. _documentation: https://docs.omniverse.nvidia.com/isaacsim/latest/isaac_lab_tutorials/tutorial_instanceable_assets.html
.. _MJCF importer: https://docs.omniverse.nvidia.com/isaacsim/latest/advanced_tutorials/tutorial_advanced_import_mjcf.html
.. _URDF importer: https://docs.omniverse.nvidia.com/isaacsim/latest/advanced_tutorials/tutorial_advanced_import_urdf.html
.. _anymal.urdf: https://github.com/isaac-orbit/anymal_d_simple_description/blob/master/urdf/anymal.urdf
.. _asset converter: https://docs.omniverse.nvidia.com/extensions/latest/ext_asset-converter.html
.. _mujoco_menagerie: https://github.com/google-deepmind/mujoco_menagerie/tree/main/unitree_h1
1 change: 1 addition & 0 deletions source/apps/isaaclab.python.kit
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ keywords = ["experience", "app", "usd"]
"omni.kit.viewport.menubar.render" = {}
"omni.kit.viewport.menubar.camera" = {}
"omni.kit.viewport.menubar.display" = {}
"omni.kit.viewport.menubar.lighting" = {}

"omni.kit.viewport.rtx" = {}
"omni.kit.widget.cache_indicator" = {}
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/omni.isaac.lab/config/extension.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

# Note: Semantic Versioning is used: https://semver.org/
version = "0.22.10"
version = "0.22.11"

# Description
title = "Isaac Lab framework for Robot Learning"
Expand Down
9 changes: 9 additions & 0 deletions source/extensions/omni.isaac.lab/docs/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Changelog
---------

0.22.11 (2024-09-10)
~~~~~~~~~~~~~~~~~~~~

Added
^^^^^

* Added config class, support, and tests for MJCF conversion via standalone python scripts.


0.22.10 (2024-09-09)
~~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@
from .asset_converter_base_cfg import AssetConverterBaseCfg
from .mesh_converter import MeshConverter
from .mesh_converter_cfg import MeshConverterCfg
from .mjcf_converter import MjcfConverter
from .mjcf_converter_cfg import MjcfConverterCfg
from .urdf_converter import UrdfConverter
from .urdf_converter_cfg import UrdfConverterCfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

from __future__ import annotations

import os

import omni.kit.commands
import omni.usd
from omni.isaac.core.utils.extensions import enable_extension
from pxr import Usd

from .asset_converter_base import AssetConverterBase
from .mjcf_converter_cfg import MjcfConverterCfg


class MjcfConverter(AssetConverterBase):
"""Converter for a MJCF description file to a USD file.
This class wraps around the `omni.isaac.mjcf_importer`_ extension to provide a lazy implementation
for MJCF to USD conversion. It stores the output USD file in an instanceable format since that is
what is typically used in all learning related applications.
.. caution::
The current lazy conversion implementation does not automatically trigger USD generation if
only the mesh files used by the MJCF are modified. To force generation, either set
:obj:`AssetConverterBaseCfg.force_usd_conversion` to True or delete the output directory.
.. note::
From Isaac Sim 2023.1 onwards, the extension name changed from ``omni.isaac.mjcf`` to
``omni.importer.mjcf``. This converter class automatically detects the version of Isaac Sim
and uses the appropriate extension.
.. _omni.isaac.mjcf_importer: https://docs.omniverse.nvidia.com/isaacsim/latest/ext_omni_isaac_mjcf.html
"""

cfg: MjcfConverterCfg
"""The configuration instance for MJCF to USD conversion."""

def __init__(self, cfg: MjcfConverterCfg):
"""Initializes the class.
Args:
cfg: The configuration instance for URDF to USD conversion.
"""
super().__init__(cfg=cfg)

"""
Implementation specific methods.
"""

def _convert_asset(self, cfg: MjcfConverterCfg):
"""Calls underlying Omniverse command to convert MJCF to USD.
Args:
cfg: The configuration instance for MJCF to USD conversion.
"""
import_config = self._get_mjcf_import_config(cfg)
omni.kit.commands.execute(
"MJCFCreateAsset",
mjcf_path=cfg.asset_path,
import_config=import_config,
dest_path=self.usd_path,
)

# fix the issue that material paths are not relative
if self.cfg.make_instanceable:
instanced_usd_path = os.path.join(self.usd_dir, self.usd_instanceable_meshes_path)
stage = Usd.Stage.Open(instanced_usd_path)
# resolve all paths relative to layer path
source_layer = stage.GetRootLayer()
omni.usd.resolve_paths(source_layer.identifier, source_layer.identifier)
stage.Save()

# fix the issue that material paths are not relative
# note: This issue seems to have popped up in Isaac Sim 2023.1.1
stage = Usd.Stage.Open(self.usd_path)
# resolve all paths relative to layer path
source_layer = stage.GetRootLayer()
omni.usd.resolve_paths(source_layer.identifier, source_layer.identifier)
stage.Save()

def _get_mjcf_import_config(self, cfg: MjcfConverterCfg) -> omni.importer.mjcf.ImportConfig:
"""Returns the import configuration for MJCF to USD conversion.
Args:
cfg: The configuration instance for MJCF to USD conversion.
Returns:
The constructed ``ImportConfig`` object containing the desired settings.
"""

# Enable MJCF Extensions
enable_extension("omni.importer.mjcf")

from omni.importer.mjcf import _mjcf as omni_mjcf

import_config = omni_mjcf.ImportConfig()

# set the unit scaling factor, 1.0 means meters, 100.0 means cm
import_config.set_distance_scale(1.0)
# set imported robot as default prim
import_config.set_make_default_prim(True)
# add a physics scene to the stage on import if none exists
import_config.set_create_physics_scene(False)
# set flag to parse <site> tag
import_config.set_import_sites(True)

# -- instancing settings
# meshes will be placed in a separate usd file
import_config.set_make_instanceable(cfg.make_instanceable)
import_config.set_instanceable_usd_path(self.usd_instanceable_meshes_path)

# -- asset settings
# default density used for links, use 0 to auto-compute
import_config.set_density(cfg.link_density)
# import inertia tensor from urdf, if it is not specified in urdf it will import as identity
import_config.set_import_inertia_tensor(cfg.import_inertia_tensor)

# -- physics settings
# create fix joint for base link
import_config.set_fix_base(cfg.fix_base)
# self collisions between links in the articulation
import_config.set_self_collision(cfg.self_collision)

return import_config
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

from dataclasses import MISSING

from omni.isaac.lab.sim.converters.asset_converter_base_cfg import AssetConverterBaseCfg
from omni.isaac.lab.utils import configclass


@configclass
class MjcfConverterCfg(AssetConverterBaseCfg):
"""The configuration class for MjcfConverter."""

link_density = 0.0
"""Default density used for links. Defaults to 0.
This setting is only effective if ``"inertial"`` properties are missing in the MJCF.
"""

import_inertia_tensor: bool = True
"""Import the inertia tensor from mjcf. Defaults to True.
If the ``"inertial"`` tag is missing, then it is imported as an identity.
"""

fix_base: bool = MISSING
"""Create a fix joint to the root/base link. Defaults to True."""

import_sites: bool = True
"""Import the sites from the MJCF. Defaults to True."""

self_collision: bool = False
"""Activate self-collisions between links of the articulation. Defaults to False."""
Loading

0 comments on commit a78c419

Please sign in to comment.