MuJoCo 配置过程

MuJoCo 环境配置过程.

安装 MuJoCo

正如官方介绍中所描述的, MuJoCo 的安装过程 “非常简单”.

C 版本

对于 C 版本, 只需要下载对应的预编译 release 版本 解压即可.

为了验证, 可以直接运行 bin 目录中的可执行程序 simulate, 若出现以下界面, 则表示安装成功.

接下来就可以开心地玩耍了. 比如, 从 model 目录中找到 humanoid.xml 直接拖进来, 界面中便出现了一个站立的铰接人体模型, 随着鼠标键的抬起而垮在地上.

Python 版本

对于 Python 版本, 只需要运行一条命令即可:

1
pip install mujoco

完成后就可以愉快地 import mujoco 了.

对于大部分较新的机器, 安装过程应该都是如此丝滑.

然而, 写下这篇文档, 表示我遇到了一些问题.

出现的问题

  • 对于 C 版本, 我运行 simulate 后, 并没有如愿打开上面的那个界面, 只有一闪而过的影子, 试了各个版本均是如此.
  • 对于 Python 版本, 我 pip install mujoco 之后, 运行 import mujoco 就崩溃.

经过一番折腾, 我发现了问题所在:

MuJoCo 的成功安装, 还有两个必要条件是官方文档没有说的:

  • 安装驱动的 GPU;
  • 支持 AVX 指令的 CPU.

二者缺一不可.

解决方案

显卡驱动

通过 nvidia-smi 命令查看显卡驱动是否成功安装.

若需要重新安装显卡驱动, Windows 中有可能安装失败, 问题在于之前的驱动无法卸载干净. 这时需要另一个软件 DDU 的帮助. 在安全模式下运行 DDU, 即可完全删除之前的显卡驱动. 重启后重新安装驱动即可成功.

查看 CPU 是否支持 AVX 指令

有很多软件可以查看, Windows 下推荐一个软件 CPU-Z, 可以下载免安装版. 运行即可查看 CPU 的相关参数. 可以看到我的 CPU 支持的指令集中不包含 AVX. 机器确实太老了.

对于这种不支持 AVX 指令集的 CPU, 只能通过 MuJoCo 的源码自行 CMake 一个 non-AVX 的版本.

官方链接中找一个 Source code 下载. 在 CMake 中, 只需要把 AVX 相关的两项取消打勾, 然后生成即可. 注意 CMake 版本别太老就好.

另外, 注意 CMAKE_INSTALL_PREFIX 设置最终编译安装的目录.

生成完成之后, 在 Visual Studio 中生成解决方案, 然后 仅生成INSTALL 即可.

现在, 就可以在 CMAKE_INSTALL_PREFIX 中设置的安装目录中看到编译好的文件了. 运行 bin 目录下的 simulate 即出现本文开始的软件界面.

对于 Python 版本, 如果 CPU 不支持 AVX 指令的话, 暂时仍未找到解决办法.

补充

如果要使用 C 版本的 MuJoCo 库, 理论上还需要将 MuJoCo 安装目录中的 bin, libinclude 路径加入系统环境变量中. 然而本着尽量不影响系统配置的原则, 我没有这样做.

设置属性表

由于 MuJoCo 库并不常用, 我这里选择使用配置属性表的方法, 避免向系统环境变量中添加路径.

在项目中新建属性表, 将上述三个路径分别配置在 VC++目录 的这三项中, 以及将库目录中的 lib 文件名填入 链接器输入附加依赖项 中.

这样就完成了 MuJoCo 库的属性表配置, 可以将这个属性表文件保存好, 以后再在这台电脑写 MuJoCo 的项目就可以直接添加现有属性表了. 非常方便.

最后一个问题, 就是程序编译的时候, 可能会报 “找不到 mujoco.dll” 之类的错误. 解决办法有两种: 1. 将 bin 中的 mujoco.dll 复制到系统目录 C:\Windows\System32C:\Windows\SysWOW64 中; 2. 将 mujoco.dll 复制到当前项目目录中. 本着尽量不影响系统配置的原则, 我一般都选择第 2 种方法.

安装 GLFW

要实现可视化, 还需要安装 GLFW 库. 从官网下载预编译版本即可, 属性表配置步骤与上述操作完全一样. 以后要安装其它的库, 也是同样的步骤.

测试示例程序

以上准备工作完成后, 挑一个模型文件(如 humanoid.xml)复制过来, 就可以运行 sample 目录中的示例程序了, 比如 basic.cc 程序, 这里把它改得稍微精简一些.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <cstdio>
#include <cstring>
#include <GLFW/glfw3.h>
#include <mujoco/mujoco.h>

// MuJoCo 数据结构
mjModel* m = NULL; // MuJoCo model
mjData* d = NULL; // MuJoCo data
mjvCamera cam; // abstract camera
mjvOption opt; // visualization options
mjvScene scn; // abstract scene
mjrContext con; // custom GPU context

// 主函数
int main(void) {
char error[1000];
// 读取模型文件
m = mj_loadXML("humanoid.xml", NULL, error, 1000);
// make data
d = mj_makeData(m);
// 初始化 GLFW
if (!glfwInit()) {
mju_error("Could not initialize GLFW");
}
// 创建窗口, make OpenGL context current, request v-sync
GLFWwindow* window = glfwCreateWindow(1200, 900, "Demo", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// 初始化可视数据结构
mjv_defaultCamera(&cam);
mjv_defaultOption(&opt);
mjv_defaultScene(&scn);
mjr_defaultContext(&con);
// 创建场景和上下文
mjv_makeScene(m, &scn, 2000);
mjr_makeContext(m, &con, mjFONTSCALE_150);
// 设置相机距离
cam.distance = 5;
// 启动主循环, 进行模拟
while (!glfwWindowShouldClose(window)) {
mjtNum simstart = d->time;
while (d->time - simstart < 1.0 / 60.0) {
mj_step(m, d);
}
// get framebuffer viewport
mjrRect viewport = { 0, 0, 0, 0 };
glfwGetFramebufferSize(window, &viewport.width, &viewport.height);
// 更新场景与渲染
mjv_updateScene(m, d, &opt, NULL, &cam, mjCAT_ALL, &scn);
mjr_render(viewport, &scn, &con);
// swap OpenGL buffers (blocking call due to v-sync)
glfwSwapBuffers(window);
// process pending GUI events, call GLFW callbacks
glfwPollEvents();
}
// 清空可视化缓存
mjv_freeScene(&scn);
mjr_freeContext(&con);
// 清空 MuJoCo 模型和数据
mj_deleteData(d);
mj_deleteModel(m);
}

运行程序, 再次见证站立小人倒下的过程.

Hello World!