本节摘要:MuJoCo(Multi-Joint dynamics with Contact)是一个以「快速、精确、稳定地求解多关节刚体接触动力学」为核心使命的物理仿真引擎。它的一切设计——软接触模型、凸优化求解、确定性步进——都围绕这一使命展开,也因此划出了清晰的能力边界:接触与控制仿真是它的主场,视觉真实感与超大场景是它的边界之外。理解这套哲学,是后面所有选型与调参判断的底层依据。
阅读完本节,你应当能够:
先看一个几乎所有机器人工程师都撞过的反例。同一个双足机器人模型,分别放进两款引擎里站立:一款是某游戏引擎的物理组件,一款是 MuJoCo。游戏引擎里,机器人站得笔直,画面流畅,看起来一切正常;把地面摩擦调低一点,它开始缓慢滑移,再调低,直接抖动穿模,脚陷进地板半个模型。MuJoCo 里,同一台机器人站着时脚底与地面之间其实存在微小的、可计算的穿透量,接触力随穿透深度平滑变化;摩擦调低后,它以符合库仑摩擦定律的方式打滑,增大脚底接触面积或调整踝关节力矩就能重新站稳。
两款引擎都没有「错」,差别在于它们对接触这件事的根本态度。游戏引擎问的是「这一帧两个物体碰没碰到,别穿模就行」,接触是离散事件的触发器;MuJoCo 问的是「这一步两个物体之间的接触力应该是多少,才能让整体运动符合动力学方程」,接触是连续的、可微分的力学约束。前者为渲染帧率服务,后者为控制算法服务。你要训练一个学走路的策略,或者验证一个踝关节控制器,只有后一种答案可用——因为你的算法需要从「力为什么这么反」反推「参数该怎么改」,而事件触发的接触给不出这层因果。
这就是本节要立起来的判断标准:MuJoCo 是把物理定律当作一等公民来计算的引擎,评价它的尺度不是「像不像」,而是「对不对、稳不稳、快不快」。
MuJoCo 全称 Multi-Joint dynamics with Contact,三个组成部分恰好对应它的三块核心能力。
Multi-Joint(多关节):引擎的原生建模单位是铰接刚体系统——连杆通过关节连接成树状结构,整体用广义坐标描述。它不是把每个物体当作孤立的点来碰撞,而是把整台机器当作一个耦合的动力学系统来求解。机械臂、四足、灵巧手这类多连杆机构是它的原生对象。
dynamics(动力学):每一步仿真求解的是完整的运动方程——给定当前状态和执行器力矩,计算加速度、更新速度与位置。质量矩阵、科氏力、重力补偿这些项都在方程里显式出现。这意味着你可以直接问引擎「维持当前姿态需要多大关节力矩」这类逆动力学问题,这是做模型预测控制和力控的前提。
Contact(接触):这是 MuJoCo 押注最重的一块。真实机器人与环境的交互几乎都通过接触发生——脚踩地、手指抓杯子、臂尖撞桌面——而接触恰恰是动力学里最难的部分:不光滑、不连续、多点多向耦合。MuJoCo 用一套软约束加凸优化的方案把它做扎实,代价和收益在下一小节展开。

三根支柱不是并列的口号,而是层层依赖:运动学树决定了动力学的组织方式,动力学的求解质量决定了接触力的可信度。所以后面章节的顺序也是按这个依赖排的——第二章讲怎么把运动学树建出来,第三章讲动力学和接触怎么算。
传统硬碰撞的思路是「不许穿透」:检测到相交就把物体弹开或投影回去。这在视觉上够用,但在动力学上有两个致命伤:接触力不连续(碰上的一瞬间力从零跳到很大),以及穿透深度没有物理含义(穿进去多少全看算法心情)。控制算法需要的是力随状态平滑变化的模型,否则梯度不存在、优化不收敛。
MuJoCo 的做法是允许微小穿透,让接触力成为穿透深度与速度的平滑函数。物体像被一层看不见的弹簧阻尼垫托着:穿透越深、逼近越快,法向支撑力越大;参数调得硬,垫子就薄,行为逼近刚性;调得软,垫子就厚,接触变得柔顺。一个直观的对照:
| 维度 | 硬碰撞思路 | MuJoCo 软接触思路 |
|---|---|---|
| 穿透量 | 视为错误,立即修正 | 允许微小值,力随其平滑变化 |
| 接触力 | 事件式跳变 | 连续函数,可求导 |
| 数值行为 | 高频抖动的常见来源 | 稳定,可复现 |
| 对 RL 的意义 | 奖励信号毛刺多 | 梯度与奖励平滑,训练稳 |
要跑通第一个模型感受这件事,十行以内的 Python 就够。下面这段代码加载一个内置模型、仿真一百步并打印高度——先不展开语法细节,只看它有多短:
import mujoco import numpy as np model = mujoco.MjModel.from_xml_path("humanoid.xml") # 模型描述,第二章的主角 data = mujoco.MjData(model) # 状态容器,第三章的主角 for i in range(100): mujoco.mj_step(model, data) # 一步 = 完整的动力学求解 height = data.qpos[2] # 根 body 的高度分量 print(f"100 步后躯干高度: {height:.3f} m")
同样的循环在硬碰撞引擎里能不能跑通要碰运气——初始姿态差一点,第一步就可能弹飞。MuJoCo 的确定性(同输入必同输出)让这个循环在任何机器上跑出完全一样的数字,这是科研可复现性的地基,也是它成为大量论文默认环境的原因之一。
主张一个工具好,必须连同它的边界一起讲,否则就是推销。
第一类,以视觉真实感为卖点的项目。 MuJoCo 自带渲染是为「让算法看见场景」服务的离屏渲染,够做视觉 RL,但光照、材质、后处理的丰富度与游戏引擎不在一个量级。要做仿真宣传片或数字孪生可视化,把 MuJoCo 的物理输出喂给专业渲染管线,或直接换游戏引擎。
第二类,需要精细软体、布料、流体外观的场景。 MuJoCo 有流体阻力近似与柔体方案,但定位是「对动力学有影响的简化建模」,不是影视级的布料解算。柔体主角的项目请找专门的解算器。
第三类,单帧精度可以牺牲、但场景规模巨大的环境仿真。 万人级别的城市人流、上万物体的仓库调度,这类问题的瓶颈在碰撞对数量而非求解精度,专门的大规模并行方案更合适(第七章会讲 MuJoCo 自己的 GPU 答案 MJX,它恰恰是把精度优势带进并行世界的一次反向扩张)。
下一节把镜头从内核拉到外围:这个引擎十几年攒下的生态里,有哪些现成的模型、环境和工具能直接搬进你的项目。