扩展开发#

在 Omniverse 中,一切都是扩展或扩展的集合(即应用程序)。它们是模块化的包,构成了 Omniverse 生态系统的原子。每个扩展提供一组功能,其他扩展或独立应用程序可以使用这些功能。如果一个文件夹在 config 目录中包含 extension.toml 文件,则该文件夹被识别为扩展。有关扩展的更多信息,请参阅 Omniverse文档

每个Isaac Lab中的扩展都被编写为一个python包,并且遵循以下结构:

<extension-name>
├── config
│   └── extension.toml
├── docs
│   ├── CHANGELOG.md
│   └── README.md
├── <extension-name>
│   ├── __init__.py
│   ├── ....
│   └── scripts
├── setup.py
└── tests

config/extension.toml 文件包含扩展的元数据。这包括名称、版本、描述、依赖关系等。Omniverse API 使用此信息来加载扩展。 docs 目录包含有关扩展的文档,其中包括有关扩展的更详细信息以及一个包含扩展在每个版本中所做更改的 CHANGELOG 文件。

<extension-name> 目录包含扩展的主要 Python 包。它也可能包含 scripts 目录,用于存放在启用扩展时加载到 Omniverse 中的基于 Python 的应用程序,使用 Extension Manager

更具体地说,当启用扩展时,将加载 config/extension.toml 文件中指定的python模块,并执行包含 omni.ext.IExt 类子类的脚本。

import omni.ext

class MyExt(omni.ext.IExt):
   """My extension application."""

   def on_startup(self, ext_id):
      """Called when the extension is loaded."""
      pass

   def on_shutdown(self):
      """Called when the extension is unloaded.

      It releases all references to the extension and cleans up any resources.
      """
      pass

在 Omniverse 中,加载扩展是自动完成的,但在独立应用程序中使用 Python 包需要额外的步骤。为了简化构建过程并避免需要理解 Omniverse 使用的 premake 构建系统,我们直接使用 setuptools Python 包来构建扩展提供的 Python 模块。这是通过扩展目录中的 setup.py 文件完成的。

备注

setup.py 文件不是必需的,只有在使用 Extension Manager 将扩展加载到 Omniverse 中时才需要。

最后,tests 目录包含了该扩展的单元测试。这些测试是使用 unittest 框架编写的。需要注意的是,Omniverse 也提供了类似的 测试框架 。然而,它需要经过构建过程,并且不支持在独立应用程序中对python模块进行测试。

自定义扩展依赖管理#

某些扩展可能具有依赖项,需要在扩展可以使用之前安装额外的软件包。虽然 Python 依赖项由 setuptools 软件包处理并在 setup.py 文件中指定,但是像 ROS 软件包或 apt 软件包之类的非 Python 依赖项并不由 setuptools 处理。处理这些类型的依赖关系需要额外的过程。

有两种类型的依赖关系可以在 extension.toml 文件的 isaac_lab_settings 部分中指定:

  1. apt_deps: 需要安装的apt软件包列表。这些使用 apt 软件包管理器安装。

  2. ros_ws: 包含 ROS 软件包的 ROS 工作空间路径。这些软件包是使用 rosdep 依赖管理器安装的。

作为示例,以下的 extension.toml 文件指定了扩展的依赖关系:

[isaac_lab_settings]
# apt dependencies
apt_deps = ["libboost-all-dev"]

# ROS workspace
# note: if this path is relative, it is relative to the extension directory's root
ros_ws = "/home/user/catkin_ws"

这些依赖项是使用 tools 目录中提供的 install_deps.py 脚本安装的。要为所有扩展安装所有依赖项,请运行以下命令:

# execute from the root of the repository
# the script expects the type of dependencies to install and the path to the extensions directory
# available types are: 'apt', 'rosdep' and 'all'
python tools/install_deps.py all ${ISAACLAB_PATH}/source

备注

当前,此脚本在构建 Dockerfile.baseDockerfile.ros2 的过程中自动执行。这确保在构建扩展之前分别安装所有 ‘apt’ 和 ‘rosdep’ 依赖项。

独立应用程序#

在典型的 Omniverse 工作流程中,首先启动模拟器,然后启用扩展。Python 模块和其他 Python 应用的加载会自动发生,在后台完成,虽然这是推荐的工作流程,但并非总是可行的。

例如,考虑机器人强化学习。在这种情况下,必须完全控制仿真步骤和更新时机,而不是异步等待结果。在这种情况下,我们需要直接控制仿真,因此有必要编写一个独立的应用程序。这些应用程序在功能上是相似的,它们通过 AppLauncher 启动仿真器,然后通过 SimulationContext 直接控制仿真。在这些情况下,必须在应用程序启动后导入扩展的 python 模块。 在应用程序启动之前这样做会导致缺少模块错误。

以下代码片段显示了如何编写一个独立应用程序:

"""Launch Isaac Sim Simulator first."""

from isaaclab.app import AppLauncher

# launch omniverse app
app_launcher = AppLauncher(headless=False)
simulation_app = app_launcher.app


"""Rest everything follows."""

from isaaclab.sim import SimulationContext

if __name__ == "__main__":
   # get simulation context
   simulation_context = SimulationContext()
   # reset and play simulation
   simulation_context.reset()
   # step simulation
   simulation_context.step()
   # stop simulation
   simulation_context.stop()

   # close the simulation
   simulation_app.close()

在运行任何其他代码之前,必须先启动模拟器,因为扩展在模拟器启动时会被热加载。许多 Omniverse 模块只有在启动模拟器后才会变得可用。有关更多详细信息,我们建议探索 Isaac Lab 教程