跳到主要内容

3. MuJoCo 快速上手

开始之前,先说明本节需要的基础:

  • 具备 Python 基础,能够创建虚拟环境(如 venvConda)并运行脚本
  • 知道“模型文件描述一个场景/机器人”这件事;即使没系统学过 XML 或 URDF,也不影响跟着做完本节。

本节目标:

  1. 选对安装方式,把环境装起来。
  2. 理解 MJCF -> MjModel -> MjData -> mj_step() 这条最核心的工作流。
  3. 跑通一个最小模型,让一个盒子真正掉下来。
  4. 分清什么时候用 viewer,什么时候直接写 Python 脚本。

3.1 MuJoCo 简介

MuJoCo(Multi-Joint dynamics with Contact)是由 Google DeepMind 维护并开源的高性能通用物理引擎。

传统物理引擎大致分为两类:一类是机器人学与生物力学领域常用的引擎,它们在广义坐标(或关节坐标)下使用高效且精确的递归算法,但要么忽略接触动力学,要么沿用早期的弹簧-阻尼近似,因而往往需要极小的仿真步长;另一类是游戏引擎,采用更现代的思路,通过求解优化问题来计算接触力,但通常在笛卡尔坐标下以数值方式处理关节约束,面对复杂运动链时容易出现不准确与不稳定。MuJoCo 是第一个将两者结合起来的通用物理引擎——广义坐标建模 + 基于优化的接触动力学,在精度与稳定性之间取得了更好的平衡。

它的核心价值,是为机器人学、生物力学、图形动画和机器学习等领域,提供快速而精确的多刚体动力学与接触仿真。对机器人学习者来说,更直观的理解是:MuJoCo 擅长把"建模 → 施加控制 → 推进仿真 → 读取状态"这条闭环做得极其直接。

因此,它尤其适合控制器验证、接触丰富的运动实验、强化学习环境搭建,以及各类需要大量反复迭代的算法原型开发。

MuJoCo 与其他仿真平台的区别

第一次接触仿真时,一个常见误区是把所有平台都想成“只是界面不同”。其实它们的设计重心差别很大。

  • Isaac Sim 更像高保真机器人仿真工作台,强项是逼真的渲染、传感器、场景搭建和围绕工业/数字孪生工作流的集成。
  • Gazebo / Ignition 更像机器人系统集成测试场,和 ROS 生态贴得更近,适合验证感知、导航、控制节点如何在完整系统里协同。
  • PyBullet 更像轻量级、容易快速起步的物理仿真工具,做教学、小实验和快速验证很方便。
  • MuJoCo 则更像动力学、接触与控制实验底座,重点不是把 3D 世界“做得很大很真”,而是把仿真内核、模型组织和算法迭代这条链路做得高效、稳定、可编程。

相比 Isaac Sim 这类高保真平台,MuJoCo 通常对设备和图形环境的要求更低,更适合先把控制、接触和强化学习实验快速跑起来。

所以如果目标是下面这些方向,MuJoCo 往往会更合适:

  • 机械臂控制
  • 腿足机器人接触实验
  • 强化学习环境搭建
  • 模型预测控制、最优控制
  • 算法原型验证

反过来说,如果读者当前更关心的是高保真视觉传感器、复杂场景编辑、ROS 全系统联调,或者偏数字孪生式的工作流,那 Isaac Sim 或 Gazebo 一类平台通常会更自然。MuJoCo 的长板,不在“做一个很完整的仿真世界”,而在“把动力学实验这件事做得非常顺手”。

3.2 安装

3.2.1 安装方式选择

MuJoCo 支持 WindowsLinuxmacOS 等多平台安装,包含 pip 安装和下载官方预编译二进制两种方式。

pip 安装简单,适合新手第一次入门。如果更偏下面这些场景,再考虑下载官方预编译二进制:

  • 想直接体验原生 simulate 应用
  • 想看官方附带的模型集合和 C/C++ sample
  • 想做底层开发或自己编译

3.2.2 pip 安装

推荐使用 Conda 管理 Python 环境,安装命令如下:

conda create -n mujoco python=3.12 -y
conda activate mujoco
python -m pip install --upgrade pip
pip install mujoco==3.7.0

3.2.3 下载官方预编译二进制

如果目标是直接体验原生 simulate、查看官方模型和样例程序,或者后续需要做 C/C++ 层开发,可以直接从 GitHub Releases 下载官方预编译二进制。

基本步骤如下:

  1. 前往 GitHub Releases 下载对应平台的预编译包
  2. Windows.zipLinux.tar.gzmacOS.dmg
  3. Windows/Linux 解压即可,没有额外安装器
  4. macOS 可以直接双击 MuJoCo.app

