代码示例#

MuJoCo 附带了几个提供有用功能的代码示例。其中一些相当复杂(尤其是 simulate.cc),但我们希望它们能帮助用户学习如何使用该库进行编程。

testspeed#

此代码示例对给定模型的仿真进行计时。计时过程很简单:对被动动力学(带有可选控制噪声)进行指定步数的展开仿真,同时收集关于接触次数、标量约束和内部性能分析的 CPU 时间的统计信息。然后将结果打印到控制台。要仿真受控动力学而不是被动动力学,可以安装一个控制回调 mjcb_control,或者修改代码以显式设置控制信号,如下面的 仿真循环 部分所述。此命令行实用程序通过以下方式运行:

testspeed modelfile [nstep nthread ctrlnoise npoolthread]

命令行参数如下:

参数

默认值

含义

modelfile

(必需)

模型路径

nstep

10000

每次展开的步数

nthread

1

运行并行展开的线程数

ctrlnoise

0.01

注入到执行器中的伪随机噪声的比例

npoolthread

1

引擎内部线程池中的线程数

注意

  • 当指定 nthread > 1 时,代码会分配一个单独的 mjModel 和每个线程一个 mjData,并并行运行 nthread 个相同的仿真。这测试了所有核心都处于活动状态时的性能,就像在并行收集样本的强化学习场景中一样。最佳的 nthread 通常等于逻辑核心数。

  • 默认情况下,仿真从零速度的模型参考配置开始。但是,如果模型中存在名为“test”的关键帧,则将其用作初始状态。

  • ctrlnoise 参数可以防止模型陷入静态状态,在这种状态下,由于热启动(warmstarts),可以测量到人工加速的仿真。

  • 当指定 npoolthread > 1 时,会创建一个具有指定线程数的引擎内部 mjThreadPool,以加速大型场景的仿真。请注意,虽然可以同时使用 nthreadnpoolthread,但使用这些不同类型多线程的场景通常是互斥的。

  • 为了获得更可重复的性能统计信息,在 Linux 上使用 performance governor 运行该工具,或者在 Windows 上使用 High Performance 电源计划,以减少 CPU 缩放(CPU scaling)带来的噪声。

  • 许多现代 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]

命令行参数如下:

参数

默认值

含义

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 来启用。initOpenGLcloseOpenGL 函数根据定义了上述哪个符号,以三种不同的方式创建和关闭 OpenGL 上下文。

请注意,MuJoCo 渲染代码不依赖于 OpenGL 上下文是如何创建的。这就是 OpenGL 的妙处:它将上下文创建留给平台,而实际渲染则是标准的,在所有平台上都以相同的方式工作。回想起来,将上下文创建排除在标准之外的决定导致了不必要的重叠技术的扩散,这些技术不仅在平台之间不同,而且在 Linux 平台内部也存在差异。添加一些额外的函数(例如 OSMesa 提供的函数)可以避免很多困惑。EGL 是 Khronos 的一个新标准,旨在解决这个问题,并且正在日益普及。但我们目前还不能假定所有用户都安装了它。