编程(Programming)#

介绍(Introduction)#

本章是 MuJoCo 编程指南。单独的章节包含 API 参考 文档。MuJoCo 是一个与 Windows、Linux 和 macOS 兼容的动态库,需要支持 AVX 指令的处理器。该库通过一个与编译器无关的共享内存 C API 公开了模拟器的全部功能。它也可以在 C++ 程序中使用。

MuJoCo 代码库按不同的主要功能区域组织成子目录:

Engine

模拟器(或物理引擎)用 C 语言编写。它负责所有运行时计算。

Parser

XML 解析器用 C++ 编写。它可以解析 MJCF 模型和 URDF 模型,将它们转换为内部的 mjCModel C++ 对象,并通过 mjSpec 暴露给用户。

Compiler

编译器用 C++ 编写。它接收由解析器构建的 mjCModel C++ 对象,并将其转换为运行时使用的 mjModel C 结构体。

Abstract visualizer

抽象可视化器用 C 语言编写。它生成一个表示模拟状态的抽象几何实体列表,包含实际渲染所需的所有信息。它还提供用于相机和扰动控制的抽象鼠标钩子。

OpenGL renderer

渲染器用 C 语言编写,基于固定功能的 OpenGL。它不具备最先进渲染引擎的所有功能(如果需要,可以用此类引擎替换),但它仍然提供高效且信息丰富的 3D 渲染。

Thread

线程框架(MuJoCo 3.0 新增)用 C++ 编写并在 C 中暴露。它提供了一个 ThreadPool 接口来异步处理任务。要在 MuJoCo 中使用,请创建一个 ThreadPool 并将其分配给 mjData 中的 thread_pool 字段。

UI framework

UI 框架用 C 语言编写。UI 元素在 OpenGL 中渲染。它有自己的事件机制以及用于键盘和鼠标输入的抽象钩子。代码示例中它与 GLFW 一起使用,但也可以与其他窗口库一起使用。

入门(Getting started)#

MuJoCo 是一个开源项目。预构建的动态库适用于运行 Windows、Linux 和 macOS 的 x86_64 和 arm64 机器。这些可以从 GitHub Releases 页面 下载。不打算开发或修改核心 MuJoCo 代码的用户鼓励使用我们预构建的库,因为这些库捆绑了我们定期测试的相同版本的依赖项,并受益于为性能调整的构建标志。我们的预构建库几乎是完全自包含的,除了标准的 C 运行时外,不需要任何其他库存在。我们还隐藏了构成 MuJoCo 公共 API 之外的所有符号,从而确保它可以与可能加载到进程中的任何其他库(包括 MuJoCo 依赖的其他库版本)共存。

预构建的发行版在 Windows 上是单个 .zip 文件,在 macOS 上是 .dmg 文件,在 Linux 上是 .tar.gz 文件。没有安装程序。在 Windows 和 Linux 上,只需将存档解压缩到您选择的目录中。现在您可以从 bin 子目录运行预编译的代码示例,例如:

Windows:           simulate ..\model\humanoid\humanoid.xml
Linux and macOS:   ./simulate ../model/humanoid/humanoid.xml

目录结构如下所示。用户可以重新组织它,也可以将动态库安装在其他目录并相应设置路径。唯一自动创建的文件是执行目录中的 MUJOCO_LOG.TXT;它包含错误和警告消息,可以随时删除。

bin     - 动态库、可执行文件、MUJOCO_LOG.TXT
doc     - README.txt 和 REFERENCE.txt
include - 使用 MuJoCo 开发所需的头文件
model   - 模型集合
sample  - 代码示例和构建它们所需的 CMakeLists.txt

验证模拟器工作后,您可能还想重新编译代码示例以确保您有一个可用的开发环境。我们提供了一个跨平台的 CMake 设置,可用于独立于 MuJoCo 库本身构建示例应用程序。

在 macOS 上,DMG 磁盘映像包含 MuJoCo.app,您可以双击它以启动 simulate GUI。您也可以将 MuJoCo.app 拖到系统上的 /Application 中,就像安装任何其他应用程序一样。除了 MuJoCo.app 应用程序包 之外,DMG 还包括 mujoco.framework 子目录,其中包含 MuJoCo 动态库及其所有公共头文件。如果您使用 Xcode,可以将其作为框架依赖项导入到您的项目中。(这也适用于 Swift 项目,无需任何修改)。如果您是手动构建,可以使用 -F-framework mujoco 分别指定头文件搜索路径和库搜索路径。

