在 Ubuntu ARM64 上运行 Q1 V3.0 MuJoCo 模型:加载、步进和单执行器响应

我手里没有 Q1 实机,所以这次不碰真机控制,先确认一件具体的事:启元公开的 Q1 V3.0 MuJoCo 模型,能不能在我的 M1 Mac 虚拟出来的 Ubuntu ARM64 环境里加载、往前算几步,并且对一个执行器输入产生可观察的状态变化?

答案是能。加载和步进跑通了,单执行器开环输入也有响应,EGL 离屏渲染能生成 640×480 的像素缓冲区。不过跑通一个模型文件,离"机器人能走"还差着控制器、任务验证和真机对照,这几件事需要分开看。

图 1:从固定官方模型版本到无界面步进、开环输入对照和 EGL 渲染;最右侧的边界是这次没有覆盖的真机和步态验证。

先选对模型文件

官网下载页把模型资源标为 Q1 V3.0 URDF v1.0.0,AtomGit 的 q1-urdf 仓库里同时有 URDF、网格、MuJoCo XML 和 ROS 启动文件。我把仓库固定在提交 562b764a18613d459140ed9b255fa30434e346ef,后续复现时至少能保证拿到同一版模型文件。

这个仓库的 ROS 包仍采用 ROS 1 catkin,部分 launch 文件引用的旧模型路径也与仓库当前文件不一致。我的开发环境是 ROS 2 Humble,因此没有把那些 launch 文件当成现成的 Humble 仿真教程,而是直接用 MuJoCo Python API 加载 xml/q1_v3_mc.xml。这个 XML 含有 motor actuator,适合继续检查输入和状态;另外两个 XML 没有 actuator,不能拿来做同一个输入实验。

在 Ubuntu 客体里先克隆固定版本:

bash 复制代码
mkdir -p ~/q1-mujoco
cd ~/q1-mujoco
git clone https://atomgit.com/primebot/q1-urdf.git official-q1-urdf
cd official-q1-urdf
git checkout 562b764a18613d459140ed9b255fa30434e346ef

模型文件会引用仓库里的 meshes/ 目录,所以保留完整仓库结构,不要只把 XML 单独拷出来。检查目标文件和网格目录:

bash 复制代码
test -f xml/q1_v3_mc.xml && test -d meshes \
  && echo 'Model XML and meshes are present'

图 2:虚拟环境里安装到的 MuJoCo Python 包为 3.16.0。文章里的运行结果都对应这个版本。

先无界面加载,再走一步

虚拟机是 Ubuntu 22.04.5 LTS、aarch64,Python 3.10;MuJoCo 装在 ~/q1-mujoco-venv,没有污染系统 Python。安装可以按下面的方式重做:

bash 复制代码
sudo apt update
sudo apt install -y python3-venv
python3 -m venv ~/q1-mujoco-venv
source ~/q1-mujoco-venv/bin/activate
python3 -m pip install mujoco==3.16.0

这里 apt 安装需要 sudo 权限。先不打开 Viewer,只用项目脚本检查 XML 是否能被解析、仿真状态是不是有限数值。下面命令在项目根目录执行:

bash 复制代码
source ~/q1-mujoco-venv/bin/activate
cd ~/q1-mujoco/q1-mujoco-verify
python3 scripts/model_step_check.py \
  --model ../official-q1-urdf/xml/q1_v3_mc.xml --steps 1000

输出是 nq=29、nv=28,22 个执行器、49 个 sensor、60 维 sensor data;仿真步长是 0.001 s。1000 步对应模型时间 1 秒,最后 qpos/qvel finite 为 True。nq 和 nv 分别是广义位置与速度状态的维度,不是执行器数或关节数,不能拿它们互相替代。

图 3:q1_v3_mc.xml 在无界面模式下完成 1000 步,状态保持有限。这里的 1 秒是仿真时间,不是机器运行耗时。

从 actuator 名称找到对应关节

接下来我把 actuator 和 joint 名称逐个列出来,再选一个关节做输入实验。这样至少不会把数组下标猜成关节名。MuJoCo 模型里的 actuator 有自己的控制范围,截图中的髋部执行器是 [-36.0, 36.0],踝部的范围则是 [-22.0, 22.0]。这是 XML 定义的 ctrlrange,不是我测出来的真机扭矩或电流上限。

映射由项目脚本 scripts/list_actuators.py 从加载后的模型读取,完整输出 22 项:

bash 复制代码
python3 scripts/list_actuators.py \
  --model ../official-q1-urdf/xml/q1_v3_mc.xml

我选中的是 motor_left_hip_pitch,它映射到 left_hip_pitch_joint。把名字解析出来后,才能从 jnt_qposadr 和 jnt_dofadr 找到这个关节在 qpos、qvel 数组里的位置;这一步比直接写死某个数组下标更稳妥。

图 4:模型列出的 22 个 actuator、对应 joint 和 ctrlrange。映射关系来自加载后的 MuJoCo 模型,不是硬件标定表。

单执行器开环输入对照

为了区分"模型会动"和"输入改变状态",我各跑了一次 200 步:一组把执行器输入保持为 0,另一组保持为 1.0。每组都从新建的 MjData(model) 初始状态开始,模型时间都是 0.200 秒。输入 1.0 落在该 actuator 的 ctrlrange 内。可复现脚本会检查输入是否在范围里,并分别报告两组末值和末值差:

bash 复制代码
python3 scripts/single_actuator_response.py \
  --actuator motor_left_hip_pitch --control 1.0 --steps 200

