仿真环境搭建:MuJoCo物理引擎介绍、安装与配置、基本XML建模、场景文件解析
做具身智能,仿真环境就是你的试验田。
我见过太多人,算法写得飞起,一上真机就翻车。为什么?因为仿真环境没搭对。今天咱们就聊聊MuJoCo——这个在机器人圈子里越来越火的物理引擎。
为什么选MuJoCo?
说实话,物理引擎不少。Bullet、ODE、PhysX……但我个人习惯用MuJoCo。原因很简单:它快,而且准。
MuJoCo的全称是Multi-Joint dynamics with Contact。它专门为机器人仿真设计的。你想想看,一个机械臂有6个关节,每个关节都要算力矩、算摩擦、算接触——普通引擎算着算着就飘了。MuJoCo不会。
MuJoCo的核心优势:
- 计算效率高——用了一种叫"软接触"的模型,算得快还不容易发散
- 精度可控——你可以调整仿真步长,从实时仿真到高精度离线仿真都能做
- 力矩控制友好——它原生支持力矩模式,这对我们后面讲力矩控制至关重要
- Python接口完善——mujoco-py和dm_control都很好用
我记得2020年DeepMind把MuJoCo开源了。那时候我正好在做一个灵巧手的项目,之前用Bullet,接触模型怎么调都不对。换成MuJoCo,两天就把问题搞定了。
安装与配置
安装其实不复杂。但有几个坑,我先帮你踩了。
环境要求
| 组件 | 推荐版本 | 备注 |
|---|---|---|
| Python | 3.8 - 3.11 | 3.12有些包还没适配 |
| MuJoCo | 2.3.x 或 3.x | 2.3更稳定,3.x功能更新 |
| mujoco-py | 2.1.2.14 | 注意和MuJoCo版本匹配 |
| 操作系统 | Ubuntu 20.04/22.04 | Windows也能用,但坑更多 |
安装步骤
我个人建议用conda环境,干净利落。
# 创建环境
conda create -n mujoco_env python=3.9
conda activate mujoco_env
# 安装MuJoCo(以2.3.7为例)
# 下载预编译包:https://github.com/deepmind/mujoco/releases
# 解压到 ~/.mujoco/mujoco237/
# 配置环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.mujoco/mujoco237/bin
export MUJOCO_PY_MUJOCO_PATH=$HOME/.mujoco/mujoco237
# 安装mujoco-py
pip install mujoco-py==2.1.2.14
# 验证安装
python -c "import mujoco_py; print('MuJoCo loaded successfully')"
我曾经踩过的坑:
- glfw库缺失——运行时报错"GLFW error",装一下就行:
sudo apt install libglfw3 libglfw3-dev - patchelf没装——编译mujoco-py时需要:
sudo apt install patchelf - Python版本太高——3.12的某些ABI不兼容,老老实实用3.9或3.10
基本XML建模
MuJoCo用XML描述机器人模型。这个XML叫MJCF(MuJoCo CoMpiled Format)。说白了,就是告诉仿真器:你的机器人长什么样、关节在哪、怎么动。
一个最简单的模型长这样:
<mujoco model="simple_arm">
<compiler angle="radian" />
<worldbody>
<light name="top" pos="0 0 1.5"/>
<body name="base" pos="0 0 0.2">
<geom type="box" size="0.1 0.1 0.05" rgba="0.5 0.5 0.5 1"/>
<joint name="shoulder" type="hinge" pos="0 0 0.05" axis="0 0 1"/>
<body name="upper_arm" pos="0 0 0.05">
<geom type="cylinder" size="0.03 0.15" rgba="0.2 0.6 0.8 1"/>
<joint name="elbow" type="hinge" pos="0 0 0.15" axis="0 1 0"/>
<body name="forearm" pos="0 0 0.15">
<geom type="cylinder" size="0.02 0.12" rgba="0.8 0.3 0.2 1"/>
</body>
</body>
</body>
</worldbody>
</mujoco>
这个模型描述了一个两关节机械臂。你看结构:
<worldbody>——整个世界的基础坐标系<body>——每个刚体段,可以嵌套<joint>——关节,定义运动自由度<geom>——几何形状,用来碰撞检测和渲染
嗯,这里要注意:关节的位置和轴方向。我刚开始学的时候,经常把轴设反了。比如肩关节绕Z轴转,肘关节绕Y轴转——你得想清楚你的机器人是怎么运动的。
场景文件解析
场景文件比模型文件多了一些东西。它定义了:环境、物体、初始状态、仿真参数。
来看一个完整的场景:
<mujoco model="pick_and_place">
<compiler angle="radian" meshdir="meshes"/>
<option timestep="0.002" gravity="0 0 -9.81"/>
<asset>
<mesh file="gripper.stl" name="gripper_mesh"/>
<texture type="skybox" file="sky.png"/>
<material name="gripper_mat" texture="sky" texuniform="true"/>
</asset>
<worldbody>
<light directional="true" pos="0 0 3"/>
<geom type="plane" size="1 1 0.01" rgba="0.9 0.9 0.9 1"/>
<body name="target_block" pos="0.3 0 0.02">
<geom type="box" size="0.03 0.03 0.02" rgba="1 0 0 1"/>
<freejoint/>
</body>
<include file="robot.xml"/>
</worldbody>
<actuator>
<motor joint="shoulder" ctrlrange="-3.14 3.14" ctrllimited="true"/>
<motor joint="elbow" ctrlrange="-2.5 2.5" ctrllimited="true"/>
</actuator>
</mujoco>
这里面有几个关键点:
- <option>——仿真参数。timestep=0.002表示每步2毫秒。重力默认是-9.81沿Z轴。
- <asset>——资源文件。网格、纹理、材质都放这里。
- <freejoint/>——自由关节。让物体可以自由移动和旋转,适合抓取目标。
- <include>——引入外部模型文件。这样可以把机器人和场景分开管理。
- <actuator>——执行器。定义每个关节用什么方式驱动。motor是位置/速度模式,后面我们会讲torque模式。
我的个人习惯:
把模型文件和场景文件分开。机器人本体放一个XML,场景布局放另一个。这样换场景时不用改机器人模型,调试起来快很多。
知识体系总览
下面这张图,把本章的核心逻辑串起来了:
避坑指南
最后,分享几个我实战中遇到的坑:
我曾经犯过的错:
- 坐标系搞混——MuJoCo默认Z轴向上,但很多URDF模型是Y轴向上。导入时记得用
<compiler angle="radian" coordinate="world">指定。 - timestep设太大——0.005以上就容易发散。我一般用0.002,精度和速度平衡得不错。
- 忘记加freejoint——物体放在场景里不动,抓不起来。检查一下有没有
<freejoint/>。 - 网格文件路径——meshdir是相对路径,相对于XML文件所在目录。我习惯把所有mesh放一个文件夹,省得找。
好了,环境搭好了,模型写好了。下一步就是让机器人动起来。但那是后面章节的事。先把今天的内容消化掉,动手写一个自己的机械臂模型,跑起来看看效果。