从源代码构建(Building from source)#

要从源代码构建 MuJoCo,您需要安装 CMake 和一个可用的 C++17 编译器。步骤如下:

  1. 克隆 mujoco 仓库:git clone https://github.com/deepmind/mujoco.git

  2. 创建一个新的构建目录并 cd 进入其中。

  3. 运行 cmake $PATH_TO_CLONED_REPO 来配置构建。

  4. 运行 cmake --build . 进行构建。

MuJoCo 的构建系统使用 CMake 的 FetchContent 模块自动从上游仓库获取互联网上的依赖项。

主要的 CMake 设置将构建 MuJoCo 库本身以及所有示例应用程序,但不会构建 Python 绑定。这些有它们自己的构建说明,可以在文档的 Python 部分找到。

此外,CMake 设置还实现了一个安装阶段,该阶段会将输出文件复制并组织到目标目录中。

  1. 选择目录:cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>

  2. 构建后,使用 cmake --install . 进行安装。

  3. 如果需要,继续构建 Python 绑定 - 参见 从源代码构建

注意:

  • 在 Windows 上构建时,请使用 Visual Studio 2019 或更高版本,并确保安装了 Windows SDK 版本 10.0.22000 或更高版本(有关详细信息,请参阅 #862)。

  • 要优化运行时性能,请使用 -DCMAKE_BUILD_TYPE=Release 构建。

小技巧

作为参考,可以在 GitHub 上的 MuJoCo 持续集成设置 中找到可用的构建配置。

构建文档(Building the docs)#

如果您希望本地构建文档,例如测试改进它的拉取请求,请执行以下操作:

  1. 克隆 mujoco 仓库:git clone https://github.com/deepmind/mujoco.git

  2. 进入 doc/ 目录:cd mujoco/doc

  3. 安装依赖项:pip install -r requirements.txt

  4. 构建 HTML:make html

  5. 在您选择的浏览器中打开 _build/html/index.html

头文件(Header files)#

发行版包含几个头文件,这些文件在所有平台上都是相同的。它们也可以从下面的链接获得,以使本文档自包含。

mujoco.h

这是主要的头文件,必须包含在所有使用 MuJoCo 的程序中。它定义了所有 API 函数和全局变量,并包含除 mjxmacro.h 之外的所有其他头文件。

mjmodel.h

定义了 C 结构体 mjModel,它是被模拟模型的运行时表示。它还定义了许多定义 mjModel 所需的原始类型和其他结构体。

mjdata.h

定义了 C 结构体 mjData,它是所有计算读取输入和写入输出的工作空间。它还定义了定义 mjData 所需的原始类型和其他结构体。

mjvisualize.h

定义了抽象可视化器所需的原始类型和结构体。

mjrender.h

定义了 OpenGL 渲染器所需的原始类型和结构体。

mjui.h

定义了 UI 框架所需的原始类型和结构体。

mjtnum.h

将 MuJoCo 的 mjtNum 浮点类型定义为 doublefloat。参见 mjtNum

mjspec.h

定义了用于 程序化模型编辑 的枚举和结构体。

mjplugin.h

定义了 引擎插件 所需的数据结构。

mjthread.h

定义了 线程 所需的数据结构和函数。

mjmacro.h

定义了在用户代码中有用的 C 宏。

mjxmacro.h

此文件是可选的,不被 mujoco.h 包含。它定义了 X 宏,可以自动化将 mjModel 和 mjData 映射到脚本语言,以及其他需要访问 mjModel 和 mjData 所有字段的操作。

mjexport.h

用于从 MuJoCo 库导出公共符号的宏。客户端代码不应直接使用此头文件。

mjsan.h

使用消毒器检测工具构建时所需的定义。

版本与兼容性(Versions and compatibility)#

MuJoCo 自 2010 年以来被广泛使用并且相当成熟(尽管我们的版本编号方案相当保守)。尽管如此,它仍然处于积极开发中,我们有许多令人兴奋的新功能想法,并且也根据用户反馈进行更改。这导致了建模语言和 API 中不可避免的更改。虽然我们鼓励用户升级到最新版本,但我们认识到这并不总是可行的,特别是当其他开发人员发布依赖 MuJoCo 的软件时。因此,我们引入了简单的机制来帮助避免版本冲突,如下所述。

如果现有代码是用某个版本的 MuJoCo 开发的,而现在正在用不同的版本编译和链接,情况就更微妙了。如果该代码中使用的 API 函数的定义发生了变化,编译器或链接器将生成错误。但是,即使函数定义没有改变,断言软件版本相同可能仍然是一个好主意。为此,主头文件 (mujoco.h) 定义了符号 mjVERSION_HEADER,并且库提供了函数 mj_version。因此,头文件和库版本可以通过以下方式进行比较:

1// 推荐的版本检查
2if (mjVERSION_HEADER != mj_version())
3  complain();

请注意,只有主头文件定义了这个符号。我们假设每个软件版本发布的头文件集合将保持在一起,并且不会在版本之间混合。为了避免浮点比较的复杂性,上述符号和函数使用 100 倍版本号的整数,因此例如在软件版本 2.1 中,符号 mjVERSION_HEADER 被定义为 210。

命名约定(Naming convention)#

API 中定义的所有符号都以前缀 “mj” 开头。前缀中 “mj” 之后的字符决定了符号所属的系列。首先我们列出与类型定义对应的前缀。

mj

核心模拟数据结构(C 结构体),例如 mjModel。如果前缀后的所有字符都是大写的,例如 mjMIN,则这是一个宏或符号 (#define)。

mjt

原始类型,例如 mjtGeom。除了 mjtByte 和 mjtNum,此系列中的所有其他定义都是枚举。

mjf

回调函数类型,例如 mjfGeneric

mjv

与抽象可视化相关的数据结构,例如 mjvCamera

mjr

与 OpenGL 渲染相关的数据结构,例如 mjrContext

mjui

与 UI 框架相关的数据结构,例如 mjuiSection

mjs

程序化模型编辑 相关的数据结构,例如 mjsJoint

接下来我们列出与函数定义对应的前缀。请注意,函数前缀总是以下划线结尾。

mj_

核心模拟函数,例如 mj_step。几乎所有这些函数都有指向 mjModel 和 mjData 的指针作为它们的头两个参数,可能后面跟着其他参数。它们通常将输出写入 mjData。

mju_

工具函数,例如 mju_mulMatVec。这些函数是自包含的,因为它们没有 mjModel 和 mjData 指针作为参数。

mjv_

与抽象可视化相关的函数,例如 mjv_updateScene

mjr_

与 OpenGL 渲染相关的函数,例如 mjr_render

mjui_

与 UI 框架相关的函数,例如 mjui_update

mjcb_

全局回调函数指针,例如 mjcb_control。用户可以通过将这些全局指针设置为用户定义的函数来安装自定义回调。

mjd_

用于计算导数的函数,例如 mjd_transitionFD

mjs_

用于 程序化模型编辑 的函数,例如 mjs_addJoint

使用 OpenGL(Using OpenGL)#

MuJoCo 原生 OpenGL 渲染器的使用将在 OpenGL 渲染 中解释。对于渲染,MuJoCo 在兼容性配置文件中使用 OpenGL 1.5,并带有 ARB_framebuffer_objectARB_vertex_buffer_object 扩展。OpenGL 符号在第一次调用 mjr_makeContext 函数时通过 GLAD 加载。这意味着 MuJoCo 库本身没有对 OpenGL 的显式依赖,只要不调用 mjr_ 函数,就可以在没有 OpenGL 支持的系统上使用。

使用 MuJoCo 内置渲染功能的应用程序负责链接到适当的 OpenGL 上下文创建库,并确保在当前运行线程上存在一个 OpenGL 上下文。在 Windows 和 macOS 上,操作系统提供了规范的 OpenGL 库。在 Linux 上,MuJoCo 目前支持 GLX 用于渲染到 X11 窗口,OSMesa 用于无头软件渲染,以及 EGL 用于硬件加速的无头渲染。

在 2.1.4 版本之前,MuJoCo 使用 GLEW 而不是 GLAD 来管理 OpenGL 符号,这需要在构建时根据使用的 GL 实现链接到不同的 GLEW 库。为了避免在不需要渲染时管理 OpenGL 依赖项,提供了库的“nogl”构建版本。由于在切换到 GLAD 后 OpenGL 符号现在在运行时延迟解析,因此不再提供“nogl”库。