代码示例#
MuJoCo 附带了几个提供有用功能性的代码示例。其中一些相当复杂(尤其是 simulate.cc),但我们希望它们能帮助用户学习如何使用该库进行编程。
testspeed#
此代码示例用于测试给定模型的仿真速度。计时过程很简单:被动动力学(可选控制噪声)的仿真会展开指定的步数,同时收集有关接触点数量、标量约束和内部剖析的 CPU 时间统计数据。然后将结果打印到控制台。要仿真受控动力学而非被动动力学,可以安装一个控制回调函数 mjcb_control,或者修改代码以显式设置控制信号,如下面的仿真循环部分所述。此命令行工具的运行方式为:
testspeed modelfile [nstep nthread ctrlnoise npoolthread]
其中命令行参数为
参数 |
默认值 |
含义 |
|---|---|---|
|
(必需) |
模型路径 |
|
10000 |
每次展开的步数 |
|
1 |
运行并行展开的线程数 |
|
0.01 |
注入致动器的伪随机噪声的尺度 |
|
1 |
引擎内部线程池中的线程数 |
注释
当指定
nthread > 1时,代码会分配一个 mjModel 和每个线程一个 mjData,并并行运行nthread个相同的仿真。这用于测试所有核心都处于活动状态下的性能,就像在强化学习场景中并行收集样本一样。最佳的nthread通常等于逻辑核心的数量。默认情况下,仿真从模型的参考配置(速度为零)开始。但是,如果模型中存在名为“test”的关键帧,则会将其用作初始状态。
ctrlnoise参数可防止模型稳定在一个静态状态,在这种状态下,由于热启动,可能会测得虚高的仿真速度。当指定
npoolthread > 1时,会创建一个包含指定线程数的引擎内部 mjThreadPool,以加速大型场景的仿真。请注意,虽然可以同时使用nthread和npoolthread,但通常需要这两种不同类型多线程的场景是互斥的。为了获得更具可重复性的性能统计数据,请在 Linux 上使用
performancegovernor,或在 Windows 上使用High Performance电源计划运行该工具,以减少 CPU 缩放带来的噪声。许多现代 CPU 包含“性能”核心和“效率”核心的混合体。用户应考虑将进程限制为仅在同一种类型的核心上运行,以获得更易于解释的性能统计数据。这可以通过 Linux 上的 taskset 命令或 Windows 上的 start /affinity 命令来完成(在 macOS 上,无法通过已文档化的 API 方式指定处理器亲和性)。
simulate#
此代码示例是一个功能齐全的交互式模拟器。它使用与平台无关的 GLFW 库打开一个 OpenGL 窗口,并在其中渲染仿真状态。它内置了帮助、仿真统计、性能分析器和传感器数据图表。模型文件可以作为命令行参数指定,也可以在运行时通过拖放功能加载。此代码示例使用原生 UI 来渲染各种控件,并演示了新 UI 框架的预期使用方式。以下是 simulate 运行时的屏幕截图
交互通过鼠标完成;按下 F1 键可获得内置帮助,其中包含可用命令的摘要。简而言之,通过左键双击选择一个对象。然后用户可以按住 Ctrl 并拖动鼠标,对所选对象施加力和力矩。单独拖动鼠标(不按 Ctrl)可移动相机。有用于暂停仿真、重置和重新加载模型文件的键盘快捷键。后一个功能在 XML 编辑器中编辑模型时非常有用。
代码很长但注释合理,因此最好直接阅读。这里我们提供一个高层次的概述。main() 函数会初始化 MuJoCo 和 GLFW,打开一个窗口,并安装用于鼠标和键盘处理的 GLFW 回调函数。请注意,没有渲染回调;GLFW 让用户负责,而不是在后台运行渲染循环。主循环处理 UI 事件和渲染。仿真在一个后台线程中处理,该线程与主线程同步。
鼠标和键盘回调函数执行任何必要的操作。其中许多操作调用了 MuJoCo 的抽象可视化机制提供的功能。实际上,该机制旨在或多或少地直接挂钩到鼠标和键盘事件,并提供相机以及扰动控制。
性能分析器和传感器数据图表演示了 mjr_figure 函数的用法,该函数可以绘制带有网格、注释、轴缩放等的精细 2D 图形。性能分析器中显示的信息是从 mjData 的诊断字段中提取的。它是调整约束求解器算法参数的非常有用的工具。模型中定义的传感器的输出被可视化为条形图。
请注意,性能分析器显示的是用高分辨率计时器收集的计时信息。在 Windows 上,根据电源设置,操作系统可能会降低 CPU 频率;这是因为 simulate.cc 为了减速到实时而大部分时间处于休眠状态。这会导致计时不准确。为避免此问题,请更改 Windows 电源计划,使最小处理器状态为 100%。
compile#
此代码示例调用了内置的解析器和编译器。它实现了所有可能的模型格式转换,从 (MJCF, URDF, MJB) 格式转换为 (MJCF, MJB, TXT) 格式。保存为 MJCF 的模型使用我们在建模章节中描述的规范格式子集,因此 MJCF 到 MJCF 的转换通常会产生一个不同的文件。TXT 格式是人类可读的模型路线图。它不能被 MuJoCo 加载,但在模型开发过程中可以作为一个非常有用的辅助工具。它与编译后的 mjModel 是一一对应的。另请注意,可以使用函数 mj_printData 创建一个与 mjData 一一对应的文本文件,尽管此代码示例没有这样做。
basic#
此代码示例是一个最小的交互式模拟器。模型文件必须作为命令行参数提供。它使用与平台无关的 GLFW 库打开一个 OpenGL 窗口,并以 60 fps 的速度渲染仿真状态,同时实时推进仿真。按 Backspace 键重置仿真。鼠标可用于控制相机:左键拖动旋转,右键拖动在垂直平面内平移,Shift+右键拖动在水平平面内平移,滚动或中键拖动缩放。
下面的可视化编程指南解释了可视化的工作原理。此代码示例是该指南中概念的最小化演示。
record#
此代码示例仿真给定模型的被动动力学,进行离屏渲染,读取颜色和深度像素值,并将它们保存到一个原始数据文件中,该文件随后可以使用 ffmpeg 等工具转换为电影文件。与 simulate.cc 相比,渲染过程被简化了,因为没有用户交互、可视化选项或计时;相反,我们只是以默认设置尽可能快地进行渲染。离屏缓冲区的尺寸和多重采样数在 MuJoCo 模型中通过 visual/global/{offwidth, offheight} 和 visual/quality/offsamples 属性指定,而仿真时长、要渲染的每秒帧数(通常远低于物理仿真速率)和输出文件名则作为命令行参数指定。
record modelfile duration fps rgbfile [adddepth]
其中命令行参数为
参数 |
默认值 |
含义 |
|---|---|---|
|
(必需) |
模型路径 |
|
(必需) |
录制时长(秒) |
|
(必需) |
每秒帧数 |
|
(必需) |
原始录制文件的路径 |
|
1 |
在左下角叠加深度图像(0:无) |
例如,一个 5 秒、每秒 60 帧的动画可以通过以下命令创建:
record humanoid.xml 5 60 rgb.out
默认的 humanoid.xml 模型指定了 2560x1440 分辨率的离屏渲染。有了这些信息,我们可以将(大的)原始数据文件压缩成可播放的电影文件:
ffmpeg -f rawvideo -pixel_format rgb24 -video_size 2560x1440
-framerate 60 -i rgb.out -vf "vflip,format=yuv420p" video.mp4
请注意,模型的离屏渲染分辨率和 ffmpeg 的 video_size 必须相同。
此示例可以通过三种方式编译,它们在创建 OpenGL 上下文的方式上有所不同:使用带不可见窗口的 GLFW、使用 OSMesa 或使用 EGL。后两种选项仅在 Linux 上可用,并在编译 record.cc 时通过定义符号 MJ_OSMESA 或 MJ_EGL 来调用。函数 initOpenGL 和 closeOpenGL 根据定义的符号以三种不同的方式创建和关闭 OpenGL 上下文。
请注意,MuJoCo 渲染代码不依赖于 OpenGL 上下文的创建方式。这就是 OpenGL 的美妙之处:它将上下文创建留给平台,而实际的渲染则是标准的,并在所有平台上以相同的方式工作。回想起来,将上下文创建排除在标准之外的决定导致了重叠技术的不必要扩散,这些技术不仅在平台之间不同,在 Linux 的情况下,在同一平台内也不同。增加几个额外的函数(例如 OSMesa 提供的那些)本可以避免很多混淆。EGL 是 Khronos 的一个新标准,旨在解决这个问题,并且它正在变得越来越流行。但我们还不能假设所有用户都安装了它。