编程#
引言#
本章是 MuJoCo 编程指南。API 参考文档位于单独的一章中:API 参考。MuJoCo 是一个兼容 Windows、Linux 和 macOS 的动态库,需要具有 AVX 指令集的处理器。该库通过与编译器无关的共享内存 C API 暴露了模拟器的全部功能。它也可以在 C++ 程序中使用。
MuJoCo 代码库按功能的不同主要领域组织成子目录
- 引擎
模拟器(或物理引擎)用 C 语言编写。它负责所有的运行时计算。
- 解析器
XML 解析器用 C++ 编写。它可以解析 MJCF 模型和 URDF 模型,将它们转换成内部 mjCModel C++ 对象,该对象通过 mjSpec 暴露给用户。
- 编译器
编译器用 C++ 编写。它接收由解析器构建的 mjCModel C++ 对象,并将其转换为运行时使用的 mjModel C 结构体。
- 抽象可视化器
抽象可视化器用 C 语言编写。它生成一个抽象几何实体列表,代表模拟状态,其中包含实际渲染所需的所有信息。它还提供了用于摄像机和扰动控制的抽象鼠标钩子。
- OpenGL 渲染器
渲染器用 C 语言编写,基于固定功能管线的 OpenGL。它不具备最先进渲染引擎的所有功能(如果需要可以替换为这类引擎),但它仍然提供了高效且信息丰富的 3D 渲染。
- 线程
线程框架(MuJoCo 3.0 新增)用 C++ 编写并暴露在 C 中。它提供了一个 ThreadPool 接口来异步处理任务。要在 MuJoCo 中使用,请创建一个 ThreadPool 并将其分配给 mjData 中的 thread_pool 字段。
- UI 框架
UI 框架用 C 语言编写。UI 元素在 OpenGL 中渲染。它有自己的事件机制和用于键盘和鼠标输入的抽象钩子。代码示例使用 GLFW,但它也可以与其他窗口库一起使用。
开始使用#
MuJoCo 是一个开源项目。我们为运行 Windows、Linux 和 macOS 的 x86_64 和 arm64 机器提供了预编译的动态库。这些库可以从 GitHub Release 页面下载。不打算开发或修改 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 - dynamic libraries, executables, MUJOCO_LOG.TXT
doc - README.txt and REFERENCE.txt
include - header files needed to develop with MuJoCo
model - model collection
sample - code samples and CMakeLists.txt needed to build them
在验证模拟器工作正常后,您可能还想重新编译代码示例,以确保您拥有一个工作正常的开发环境。我们提供了一个跨平台的 CMake 设置,可用于独立于 MuJoCo 库本身构建示例应用程序。
在 macOS 上,DMG 磁盘镜像包含 MuJoCo.app
,您可以双击它启动 simulate
GUI。您还可以将 MuJoCo.app
拖到系统中的 /Applications
目录,就像安装其他任何应用程序一样。除了 MuJoCo.app
应用程序包之外,DMG 还包含 mujoco.framework
子目录,其中包含 MuJoCo 动态库及其所有公共头文件。如果您使用 Xcode,可以将其作为项目中的框架依赖项导入。(这对 Swift 项目也适用,无需任何修改)。如果手动构建,可以使用 -F
和 -framework mujoco
分别指定头文件搜索路径和库搜索路径。
从源代码构建#
要从源代码构建 MuJoCo,您需要安装 CMake 和一个工作正常的 C++17 编译器。步骤如下:
克隆
mujoco
仓库:git clone https://github.com/deepmind/mujoco.git
创建一个新的构建目录并
cd
进入该目录。运行
cmake $PATH_TO_CLONED_REPO
来配置构建。运行
cmake --build .
来构建。
MuJoCo 的构建系统使用 CMake 的 FetchContent 模块,自动从互联网上的上游仓库获取依赖项。
主 CMake 设置将构建 MuJoCo 库本身以及所有示例应用程序,但不会构建 Python 绑定。Python 绑定的构建说明可以在文档的 Python 部分找到。
此外,CMake 设置还实现了安装阶段,将输出文件复制并组织到目标目录。
选择目录:
cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>
构建完成后,使用
cmake --install .
进行安装。
在 Windows 上构建时,请使用 Visual Studio 2019 或更高版本,并确保安装了 Windows SDK 10.0.22000 或更高版本(有关更多详细信息,请参阅 #862)。
提示
作为参考,一个工作正常的构建配置可以在 GitHub 上的 MuJoCo 持续集成设置中找到。
构建文档#
如果您希望在本地构建文档,例如测试改进文档的 pull-request,请执行以下操作:
克隆
mujoco
仓库:git clone https://github.com/deepmind/mujoco.git
进入
doc/
目录:cd mujoco/doc
安装依赖项:
pip install -r requirements.txt
构建 HTML:
make html
在您选择的浏览器中打开
_build/html/index.html
。
头文件#
分发包包含多个头文件,这些文件在所有平台上都是相同的。为了使本文档独立,这些文件也可以通过以下链接获取。
- 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
浮点类型为double
或float
。参见 mjtNum。- mjspec.h
定义了用于程序化模型编辑的枚举和结构体。
- mjplugin.h
定义了引擎插件所需的数据结构。
- mjthread.h
定义了线程所需的数据结构和函数。
- mjmacro.h
定义了在用户代码中有用的 C 宏。
- mjxmacro.h
此文件是可选的,不包含在 mujoco.h 中。它定义了X 宏,可用于自动化将 mjModel 和 mjData 映射到脚本语言,以及需要访问 mjModel 和 mjData 所有字段的其他操作。
- mjexport.h
用于从 MuJoCo 库导出公共符号的宏。客户端代码不应直接使用此头文件。
- mjsan.h
使用 sanitizer 插桩构建时所需的定义。
版本与兼容性#
MuJoCo 自 2010 年以来已被广泛使用,并且相当成熟(尽管我们的版本编号方案非常保守)。然而,它仍在积极开发中,我们有很多关于新功能的令人兴奋的想法,并且也正在根据用户反馈进行更改。这导致建模语言和 API 不可避免地发生变化。虽然我们鼓励用户升级到最新版本,但我们也认识到这并非总是可行,尤其是当其他开发人员发布依赖于 MuJoCo 的软件时。因此,我们引入了一些简单的机制来帮助避免版本冲突,如下所示。
如果现有代码是使用某个版本的 MuJoCo 开发的,并且现在使用不同版本进行编译和链接,情况会更微妙。如果该代码中使用的 API 函数定义发生了变化,编译器或链接器将产生错误。但即使函数定义没有改变,断言软件版本相同仍然是个好主意。为此,主头文件 (mujoco.h) 定义了符号 mjVERSION_HEADER,库提供了函数 mj_version。因此,头文件和库版本可以通过以下方式进行比较:
// recommended version check
if (mjVERSION_HEADER!=mj_version())
complain();
请注意,只有主头文件定义此符号。我们假定每个软件版本发布的头文件集合将保持一致,不会在版本之间混用。为了避免浮点比较带来的复杂性,上述符号和函数使用版本号的 100 倍作为整数,例如,在软件版本 2.1 中,符号 mjVERSION_HEADER 定义为 210。
命名约定#
API 中定义的所有符号都以前缀“mj”开头。“mj”后面的字符确定了符号所属的系列。首先我们列出对应于类型定义的前缀。
mj
核心模拟数据结构(C struct),例如 mjModel。如果前缀后面的所有字符都是大写的,例如 mjMIN,则这是一个宏或符号 (#define)。
mjt
基本类型,例如 mjtGeom。除了 mjtByte 和 mjtNum,此系列中的所有其他定义都是枚举(enum)。
mjf
回调函数类型,例如 mjfGeneric。
mjv
与抽象可视化相关的数据结构,例如 mjvCamera。
mjr
与 OpenGL 渲染相关的数据结构,例如 mjrContext。
mjui
与 UI 框架相关的数据结构,例如 mjuiSection。
mjs
接下来我们列出对应于函数定义的前缀。请注意,函数前缀始终以下划线结尾。
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#
MuJoCo 内置 OpenGL 渲染器的使用将在OpenGL 渲染中解释。对于渲染,MuJoCo 在兼容性配置文件中使用 OpenGL 1.5,并带有 ARB_framebuffer_object
和 ARB_vertex_buffer_object
扩展。OpenGL 符号在第一次调用 mjr_makeContext 函数时通过 GLAD 加载。这意味着 MuJoCo 库本身不显式依赖于 OpenGL,可以在不支持 OpenGL 的系统上使用,只要不调用 mjr_
函数。
使用 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”库。