3.3 GUI 显示

MuJoCo 常见的 GUI 入口主要有两类:

  1. Python 包自带的 mujoco.viewer
  2. 官方原生 GUI 程序 simulate

从功能上看,这两种方式都能打开图形界面并观察仿真;从使用场景上看,它们分别对应两条不同的工作流。

方式 A:mujoco.viewer

这条路线适合已经通过 pip install mujoco 安装了 Python 包的场景。官方 Python 文档明确说明,mujoco.viewer 是 Python 包自带的交互式 GUI viewer,并且它与二进制发布包中的 simulate 基于同一套代码基础。

最简单的启动方式是:

python -m mujoco.viewer

这个命令会打开一个空 viewer,可以直接拖入模型文件;如果已经有 MJCF 文件,也可以直接指定:

python -m mujoco.viewer --mjcf=hello.xml

这条路线更适合:

  • 已经在 Python 环境里工作
  • 想快速确认 GUI 能否正常打开
  • 想把 GUI 验证和后续 Python 脚本工作流接起来

方式 B:simulate

这条路线适合已经下载官方预编译二进制的场景。simulate 是官方原生 GUI 程序,通常和模型文件、样例程序、头文件、动态库一起出现在二进制发布包中。

如果是 Windows/Linux,官方文档给出的最小启动方式是从 bin 子目录运行:

./bin/simulate ./model/humanoid/humanoid.xml

下面动图展示的是执行 ./bin/simulate ./model/humanoid/humanoid.xml 后的界面效果:

官方原生 simulate 打开 humanoid.xml 的界面效果
官方原生 simulate 打开 humanoid.xml 的界面效果

如果只是为了先确认 GUI 能不能正常打开,优先使用 mujoco.viewer 往往更简单;如果已经下载了官方预编译二进制,或者想直接体验原生 simulate,那么这条路线会更直接。

3.4 MuJoCo 的核心心智模型

MuJoCo 上手最快的方法,不是先背 XML 标签,而是先记住这 5 个核心概念。

1. MJCF

MuJoCo 的原生模型描述格式,本质上就是 XML。可以把它理解成“世界、刚体、关节、碰撞体、执行器”这些东西的声明式描述。

2. MjModel

这是编译后的“静态模型”。它描述的是模型结构和参数,本身通常不在仿真过程中频繁改动。

3. MjData

这是仿真运行时的“动态状态”。位置、速度、接触、控制输入、中间计算结果,主要都在这里。

4. mj_step

这是推进物理仿真的核心函数。可以把它理解成“把系统往前走一个时间步”。

5. viewer

viewer 负责把仿真状态可视化出来,但 viewer 本身不是场景编辑器。它更像一个观察、调试和交互窗口。

真正最值得记住的一条主线是:

MJCF 文件 -> 编译成 MjModel -> 创建 MjData -> 循环调用 mj_step()

3.5 第一个模型:让一个盒子掉下来

最好的第一个实验,不是上来就找机械臂,而是先做一个会掉下来的盒子。

因为它会一次性建立三个最重要的直觉:

  • 地面也是 geom
  • 刚体要靠 body + joint
  • 物理是通过 mj_step() 推进的

这个 demo 可以拆成三步:

  1. 先写出最小模型 hello.xml
  2. viewer 直接打开模型,确认 GUI 显示正常
  3. 再分别用无渲染脚本和带 viewer 的脚本推进仿真

编写最小模型 hello.xml

新建一个 hello.xml

<mujoco model="hello_box">
<option timestep="0.002"/>

<worldbody>
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
<geom name="ground" type="plane" size="1 1 0.1" rgba=".9 .9 .9 1"/>

<body name="box" pos="0 0 1">
<freejoint/>
<geom
name="box_geom"
type="box"
size=".1 .2 .3"
rgba="0.1 0.6 0.2 1"
/>
</body>
</worldbody>
</mujoco>

这个模型里最关键的几行是:

  • worldbody:世界坐标系下的场景根节点
  • geom type="plane":地面
  • body name="box":一个独立刚体
  • freejoint:给这个刚体 6 自由度

如果没有 freejoint,这个盒子就会被固定在父坐标系里,不会真的掉下来。

直接用 viewer 打开模型

有了 hello.xml 之后,就可以直接用 Python 包自带 viewer 打开:

python -m mujoco.viewer --mjcf=hello.xml

下面动图展示的是执行 python -m mujoco.viewer --mjcf=hello.xml 后的界面效果:

