MuJoCo 使用方式与典型场景
四、使用方式与典型场景
示例一:最小可运行的仿真循环
import mujoco
import numpy as np
model = mujoco.MjModel.from_xml_path("arm2dof.xml")
data = mujoco.MjData(model)
mujoco.mj_resetData(model, data)
model.opt.timestep = 0.002
for i in range(2000):
# 简单正弦力矩激励
data.ctrl[0] = 0.8 * np.sin(data.time * 2.0)
data.ctrl[1] = 0.4 * np.cos(data.time * 2.0)
mujoco.mj_step(model, data)
if i % 500 == 0:
print(f"t={data.time:.3f} qpos={np.round(data.qpos, 4)}")
三个关键函数:mj_step 推进一步、mj_forward 只做前向计算不推进时间、mj_resetData 复位状态。调试时常先用 mj_forward 确认模型几何关系对不对,再进仿真循环。
示例二:一个两自由度机械臂的 MJCF 模型
<mujoco model="arm2dof">
<option timestep="0.002" integrator="implicitfast" solver="Newton"/>
<default>
<joint damping="0.1" armature="0.01"/>
<geom friction="1.0 0.005 0.0001" solref="0.02 1"/>
</default>
<worldbody>
<geom name="floor" type="plane" size="2 2 0.1"/>
<body name="link1" pos="0 0 0.5">
<joint name="j1" type="hinge" axis="0 1 0"/>
<geom name="g1" type="capsule" fromto="0 0 0 0 0 -0.3" size="0.03"/>
<body name="link2" pos="0 0 -0.3">
<joint name="j2" type="hinge" axis="0 1 0"/>
<geom name="g2" type="capsule" fromto="0 0 0 0 0 -0.25" size="0.025"/>
<site name="tip" pos="0 0 -0.25" size="0.01"/>
</body>
</body>
</worldbody>
<actuator>
<motor joint="j1" ctrlrange="-1 1"/>
<motor joint="j2" ctrlrange="-1 1"/>
</actuator>
<sensor>
<jointpos joint="j1" name="j1_pos"/>
<jointvel joint="j1" name="j1_vel"/>
<sitepos site="tip" name="tip_pos"/>
</sensor>
</mujoco>
注意 armature 与 damping 放在 <default> 里会被所有关节继承。这两个参数对仿真稳定性影响极大,真机上它们对应的是电机转子惯量和减速器摩擦,不能随手设成零。
示例三:用标准接口跑训练循环
import gymnasium as gym
# 环境 id 的后缀随版本变化,以 gymnasium 文档为准
env = gym.make("HalfCheetah-v4")
obs, info = env.reset(seed=0)
total_reward = 0.0
for _ in range(1000):
action = env.action_space.sample() # 占位策略
obs, reward, terminated, truncated, info = env.step(action)
total_reward += reward
if terminated or truncated:
obs, info = env.reset()
print("return:", total_reward)
env.close()
把 action 换成策略网络的输出,外面套上任意 RL 库的训练循环即可。要在 GPU 上并行上千个环境,改用 MJX 的接口。
示例四:可视化与无头调试
import mujoco
import mujoco.viewer
import time
model = mujoco.MjModel.from_xml_path("arm2dof.xml")
data = mujoco.MjData(model)
with mujoco.viewer.launch_passive(model, data) as viewer:
while viewer.is_running():
mujoco.mj_step(model, data)
viewer.sync()
time.sleep(model.opt.timestep)
在无头服务器上跑不了可视化,替代办法是把关键状态写进日志,或用离线渲染出图后再回放检查。
适合与不适合
- 适合:接触丰富的操作任务、强化学习算法研究与训练、控制器与轨迹优化的快速验证、需要求导的可微仿真。
- 不适合:需要与 ROS2 深度集成的系统级仿真(虽有第三方桥接,但不如 Gazebo 原生)、需要照片级渲染的合成数据、大规模室外场景与多机器人分布式仿真。

