从零学习 MuJoCo(1):从零跑通第一个物理仿真
从零学习 MuJoCo1从零跑通第一个物理仿真作者晓柒 · 从零学习 MuJoCo 系列想象把一个小球放在离地面 1 米高的地方然后松手。它会在重力作用下落到地面。在 MuJoCo 中复现这个过程需要做两件事先说明“小球和地面是什么样”再让程序一步一步计算“小球接下来会在哪里”。这篇教程就从这个例子开始。你将创建两个文件运行一个小球下落的仿真并通过修改几个数字弄清楚模型、运动计算和画面显示是怎样配合的。图 1先搭建场景再计算运动最后观察结果。1. MuJoCo 怎样让小球动起来MuJoCo 是一个物理仿真引擎可以把它理解成负责计算物体运动的程序。以小球为例程序知道这些信息小球的半径和质量小球此刻的位置和速度重力的大小与方向地面在哪里。有了这些信息MuJoCo 就能计算一小段时间之后小球的位置和速度。反复计算小球的运动过程就产生了。**Viewer 是显示仿真画面的窗口。**本例使用的launch_passive模式由 Python 程序控制仿真程序算一步再把结果同步到 Viewer。窗口负责显示循环负责推动小球运动。图 2mj_step()计算下一步viewer.sync()将结果同步到画面。先分清“设计图”和“当前状态”运行 MuJoCo 时经常会看到两个名字MjModel和MjData。可以用同一个小球来区分它们对象可以怎样理解小球例子MjModel场景的“设计图”保存模型结构和参数小球半径 0.1 米、质量 1 千克重力沿 z 轴向下MjData仿真的“状态记录表”保存当前状态和计算结果现在过去了多久、小球在哪里、正以多快的速度运动小球下落时半径和质量通常不变位置和速度却一直在变化。因此程序可以一直使用同一份model不断更新data。这两个名字暂时不用死记。后面的代码里model对应设计图data对应当前状态。“前进一步”是前进多久本例把每一步的时间设为0.01秒optiontimestep0.01/timestep就是“每次计算让仿真时间前进多久”。因此调用 1 次 mj_step() → 仿真前进 0.01 秒 调用 10 次 mj_step() → 仿真前进 0.1 秒 调用 100 次 mj_step() → 仿真前进约 1 秒这里说的是模拟世界过去的时间。电脑实际花了多久还取决于计算速度。后面的 Python 程序会用sleep适当等待让画面速度大致接近真实时间。2. 用 XML 搭一个“小球地面”的场景XML 是一种用标签组织内容的文本格式。MuJoCo 使用的这套模型描述格式叫MJCF。在这篇教程中XML 文件负责写清楚“场景里有什么”。先新建一个文件夹把下面的内容保存为其中的hello.xmlmujocomodelhello_mujoco!-- 每步前进 0.01 秒重力沿 z 轴向下 --optiontimestep0.01gravity0 0 -9.81/worldbody!-- 地面 --geomnamegroundtypeplanesize2 2 0.1/!-- 小球球心初始高度为 1 米 --bodynameballpos0 0 1freejoint/geomnameball_geomtypespheresize0.1mass1//body/worldbody/mujoco这段代码可以从外到内读mujoco包住整个模型worldbody里放地面和小球小球的body里面再写它的运动方式和形状。下面把其中几个关键部分拆开说明。worldbody物体放在哪里worldbody是整个场景的世界根节点可以把它理解成放置物体的最外层。本例中它里面有两样东西worldbody ├── 地面 ground └── 小球 ball地面直接放在worldbody下固定在世界中。小球则单独放进一个body方便定义它的位置和运动方式。body和geom物体与形状先看这两行bodynameballpos0 0 1geomtypespheresize0.1mass1//body可以把它们读成一句话建立一个名为 ball 的刚体把它放在(0, 0, 1)给它一个半径为 0.1 米、质量为 1 千克的球形几何体。“刚体”就是运动时形状不发生变化的物体。本例把小球看作刚体不考虑它被压扁或拉长。这里的分工是body表示这个刚体用于组织物体的位置和层级关系。geom描述它的形状还可以参与碰撞与质量计算。一个body也可以有多个geom。例如用几个简单形状拼成一件复杂物体它们仍然属于同一个刚体。pos0 0 1中的三个数字依次对应 x、y、z。本例把 z 轴作为高度方向所以最后一个数字1表示球心在地面上方 1 米。freejoint小球为什么可以下落完整模型比上面的两行示例多了一行freejoint/它为小球添加一个自由关节让小球可以在空间中自由移动和转动。这里的“自由度”指独立的运动方式。小球可以沿 x、y、z 三个方向移动也可以绕三个方向转动共6 个运动自由度。如果删掉freejoint/这个小球就固定在世界中的初始位置。即使重力还在它也不会自由下落。所以想让物体动起来需要同时考虑它受到什么力以及模型允许它怎样运动。gravity重力朝哪边gravity0 0 -9.81这三个数依次表示 x、y、z 方向的重力加速度。前两个为 0最后一个为负数表示重力沿 z 轴负方向也就是本例的“向下”。-9.81的单位是米每二次方秒常写成m/s²。先记住它控制重力大小与方向后面可以直接改数字观察效果。3. 用 Python 让场景运行起来XML 已经说明了场景内容。接下来需要一个 Python 程序完成三件事加载场景、计算运动、显示结果。在hello.xml旁边新建hello.py文件结构如下你的项目文件夹/ ├── hello.xml └── hello.py把下面的代码保存到hello.pyimporttimefrompathlibimportPathimportmujocoimportmujoco.viewer# 在当前 Python 文件旁边寻找 hello.xmlxml_pathPath(__file__).parent/hello.xml# 加载模型“设计图”再创建一份“状态记录表”modelmujoco.MjModel.from_xml_path(str(xml_path))datamujoco.MjData(model)# 打开窗口只要窗口没关闭就不断计算和显示withmujoco.viewer.launch_passive(model,data)asviewer:whileviewer.is_running():step_starttime.perf_counter()# 计算下一个仿真时刻的状态mujoco.mj_step(model,data)# 把最新状态同步到窗口viewer.sync()# 如果本次计算用时不足 0.01 秒就等待剩余时间remainingmodel.opt.timestep-(time.perf_counter()-step_start)ifremaining0:time.sleep(remaining)加载模型读入“设计图”modelmujoco.MjModel.from_xml_path(str(xml_path))这一行读取hello.xml把里面的小球、地面、重力等描述转换成 MuJoCo 可以使用的模型。xml_path是 XML 文件的位置。前面的Path(__file__).parent表示当前 Python 文件所在的文件夹因此代码会到hello.py旁边寻找hello.xml。创建数据记录“现在是什么样”datamujoco.MjData(model)模型加载好后需要一份data来保存当前状态。仿真开始时它包含初始位置和速度随着程序运行它会不断更新。循环计算一步接着一步循环里最关键的是这两行mujoco.mj_step(model,data)viewer.sync()第一行让 MuJoCo 根据当前状态计算下一步并更新data第二行让 Viewer 显示更新后的结果。本例的timestep是0.01秒所以每调用一次mj_step()仿真就向前走0.01秒。while viewer.is_running()会反复执行它们直到窗口关闭。最后的sleep用于控制观看速度如果电脑很快算完了一步就稍等一下再继续。它只能让速度大致接近真实时间不能保证精确计时。4. 安装 MuJoCo 并运行程序以下操作使用Windows PowerShell并假设电脑已经安装 Python。先在保存hello.xml和hello.py的文件夹中打开终端。第一步创建项目环境python-m venv.venv.\.venv\Scripts\Activate.ps1第一行创建一个名为.venv的虚拟环境第二行进入这个环境。可以把它理解成项目自己的“工具箱”MuJoCo 等依赖包安装在这里便于与其他项目分开管理。第二步安装并检查python-m pip install mujoco python-cimport mujoco; print(mujoco.__version__)如果第二条命令能输出版本号就说明当前环境能够找到 MuJoCo。第三步运行python hello.pyViewer 打开后小球应从空中下落并与地面发生碰撞。具体的弹跳幅度与停稳过程会受到接触参数等因素影响先观察下落和接触地面的过程。图 3本例程序的运行画面。小球的位置由程序持续计算再同步到 Viewer。除了看画面也可以看数字想知道程序里记录的小球高度可以在循环中的mj_step()后面加一行打印mujoco.mj_step(model,data)print(ftime{data.time:.2f}s, ball_z{data.qpos[2]:.3f}m)viewer.sync()其中data.time是仿真已经过去的时间。在这个只有一个自由关节的小球模型中data.qpos的前 3 个数是小球的位置data.qpos[2]就是球心高度。运行后应看到时间不断增加球心高度从约 1 米开始下降。这里打印的是球心高度所以球接触地面时数值也不会直接变成 0。确认后可删掉打印语句避免终端一直刷屏。5. 改几个数字看看结果是否符合预期每次只改一个地方保存 XML 后重新运行程序。完成一项实验后恢复原值再试下一项这样更容易判断是哪项修改影响了运动。实验一让小球从更高处落下把pos0 0 1改成pos0 0 2最后一个数字是高度所以小球的起点从 1 米变成了 2 米。它需要下落更长的距离碰到地面的时间也会更晚。实验二让重力变小把gravity0 0 -9.81改成gravity0 0 -2重力仍然向下但数值的绝对值变小。小球下落时速度增加得更慢看起来也会落得更慢。实验三让重力朝另一个方向把重力改成gravity9.81 0 0现在重力沿 x 轴正方向小球会朝这个方向运动。这个实验说明场景中的“向下”由重力向量决定MuJoCo 会按照你写下的三个数字计算。实验四把小球固定住恢复原来的重力再删除freejoint/重新运行后小球会固定在初始位置。这个实验把“受到重力”和“允许移动”区分开来自由关节提供了移动的可能重力才会让小球自由下落。6. 遇到报错时先检查什么No module named mujoco这表示运行程序的 Python 环境找不到 MuJoCo。电脑上可能有多个 Python或者编辑器选用了另一个环境。在运行hello.py的同一个终端执行python-m pip install mujoco python-cimport mujoco; print(mujoco.__version__)如果使用 VS Code还需要打开命令面板选择Python: Select Interpreter再选中项目里的.venv\Scripts\python.exe。安装包和运行脚本要使用同一个 Python 环境。找不到hello.xml检查hello.xml是否放在hello.py旁边以及文件名是否与程序中的写法一致。还要留意文件是否误存成了hello.xml.txt。窗口打开了小球却不动先检查三个地方循环里有没有mj_step(model, data)后面有没有viewer.sync()小球的 XML 中有没有freejoint/。这三处分别关系到计算运动、更新显示和允许运动。7. 记住这几个对应关系名称本例中的作用XML / MJCF写下场景规则小球、地面、重力等MjModel加载后的模型“设计图”MjData小球当前的状态记录worldbody整个场景的最外层body定义一个刚体geom描述刚体的形状并参与碰撞等计算freejoint让小球可以自由移动和转动timestep每次计算让仿真时间前进多久mj_step()计算下一步的状态viewer.sync()把最新状态同步到画面回到最初的小球XML 说明它是什么样、从哪里出发Python 加载模型并创建状态mj_step()计算它接下来会在哪里Viewer 把结果显示出来。这条流程同样适用于后续的机械臂和机器人仿真。下一篇将用固定方块、自由方块和单摆进一步解释body、geom和joint如何配合。参考资料MuJoCo 官方概览模型、数据与仿真步进MuJoCo Python 文档安装与 ViewerMuJoCo XML 参考body、geom 与 freejoint