mujoco.viewer 打开 hello.xml 的界面效果
mujoco.viewer 打开 hello.xml 的界面效果

通常会看到一个悬空盒子掉到平面上。

这一步最重要的认知是:

  • MuJoCo viewer 能很好地“看仿真”
  • 但它不是 Isaac Sim 那种以 GUI 编辑为中心的工作台
  • 主要工作流仍然会是“写模型 + 写脚本”

如果打开的是空 viewer,也没关系。官方文档明确写了它支持先启动空窗口,再拖放模型进去。

先不渲染,只跑物理

先把图形拿掉,是最稳的入门方式。

新建 hello_box_headless.py

import mujoco

model = mujoco.MjModel.from_xml_path("hello.xml")
data = mujoco.MjData(model)

while data.time < 2.0:
mujoco.mj_step(model, data)

print("sim time:", data.time)
print("box position:", data.body("box").xpos.copy())

下面这几个核心对象需要重点理解:

  • MjModel.from_xml_path(...):从 MJCF 文件编译模型
  • MjData(model):创建和模型对应的运行时状态
  • mj_step(model, data):推进一个仿真步
  • data.body("box").xpos:按名字读出刚体位置

执行:

python hello_box_headless.py

执行结果示例:

sim time: 2.0000000000000013
box position: [-1.09938295e-19 8.84563957e-18 2.99892245e-01]

这里最值得关注的是 box position 的第三个分量大约是 0.3。这是因为盒子的半高就是 0.3,当盒子落到地面并稳定下来之后,质心高度会接近这个值。

前两个分量非常接近 0,说明盒子基本停在世界坐标系原点上方;之所以不是严格的 0,主要是浮点数计算带来的微小数值误差。

这一步特别值钱,因为它把“MuJoCo 会不会用”和“viewer 能不能正常开窗”拆开了。

边步进边看 viewer

已经能跑通无渲染脚本后,再进入交互 viewer 会更稳。

新建 hello_box_viewer.py

import time

import mujoco
import mujoco.viewer

model = mujoco.MjModel.from_xml_path("hello.xml")
data = mujoco.MjData(model)

with mujoco.viewer.launch_passive(model, data) as viewer:
while viewer.is_running() and data.time < 10.0:
step_start = time.time()

mujoco.mj_step(model, data)
viewer.sync()

time_until_next_step = model.opt.timestep - (time.time() - step_start)
if time_until_next_step > 0:
time.sleep(time_until_next_step)

执行:

python hello_box_viewer.py

下面动图展示的是执行 python hello_box_viewer.py 后的界面效果:

hello_box_viewer.py 运行时的 viewer 界面效果
hello_box_viewer.py 运行时的 viewer 界面效果

这个版本和前面的 python -m mujoco.viewer --mjcf=hello.xml 不同:前者更像“直接打开模型看结果”,这里则是脚本一边调用 mj_step() 推进仿真,一边通过 viewer.sync() 把状态同步到 GUI。

3.6 从盒子到机器人

当“让一个盒子掉下来”这件事已经能用 MJCF 和 Python 各做一遍时,就已经跨过 MuJoCo 入门里最关键的一步了。

接下来通常有三条路线:

1. 走控制方向

  • 给模型加 joint
  • 加 actuator
  • 在循环里写控制输入
  • 观察轨迹、误差和稳定性

2. 走强化学习方向

  • 把 MuJoCo 任务封装成环境
  • Gymnasium
  • 再接 PPO、SAC、TD3 之类的训练代码

3. 走机器人建模方向

  • 先从简单机械臂开始
  • 再导入自己的 URDF
  • 逐步补碰撞、惯量、执行器和传感器

MuJoCo 官方 overview 也明确写到,模型既可以来自 MJCF,也可以来自 URDF。所以对机器人开发者来说,常见工作流可以理解成:

MJCF / URDF -> MjModel -> MjData -> 控制器 / 优化 / RL

3.7 本节小结

这一节最重要的结论有四个:

  • MuJoCo 是一个偏动力学、控制和强化学习实验的物理引擎
  • 对第一次上手的人,Python 3.12 + pip install mujoco==3.7.0 是截至 2026-04-18 最稳妥的起点
  • 真正需要建立的核心心智模型是 MJCF -> MjModel -> MjData -> mj_step()
  • viewer 很重要,但它是观察和调试窗口,不是完整场景编辑器

当“让一个盒子掉下来”能同时用 viewer 和 Python 脚本各做一遍时,就已经真正迈过 MuJoCo 的入门门槛了。

参考资料