测得的 left_hip_pitch_joint 状态如下:

条件 末端 qpos 末端 qvel
零输入 0.073236 1.090543
控制输入 1.0 0.450102 5.585105

零输入组的位置也发生了变化,因此我不把 0.450102 说成执行器单独造成的位移。原始终端最后一行把 0.450102 标成"位置变化差",但按前面的数值看,它是输入组从初始 qpos=0 到末端 qpos=0.450102 的变化;两组末端 qpos 真正相差 0.376866。我在随文项目的脚本里把"输入组自身变化"和"两个末值之差"分别输出。这个小差别会影响结果该怎么解释。

更准确的结论是:在这份模型和相同初始状态下,恒定输入 1.0 与零输入两次开环运行产生了不同的末端状态。脚本并没有位置目标、反馈控制器或多个关节配合,200 步结果也不能代表站立或行走能力。

图 5:零输入和输入 1.0 的运行结果。qpos、qvel 是 MuJoCo 模型状态值;这里没有把它们换算成实机测量值。

EGL 能渲染,不等于 Viewer 已经验证

加载和步进都过了之后,我才处理离屏渲染。最初 import mujoco 在加载 EGL 时失败,报错指向 PyOpenGL 的 EGL 平台对象为空;单独设置 MUJOCO_GL=egl 和 PYOPENGL_PLATFORM=egl 仍没有解决。继续查动态库时,find_library 找不到 EGL、GL、GLX。装好系统图形运行库后,三个库都能被客体系统找到。

Ubuntu 客体中运行 apt 需要 sudo 权限。若检查仍找不到 EGL/GL 动态库,可安装运行库后重新开一个终端检查:

bash 复制代码
sudo apt update
sudo apt install -y libegl1 libegl-mesa0 libgl1 libglx0 libgl1-mesa-dri

图 6:libEGL.so.1、libGL.so.1 和 libGLX.so.0 现在能从 ARM64 客体系统中解析到。这个检查帮助我把问题定位到系统图形运行库,而不是模型 XML。

之后我用 EGL 创建 mujoco.Renderer,调用 update_scene() 和 render(),并在 finally 中显式 renderer.close()。项目脚本 scripts/render_egl.py 可以直接执行:

bash 复制代码
export MUJOCO_GL=egl
export PYOPENGL_PLATFORM=egl
python3 scripts/render_egl.py \
  --model ../official-q1-urdf/xml/q1_v3_mc.xml

终端仍然出现了 pci id ... driver (null) 的 EGL warning,但这次渲染返回了 640×480 的像素缓冲区,显式释放后也没有再出现析构 traceback。要说清楚:这一步只证明渲染器生成了像素数据。我没有把缓冲区保存为 PNG,也没有检查一张可视的 Q1 模型渲染图;更没有验证 Parallels 的交互式 3D Viewer。

图 7:MuJoCo 3.16.0 通过 EGL 生成 640×480 缓冲区,并在程序结束前显式释放 renderer。启动时的 driver (null) warning 仍在,但不妨碍这次缓冲区生成。

这次验证到这里

在 M1 Pro 上的 Ubuntu 22.04 ARM64 虚拟机里,我确认了 Q1 V3.0 的 q1_v3_mc.xml 能用 MuJoCo 3.16.0 加载、完成 1000 步步进、列出执行器映射、对一个 actuator 做开环输入对照,并由 EGL 生成离屏像素缓冲区。对于一台没有 Q1 实机的开发环境,这足够作为模型侧的初步检查。

它还不是一个步态仿真教程:没有控制器、没有任务通过条件、没有 Viewer 模型画面,也没有真机数据。启元官方 q1-urdf 中的 ROS 1 启动文件也没有被我改造成 ROS 2 Humble launch。后续若继续做,先把渲染缓冲区保存并检查成图,再单独定义一个有初始条件、控制输入和通过标准的仿真任务;没有对应实机,就把结论留在模型侧。

模型来源:启元 Q1 V3.0 q1-urdf 仓库,本文固定在提交 562b764a18613d459140ed9b255fa30434e346ef。MuJoCo Python API 参考:MuJoCo Python bindings。

可复现脚本整理在 AtomGit 项目 q1-mujoco-verify 中,项目只保留脚本、依赖和复现说明,不包含启元官方模型文件。

更多启元机器人开发资料可访问启元机器人开发者社区。

相关推荐
楚国的小隐士1 小时前
从审核员到监工:AI正在重写评价体系,也重写人的价值
ai·编程·ai编程·哲学·马列主义
AR-26710-1 小时前
Linux Day26——传输层与三次握手
linux·运维
dghongcheng1 小时前
喷涂机器人品牌推荐:六轴 vs 协作机器人怎么选
机器人·喷涂·喷漆设备·自动喷涂线·自动喷涂
隔窗听雨眠2 小时前
PostgreSQL单表从Windows迁移到Linux:差异剖析、方案对比与全流程实战
linux·windows·postgresql
xinruoqianqiu2 小时前
记录Linux
linux
额额额对了2 小时前
嵌入式 Linux 实战:i.MX6ULL 上的 CAN 通信与摄像头采集
linux·运维·服务器
牛马鸡niumasi2 小时前
【Linux】进程替换
linux
俊哥V2 小时前
每日 AI 研究简报 · 2026-10-24
人工智能·ai·1024程序员节
todoitbo3 小时前
Q1 MuJoCo 模型里的 49 项传感器定义与 60 维数据:一次关节和 IMU 输出核验
人工智能·ai·机器人·1024程序员节·启元机器人