相关新闻

Claude-Mem 实战:给 AI 编码助手装上长期记忆,TaoToken 统一 Key 接入

Claude-Mem 实战:给 AI 编码助手装上长期记忆,TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 9:21:35 阅读更多 →
2025年AI编程工具盘点与汇总(独立IDE篇):用TaoToken统一Key接入20+款IDE的配置清单

2025年AI编程工具盘点与汇总(独立IDE篇):用TaoToken统一Key接入20+款IDE的配置清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 9:21:35 阅读更多 →
从零搭建销售Agent:线索生成、客户画像与转化预测实战指南

从零搭建销售Agent:线索生成、客户画像与转化预测实战指南

做销售增长的同学应该都有同一种体感:线索不够分、画像不清晰、转化靠手感。月初给销售分一批名单,里面有大量“看起来像客户”但实际踩不动的企微空号,销售打过去聊两句就觉得不匹配,名单浪费率长期在六成以上。后来我干脆自己动…

2026/10/17 9:20:35 阅读更多 →

最新新闻

Vim+GCC+库文件:打通Linux开发工具链的完整闭环

Vim+GCC+库文件:打通Linux开发工具链的完整闭环

我见过太多刚切到 Linux 的开发者,第一周就被劝退。倒不是 C 语言难,而是卡在了工作流上:在终端里不知道怎么快速改代码,写完程序不知道怎么编译,编译完了遇到各种链接报错又一头雾水。说白了,就是 Vim 操作…

