十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MuJoCo中Cassie双足机器人仿真库的部署、控制与强化学习实践

MuJoCo中Cassie双足机器人仿真库的部署、控制与强化学习实践 简介面向机器人控制与仿真研究者的Cassie双足机器人MuJoCo仿真库资源基于Agility Robotics官方开源仓库整理专用于多关节接触动力学建模、行走与平衡控制算法验证。压缩包共62个文件、约1.47MB以XML模型描述、STL网格、C/Python控制脚本及静态库为核心覆盖模型定义、状态观测、接触参数配置、传感器仿真等关键环节并包含噪声地形、深度图像、斜坡及有无重力等变体场景便于开展多工况对比实验。已有388人学习浏览。借助完整的模型文件与示例代码可快速搭建Cassie仿真环境在此基础上进行PD/逆动力学控制、强化学习等策略开发也可用于动态稳定性分析、故障模拟与硬件在环验证。压缩包内目录划分清晰集成Makefile和跨语言接口适合具备基础MuJoCo或机器人学知识的研究者与学生直接上手是深入探索双足机器人仿真与控制的高价值参考资料。1. MuJoCo 里的 Cassie 仿真包为什么这份 zip 值得单独下载Cassie 在双足控制里是一个很特殊的基准执行器少、腿的拓扑结构清楚但控制难度不低关键是它带了很多工程细节——跟骨处的被动自由度、脚踝的弹簧刚度、还有髋关节的复杂内收外展布局。MuJoCo 官方模型仓库mujoco_menagerie把 Agility Robotics 的 Cassie 维护成agility_cassie子目录但很多工程现场拿到的是一份Cassie机器人仿真库___下载.zip。这个包装里绝大多数情况不是可安装的 Python 库而是一组 MJCF 描述文件加网格资源入口通常是scene.xml。真正让工程师停在第一步的往往是解包之后资源路径错位、MuJoCo 版本对不上或者分不清qpos前面那 7 个量是浮动基座而不是关节角。这篇文章按“取包 → 装环境 → 加载 → 控制 → 接训练”的顺序走一遍把索引、PD 参数和接触模型这几个容易翻车的位置单独拎出来。适合正在做双足强化学习或步态研究的工程师也适合刚拿到 Cassie 仿真资源但被文件结构卡住的人。2. 先拿到 Cassie 仿真库Git 拉取、zip 解包与目录核对2.1 用 mujoco_menagerie 官方仓库拉取完整模型最省事的来源是 MuJoCo 的官方模型仓库它按机器人厂商和机型分目录Cassie 就在agility_cassie下面。浅克隆一份就够用不需要拉全部历史cd ~/workspace git clone --depth 1 https://github.com/google-deepmind/mujoco_menagerie.git cd mujoco_menagerie/agility_cassie ls -l--depth 1只抓最新快照体积小得多。目录里你会看到scene.xml、robot.xml、robot_simple.xml以及assets这类资源目录。scene.xml是给仿真直接用的入口场景里面通常已经include了机器人本体并摆好了地面robot.xml适合被别的场景引用robot_simple.xml是简化网格版本渲染负载更低但物理属性和力矩特性基本一致。这里强调一个原则MJCF 里的mesh、texture引用全部是相对路径只要动了文件夹的层级关系加载就会失败。所以拿到任何一份 Cassie 仿真库 zip第一件事不是打开代码而是保持解包后的目录结构原样。2.2 从 zip 解包并保持资源路径完整如果你拿到的确实是一个 zip 压缩包常见做法是先在临时目录解包再整体移动到工作区cd ~/workspace wget https://github.com/google-deepmind/mujoco_menagerie/archive/refs/heads/main.zip unzip main.zip mv mujoco_menagerie-main/agility_cassie cassie cd cassiemain.zip解压后第一层目录名通常带着分支名比如mujoco_menagerie-main里面才是各机器人子目录。把agility_cassie整个移到cassie之后不要再把assets子目录单独拆出去。我见过不少报错是这么来的只把scene.xml拷到新目录运行时 XML 解析成功紧接着抛LoadError说某个.stl找不到。2.3 目录结构核对scene.xml、robot.xml 与资源文件夹拿到 zip 后先对一遍文件清单避免后来把时间浪费在“模型起不来”上。文件/目录作用缺失时的典型表现scene.xml仿真实体入口包含地面与机器人没有文件仿真无从开始robot.xml机器人本体定义可被其他场景include单独加载时没有地面robot_simple.xml简化网格的轻量版本不影响物理只影响渲染速度assets/网格文件、纹理图片LoadError: file not foundREADME 或 LICENSE模型来源与使用约束影响合规与后续分发这个 zip 的本质是“模型资产”不是“Python 库”。把它与mujocopip 包的关系说清楚mujoco提供物理引擎和 Python 绑定Cassie 模型由这些 XML 加网格描述。两者缺一个都跑不起来但它们是独立的。2.4 用一行命令确认模型可加载解压完成后先做一个最小验证再进入仿真python -c import mujoco; mmujoco.MjModel.from_xml_path(scene.xml); print(joints, m.njnt, actuators, m.nu, geoms, m.ngeom)正常情况会打印出 Cassie 的全部关节数、执行器数和几何体数。值得留意的是nu也就是电机数量Cassie 每条腿 5 个驱动器两条腿共 10 路nq则要看模型版本里有没有把跟骨的被动自由度单独建成一个 hinge所以不要靠“17 还是 19”这种硬编码记忆。正确习惯是打印后自己核对后续所有控制代码都从actuator_trnid和jnt_qposadr动态取索引而不是手写数字。提示data.qpos前 7 个量永远是浮动基座的位移加四元数后面才是关节角。任何“从第 8 个开始每两个取一个”的写法都是在给自己埋雷。3. 搭建 MuJoCo 并加载 Cassie 场景Ubuntu 22.04、Windows 11 与 ROS 2 部署3.1 最小安装一条 pip 命令与两个系统依赖MuJoCo 从 2.x 后期开始官方 Python 包直接携带预编译的libmujoco.so和mujoco.dll不再需要自己编译源码。安装步骤压缩到最小就是Ubuntu 22.04sudo apt update sudo apt install -y libgl1-mesa-glx libegl1-mesa libglfw3-dev pip install --upgrade mujocoWindows 11pip install --upgrade mujoco在 Ubuntu 上装libgl1-mesa-glx是为了补libGL.so.1这是很多人在容器里碰到的第一个坑libegl1-mesa负责 EGL 无头渲染libglfw3-dev在你要用本地窗口时才会用到。如果你的系统已经升级到 Ubuntu 24.04libgl1-mesa-glx的包名改成了libgl1命令对应换一下即可。3.2 用 launch_passive 把 Cassie 摆上窗口加载 Cassie 并打开实时仿真窗口最直接的是 MuJoCo 自带的 passive viewerimport mujoco import mujoco.viewer model mujoco.MjModel.from_xml_path(scene.xml) data mujoco.MjData(model) with mujoco.viewer.launch_passive(modelmodel, datadata) as viewer: while viewer.is_running(): mujoco.mj_step(model, data) viewer.sync()launch_passive用上下文管理器创建窗口退出with块后自动释放资源。viewer.sync()负责把仿真画面同步到界面但如果机器性能跟不上画面会变慢物理照常推进。这里有一个容易误判的点mj_step只推进一个物理步默认时间步长在 2ms 量级也就是 500Hz如果控制代码写在mj_step之前的同一个循环里控制频率也等于物理频率。3.3 无头服务器渲染MUJOCO_GL 三档与 Renderer很多训练任务跑在无显示器服务器上launch_passive会直接失败。这时用环境变量切换渲染后端MUJOCO_GLegl python cassie_demo.py MUJOCO_GLglfw python cassie_demo.pyglfw需要窗口系统适合本机调试egl是无头服务器最常见的选项依赖libegl1-mesa。旧版本里的osmesa属于软渲染速度慢新版本里也已逐渐边缘化。无头环境下需要保存图像用mujoco.Renderer做离屏渲染renderer mujoco.Renderer(model, height480, width640) mujoco.mj_forward(model, data) frame renderer.render() # frame.shape (480, 640, 3)mujoco.mj_forward先做一次正向运动学保证相机能看到正确的骨骼姿态如果直接拿刚mj_resetData的data去渲染也不会报错但画出来的可能是初始堆叠状态。3.4 ROS 2 接入把 Cassie 的关节状态发布成 JointState在 ROS 2 里接 MuJoCo常见做法不是去找一个“MuJoCo 官方 ROS 包”而是在仿真进程里开一个rclpy节点把关节状态转成标准消息发出去。下面是最小的发布节点import rclpy from rclpy.node import Node from sensor_msgs.msg import JointState import mujoco class CassieJointState(Node): def __init__(self): super().__init__(cassie_joint_state) self.pub self.create_publisher(JointState, /joint_states, 10) self.timer self.create_timer(0.01, self.tick) self.model mujoco.MjModel.from_xml_path(scene.xml) self.data mujoco.MjData(self.model) self.jid self.model.actuator_trnid[:, 0].copy() self.qidx self.model.jnt_qposadr[self.jid] def tick(self): mujoco.mj_step(self.model, self.data) msg JointState() msg.header.stamp self.get_clock().now().to_msg() msg.name [ mujoco.mj_id2name(self.model, mujoco.mjtObj.mjOBJ_JOINT, j) for j in self.jid ] msg.position self.data.qpos[self.qidx].astype(float).tolist() self.pub.publish(msg)这里 100Hz 的定时器控制发布频率MuJoCo 的物理步依然按自身频率推进如果希望仿真严格同步到 ROS 定时器就把mj_step放到回调里并调整opt.timestep。actuator_trnid[:, 0]取每个执行器对应的关节编号jnt_qposadr再映射到qpos下标这样发布出去的关节顺序和名称严格对应不会出现左右腿接反的问题。3.5 安装时常见报错对照表平台报错片段常见处理Ubuntu 22.04libGL.so.1: cannot open shared object file执行sudo apt install libgl1-mesa-glxUbuntu 22.04glfw: error: X11 display unavailable设为MUJOCO_GLegl或在有桌面环境时运行Ubuntu 22.04GLEW ... not found安装libglew-dev后重启终端Windows 11Failed to load dynamic library: mujoco.dll安装 Visual C 2015-2022 运行库路径避免中文Windows 11mujoco.viewer黑屏更新的显卡驱动或设置MUJOCO_GLegl任意平台ModuleNotFoundError: mujoco检查 Python 版本 3.8-3.12pip install --upgrade pip后重装4. 控制 Cassie关节索引、PD 参数与触地调参4.1 先看懂 10 个执行器与 qpos 的关系写控制器之前先把执行器到关节的映射打印出来。这一步能避免后面大量“机器人在空中乱转”的问题。import numpy as np import mujoco model mujoco.MjModel.from_xml_path(scene.xml) data mujoco.MjData(model) act_jid model.actuator_trnid[:, 0].copy() qidx model.jnt_qposadr[act_jid] didx model.jnt_dofadr[act_jid] for i in range(model.nu): name mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_JOINT, act_jid[i]) print(f{i:2d} - {name:16s} qpos[{qidx[i]}] qvel[{didx[i]}])actuator_trnid第一列保存的是默认transmissionjoint下的关节 IDjnt_qposadr给出该关节在qpos里的下标jnt_dofadr对应qvel里的速度下标。Cassie 的nu是 10也就是每条腿 5 个电机髋偏航、髋滚转、髋俯仰、膝、踝。注意跟骨的被动自由度通常不在执行器列表里它由关节刚度和阻尼维持这正是 Cassie 落地时看起来有缓冲的原因。4.2 一个可直接落地的站立 PD 环掌握索引之后写一个位置 PD 控制器让 Cassie 站稳。这里假设data.qpos的初始值就是合理的站立构型kp np.array([120., 120., 120., 200., 150.] * 2) kd np.array([8., 8., 8., 16., 12.] * 2) q_des data.qpos.copy() dq_des np.zeros(model.nv) ctrl_min model.actuator_ctrlrange[:, 0] ctrl_max model.actuator_ctrlrange[:, 1] for step in range(1000): tau kp * (q_des[qidx] - data.qpos[qidx]) kd * (dq_des[didx] - data.qvel[didx]) data.ctrl[:] np.clip(tau, ctrl_min, ctrl_max) mujoco.mj_step(model, data)kp单位是 N·m/radkd是 N·m·s/rad。膝盖承受的动载荷比髋大所以第二组200和16给膝和踝。np.clip这行必须保留直接把超限力矩写进ctrl多步之后数值积分会不稳定表现是机器人突然“炸开”。4.3 armature 的坑为什么加了控制器仍然抖如果 Cassie 在高频抖动先用这行确认电机惯量print(armature:, model.dof_armature[didx])armature是附加在自由度上的等效转子惯量。MuJoCo 里关节默认armature0并不代表“无惯量”而是关节本身的集中惯量只由body质量分布决定对双足这种关节负载变化大的系统PD 控制器很容易把转速推得过高。出现高频振铃时优先考虑增加armature而不是放大kd。MJCF 里通常在joint上直接写armature0.05这一类值改完后重新from_xml_path加载即可。4.4 触地瞬间摩擦、solref 与 condim 的调整Cassie 站立和走路时脚底接触是主要力源。改接触参数要放在模型加载之后、mj_step之前for name in (foot_left, foot_right): gid mujoco.mj_name2id(model, mujoco.mjtGeom.mjOBJ_GEOM, name) if gid 0: model.geom_friction[gid] [1.0, 0.005, 0.0001] model.geom_solref[gid] [0.004, 1.0] model.geom_condim[gid] 3geom_friction三个值分别对应滑动、滚动、扭转摩擦双足机器人脚底滑动摩擦给 0.8~1.2 比较常见。solref的第一个值是接触响应时间常数0.004 配合 2ms 的timestep大约是两步收敛既有弹性又不会弹起。condim3表示使用摩擦锥模型比 4 更稳定如果你发现 Cassie 走着走着侧向滑出去先查的就是这里。参数推荐起点说明opt.timestep0.002触地冲击大时降到 0.001但实时性会下降geom_condim3摩擦锥模型最稳定geom_friction[0]0.8~1.2脚底滑动摩擦solref[0.004, 1.0]接触响应时间常数4.5 索引写错的表现free joint 和 joint 混在一起很多人第一次控制 Cassie会直接把qpos的某个区间当成关节角。问题是qpos前 7 个量是浮动基座的位置和四元数不在任何执行器的控制范围内。正确的做法永远是从actuator_trnid拿关节 ID从jnt_qposadr拿qpos下标从jnt_dofadr拿速度下标。这三张表打印出来贴在手边比任何“第 8 个到第 17 个”的硬编码都可靠。5. 把 Cassie 仿真库接到训练与验证链路上5.1 做成最小 RL 训练环境的骨架Cassie 最常见的用途还是没有腿的步态策略训练。最小环境框架可以这么写class CassieEnv: def __init__(self, xml_pathscene.xml): self.model mujoco.MjModel.from_xml_path(xml_path) self.data mujoco.MjData(self.model) self.qidx self.model.jnt_qposadr[self.model.actuator_trnid[:, 0]] self.didx self.model.jnt_dofadr[self.model.actuator_trnid[:, 0]] def reset(self): mujoco.mj_resetData(self.model, self.data) return self._obs() def step(self, action): ctrl_max self.model.actuator_ctrlrange[:, 1] self.data.ctrl[:] np.clip(action, -1.0, 1.0) * ctrl_max mujoco.mj_step(self.model, self.data) done self.data.body(pelvis).xpos[2] 0.5 return self._obs(), self._reward(), done, {} def _obs(self): return np.concatenate([ self.data.qpos[self.qidx], self.data.qvel[self.didx], ])这个骨架没有奖励函数和终止逻辑以外的任何修饰但训练跑起来需要记住两点第一done不能只看仿真时间要加骨盆高度阈值否则机器人摔倒后继续累积无效样本第二观测里必须包含足够的速度信息单靠qpos学出来的策略会有明显延迟。action先做归一化再乘ctrlrange是 RL 策略输出和 MuJoCo 执行器单位之间的标准换算方式。5.2 一个快速验证技巧用正弦扰动检查相位滞后在把完整训练搬上来之前可以用单关节正弦跟踪检验控制环的动态jid mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, hip_pitch_left) act_id int(np.where(act_jid jid)[0][0]) qj model.jnt_qposadr[jid] dj model.jnt_dofadr[jid] freq, amp 1.0, 0.05 while data.time 10.0: ref amp * np.sin(2 * np.pi * freq * data.time) data.ctrl[act_id] 150.0 * (ref - data.qpos[qj]) - 12.0 * data.qvel[dj] mujoco.mj_step(model, data)如果data.qpos[qj]跟踪正弦的相位滞后明显超过理论预期说明kd给得不够或者物理步长太大。这个测试只动一个关节能快速定位是哪组参数的问题而不必每次跑完整条腿。5.3 回灌真机前关节符号与坐标约定先对齐MuJoCo 里的关节正方向由 MJCF 的axis决定真机 SDK 里的正方向未必一致。常见做法不是直接比较关节角度而是先对比data.xpos的脚踝和骨盆位置与真机运动学计算结果如果位置一致而角度不一致就是符号约定问题。另一点是在模型里选一个脚底site用site_xpos当作触地参考这样训练阶段的接触判断和真机足底压力计能对得上。把这几张索引表和符号约定整理清楚Cassie 仿真库才算真正接到你的工作流里。本文还有配套的精品资源点击获取
返回列表