仿真环境搭建: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仿真环境搭建知识体系 MuJoCo物理引擎 物理引擎特性 软接触 · 高效计算 安装与配置 conda · mujoco-py · 环境变量 XML建模 body · joint · geom 场景文件解析 option · asset · actuator 核心逻辑 理解物理引擎特性 → 正确安装配置 → 掌握XML建模语法 → 解析完整场景文件 四个环节环环相扣,缺一不可

避坑指南

最后,分享几个我实战中遇到的坑:

我曾经犯过的错:

  • 坐标系搞混——MuJoCo默认Z轴向上,但很多URDF模型是Y轴向上。导入时记得用<compiler angle="radian" coordinate="world">指定。
  • timestep设太大——0.005以上就容易发散。我一般用0.002,精度和速度平衡得不错。
  • 忘记加freejoint——物体放在场景里不动,抓不起来。检查一下有没有<freejoint/>。
  • 网格文件路径——meshdir是相对路径,相对于XML文件所在目录。我习惯把所有mesh放一个文件夹,省得找。

好了,环境搭好了,模型写好了。下一步就是让机器人动起来。但那是后面章节的事。先把今天的内容消化掉,动手写一个自己的机械臂模型,跑起来看看效果。