2026/10/17 16:14:27 阅读更多 →
大漠插件7.2213 + Python:DmHelper注册调用与桌面自动化避坑指南

大漠插件7.2213 + Python:DmHelper注册调用与桌面自动化避坑指南

简介:面向大漠插件7.2213的Python注册示例包,内含作者自制的DmHelper脚本,用于演示如何通过Python语言调用大漠插件接口,完成注册、激活以及基本功能调用。大漠插件在界面自动化、软件测试、网页数据抓取等日常开发场景中应用广泛…

2026/10/17 16:14:27 阅读更多 →
5 分钟上手 North-Micro-Vision-Instruct-bf16:在 Apple Silicon 上本地跑通图像描述的完整指南

5 分钟上手 North-Micro-Vision-Instruct-bf16:在 Apple Silicon 上本地跑通图像描述的完整指南

【免费下载链接】North-Micro-Vision-Instruct-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/North-Micro-Vision-Instruct-bf16 点击查看 免费下载 North-Micro-Vision-Instruct-bf16 是一个专为 Apple Silicon(M 系列芯片&#x…

2026/10/17 16:14:27 阅读更多 →
鸿蒙下Flutter测试框架反射装载适配与规模化分发

鸿蒙下Flutter测试框架反射装载适配与规模化分发

test_reflective_loader 这个名字,很多 Flutter 开发者可能只在跑测试时瞥见过一眼,但真正能说清它底层在干嘛的人不多。这次我们团队在把一套针对鸿蒙 HarmonyOS 的 Flutter 测试基建落地时,在这个组件上扎扎实实折腾了几周,踩了…

2026/10/17 16:14:27 阅读更多 →
XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索

XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索

XERJ零配置自动索引教程:一条命令让PDF、CSV、SQLite和日志全部可搜索 【免费下载链接】xerj XERJ is the new way for AI to search data. Its autoindex capability activates agents to know your data without the token waste of grep and sed. One command in…

2026/10/17 16:14:27 阅读更多 →
Qt飞机大战飞机类设计:QGraphicsScene、状态机与碰撞检测

Qt飞机大战飞机类设计:QGraphicsScene、状态机与碰撞检测

1. 飞机类挂在 QGraphics 场景里,是我试出来的最优解1.1 一开始我也用过 QWidget 硬拼飞机大战在 Qt 里算一个很经典的练手项目,但大多数教程会把重点放在"怎么把窗口搭出来""怎么加背景图",真到自己动手写飞机类的时候&…

2026/10/17 16:13:26 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →