把 Q1 从折叠收储的状态叫起来,让它走到你面前。

对用户来说,这是一句话。对机器人来说,这句话要穿过五层:技能层决定“做什么”,智能层理解“在哪、是谁”,运动控制层决定“怎么动”,通信层把指令送到板子上,本体层把电流变成力矩。

这篇文章不按模块清单罗列。指令本身是从上往下走的,但我们要理解它为什么能走通,得反过来,从最底下的身体开始,一层层往上:先看身体能做什么,再看两块板怎么把指令送到关节,然后是小脑、大脑,最后回到技能。每到一个新层,先问它解决了下面哪一层解决不了的问题,再看它对外暴露什么,最后指出开发者最容易卡住的地方。

一、先看全景:五层,各管一段

在这里插入图片描述

图是从上往下画的,因为指令确实从上往下走;正文从 1 往上讲,因为每一层都踩在下一层上。这张图里有两组关系值得先记住。

从上往下,是指令的翻译过程。 技能层把“走过来”拆成若干阶段;智能层判断人在哪、要不要跟进;运动控制层把“向前 0.3 米每秒”翻译成关节目标;通信层把目标送到运控板;本体层把目标变成电流。每往下一层,语义少一分,实时性高一分。

从下往上,是状态的反馈过程。 关节状态、电池电量、触摸事件、相机画面,沿着相反的方向往上走,最后变成智能层的一次判断、技能层的一次状态迁移。上层之所以能“知道”机器人现在怎么样,靠的是下面四层把状态一层层交上来。

还有一条边界:第 3 层是分水岭。 第 1、2 层主要由固件和系统守住,开发者一般只动配置;第 3 层能一直管到关节,第 4、5 层负责任务,是二次开发主要发生的地方。启元的开发者模式,本质上就是在控制这条边界开放到什么程度。

接下来按 1 到 5 走。走到第 3 层会停得久一点,因为“谁能让电机转”这件事,主要在这一层决定。

二、身体层:参数会变成上层的常量

先看本体。Q1 身高 88 厘米,整机约 16 公斤,22 个自由度,电池 215 Wh,标称续航 3 小时,日常最大移动速度 1 m/s。自由度拆开是腿 6×2、臂 4×2、腰 2(来源:Q1 参数页)。

在这里插入图片描述

关节是 QDD 准直驱。官方给的数字是:齿圈电机与外壳一体化,粉末冶金减重到 260 克,2.5 mm 中空走线,峰值扭矩密度 85 N·m/kg。翻译成开发者能用的信息,是三个词:体积小、能反驱、力控响应快。前两个决定它能不能塞进 88 厘米的身体,第三个决定它能不能做柔顺交互。

这些本体参数不是产品页上的装饰。它们会变成上层代码里的常量。我把官方 URDF q1_v3 拉下来算了一遍:26 个 link、25 个 joint,其中 22 个是可动关节;所有 <mass> 加起来是 16.917 kg;髋、膝关节的 effort 上限是 36 N·m,踝关节是 22 N·m。后来在速度控制那一层看到“线速度绝对值要么是 0,要么不低于 0.2 m/s”,就不难理解:低于硬件的低速下限,关节会抖,整机会为了平衡触发代偿。

所以身体层虽然改不动,却必须读懂。它决定了上层哪些参数是“物理上做不到”,哪些只是“软件上没开放”。

三、通信与计算层:两块板,一条总线

指令离开本体层往上,先碰到的是计算与通信。

启元用的是双板:运控板 10.1.1.100,大脑板 10.1.1.101,开发机建议设成 10.1.1.99,三者在 10.1.1.0/24 网段(来源:SDK《快速入门与集成指南》第 2.1.2 节)。接上网线、打开开发者模式之后,ros2 node list 能同时看到两块板上的节点,比如 hal_camera、hal_audio、mc_ros2_node。

在这里插入图片描述

为什么要分两块板?因为实时性和算力是两种资源。运控板要在一个固定的控制周期里算完关节目标,晚一毫秒都不行;大脑板要跑视觉、语音、Agent,算得久一点没关系,但不能抖到控制环里。分成两块板,中间用网线隔开,实时控制就不会被推理任务拖累。

两块板之间跑的是 ROS2 Humble,RMW 固定为 rmw_fastrtps_cpp(FastDDS)。你可以把 DDS 理解成一条总线:节点往总线上发消息,谁关心谁订阅,不需要知道对方在哪块板、哪个进程。这套机制的好处是解耦,代价是调优。

调优的参数写在 SDK 自带的 fastdds_profiles.xml 里:UDP 收发缓冲 20 MB(20971520),开发机内核参数要跟着抬到 24 MB(25165824),否则 ros2 topic echo 会时通时不通。配置文件里还有一个 200 MB 的共享内存段,但默认 participant 只启用 UDP,同机多进程部署时才去开 SHM。

QoS 也不是一套参数打天下:

数据频率QoS
速度话题 /aima/mc/locomotion/velocity50–100 HzReliable / Volatile / Depth=10
上肢关节 /aima/mc/custom/joint/command100 HzBest Effort / Volatile / Depth=10
关节指令 /aima/hal/joint/command1000 HzBest Effort / Volatile / Depth=10
关节状态 /aima/hal/joint/state500 HzBest Effort / Volatile / Depth=10
电池 /aima/hal/bms/state1 HzBest Effort / Volatile / Depth=10

速度用 Reliable,因为它是“持续意图”,丢一帧可能意味着机器人突然收不到“继续走”;关节指令 1 kHz 用 Best Effort,因为下一帧马上补上,重传反而制造延迟。这个取舍在别的机器人栈里也能看到,但启元把它写进了默认配置,开发者不用自己猜。

通信层不产生动作,但它决定动作能不能及时、完整地到达。调不好,上层逻辑再对,表现出来也是“时好时坏”。

四、运动控制层:三个问题,三道关

指令到了运控板,MC 要连续回答三个问题:现在允许动吗?谁有权动?动多快?

4.1 现在允许动吗:状态机

Q1 的运动状态不是一组可以随便跳的枚举,而是一张有向图。官方 McAction.msg 给 Q1 列了 22 个动作常量,示例代码 mc_action_switcher.py 里的 _ACTION_RULES 把其中 18 个状态写成了 55 条有向边。
在这里插入图片描述

为什么要有这张图?因为人形机器人的动作有物理先后。趴着不能直接走,必须先撑起来;躺着不能直接跑,必须先经过收储或站立。状态机把这些物理约束写成规则,不合法的跳转直接拒绝,返回 -1001 到 -1006 这样的错误码。

回到我们的指令。Q1 现在在 STORE_DEFAULT(折叠收储),目标是 BIPED_WALK_RUN(走跑)。官方规划器给的是两步:

STORE_DEFAULT -> BIPED_WALK_RUN: 2 次 SetMcAction
  1. BIPED_GROUND_POSE
  2. STAND_UP -> BIPED_WALK_RUN(auto)

第一步 BIPED_GROUND_POSE 把身体撑起来,第二步 STAND_UP 执行站起。站起完成后,MC 会自动把状态更新到走跑,不需要再发第三次。这个“自动落到走跑”的规则写在官方代码的 _AUTOMATIC_NEXT_ACTIONS 里,注释的原话是 “STAND_UP is the Q1 recovery action: its runner updates MC to BIPED_WALK_RUN”。

这里有两个新手最容易踩的点。第一,两次 SetMcAction 的间隔不能小于 500 ms,否则返回 -10001。第二,GetMcAction 的 status 在切换期间是 200(TRANSITION),切完才是 100(RUNNING);必须轮询到 100 再发下一条,否则两条轨迹会叠在一起。

我把这张图抽成 JSON,穷举了所有有序状态对:306 对里 209 对可达,97 对不可达;可达的里面,89 对一步,105 对两步,15 对三步;最长的一条最短路是 8 步。不可达不代表机器人坏了,只代表“这两个状态之间没有合法的物理路径”,比如从躺姿直接到走跑,规划器就会拒绝。

4.2 谁有权动:输入源仲裁

状态对了,只说明“这个动作合法”。谁有权发这个动作,是另一套机制。

机器人可能同时被手机 App、语音 Agent、实体遥控器、开发者程序控制。启元的做法是给每个控制源注册一个名字、一个优先级、一个超时时间,由 MC 仲裁出当前唯一的主控。

优先级分五档(来源:《接口说明》2.1.1.4):

档位优先级信源
系统级100–80急停、安全保护、rc、pnc、interaction
高级79–60实体遥控器、App 手动遥控、vr、app_proxy
中级59–40语音指令、手势交互
低级39–20SDK 二次开发、PNC 仿真
备用19–0研发调试、低压测试、离线仿真

规则有三条:高优先级直接抢占;同优先级先入为主,当前主控不停,后来者进不来;每个源有 1000 ms 看门狗,主控断了,按优先级降序找下一个还活着的候补。

要发速度,开发者得先调 SetMcInputSource,用 1001(ADD)注册一个源,填 name、priority、timeout。注册成功后源默认就是 Enable,直接参与仲裁。之后每条速度消息的 source 字段必须和注册名完全一致,否则帧会被静默丢弃。

官方速度示例里,这个注册写成了 priority = 80,和 rc、pnc、interaction 同级;而文档建议 SDK 二次开发用 39–20。这不是小差别:同优先级是先入为主,如果 SDK 先占锁,遥控器后发,反而抢不进来,要等 SDK 停发 1000 ms 超时后才能接管。我在自己的会话里把优先级改成 30,行为就回到文档描述的样子。示例代码大概率是为了让新手脚本“一跑就动”,但抄进产品之前,这一行值得改。

在这里插入图片描述

这张时序图是我按文档规则写的离线仲裁器跑出来的:App(p=60)先占锁;SDK 节点(p=30)在 300 ms 开始发,一直被挡;App 在 650 ms 停发,看门狗到 1660 ms 才把锁释放给 SDK;遥控器(p=80)2000 ms 介入,立刻抢占;2400 ms 遥控器停发,3360 ms 超时,锁又回到 SDK;5160 ms SDK 也停了,没有候补,运动停止。

两个细节值得记住。第一,控制权是内存态。 SetMcInputSource 的增删改只写 RAM,不回刷 YAML;机器人重启,动态注册的源就没了。所以程序启动时先 DELETE 再 ADD,清掉上次异常退出留下的同名源。第二,GetCurrentInputSource 返回的是锁的归属,不代表指令流还活着。 主控超时后、还没有新抢占者之前,接口依然返回旧主控的名字;要自己记最后一帧的时间。

4.3 动多快:速度话题

状态放行、控制权到手,最后才是发速度。

/aima/mc/locomotion/velocity 的字段不多:forward_velocity、lateral_velocity、angular_velocity、pitch_velocity、level,外加 header 和 source。约束有三条:

  • 频率 50–100 Hz。官方示例用 50 Hz 定时器发,低于这个频率,1000 ms 看门狗会把控制权摘走;高于这个频率没有额外收益。
  • 速度有死区。线速度绝对值要么是 0,要么不低于 0.2 m/s;角速度同理,不低于 0.2 rad/s。文档的解释是,低于硬件最低速度运行时,关节容易抖动、异响,整机为了维持平衡还会触发代偿,反而更危险。
  • source 必须和注册名一致。名字写错、大小写不一致、用了内置名(rc、pnc、interaction、vr、app_proxy),帧会被静默丢弃,或者和内置源互相冲刷。

三个问题都答完,MC 才会把速度指令翻译成关节目标。到这里,“走过来”这件事在运动控制层就算完成了。

五、智能层:看人、听话、决定下一步

运动控制层回答“怎么动”,但“人去哪了”“该跟谁走”“用户刚才说了什么”不归它管。

这一层的输入是传感器。Q1 配的是单目摄像头、环形麦克风、触摸传感器和 8 核处理器;T1 Pro 多了 Orin Nano、5 组 ToF、双目摄像头和两颗鱼眼(来源:Q1 参数页、T1 参数页)。输出则是几类接口:语音识别结果走 /aima/agent/asr_result 话题,播报走 PlayTts 服务,表情走 PlayEmotion,触摸走 /aima/hal/touch/state,相机可以抓单帧(CaptureJpegImage,全链路 100–500 ms,建议 1 fps)或者拉 RTSP 流(端口 2554)。

启元在发布会上公布了这一层的模型命名:PrimeMotion 负责柔顺安全的小脑运控,PrimeGo 负责多模态感知与跟随,PrimeVista 负责多模态交互,PrimeMind 是面向家庭场景的家务基座模型;此外还有一个基于 Harness 架构的机器人 Agent(来源:新华网)。

需要区分的是:这些是模型和产品的命名,不是 SDK 里的接口名。SDK 给开发者的是“原始数据 + 服务”,不是“模型内部”。比如你可以订阅 ASR 结果、调用 TTS、抓一帧图,但 SDK 没有开放“目标检测”或“导航”的现成接口。官方 carry-clothes 技能在 selfProvided 里写得很直白:目标检测和视觉伺服要开发者自己补,默认的 HeuristicDetector 只是占位,不产生结果。

这是理解启元架构的一个关键:智能层是产品能力,运动层是开放能力。 产品页上“看得见、听得懂、会跟随”是前者;SDK 文档里“话题、服务、关节”是后者。两者之间有交集,但不能画等号。

六、技能层:把动作串成任务

用户不会直接调用 Agent,他们装的是技能。

启元的技能包格式叫 RPK,入口是 manifest.json。官方 carry-clothes(把衣服拿到洗衣机旁)是一个很好的样本,因为它的清单把“技能”这件事拆得很清楚:

  • runtime:Python ≥ 3.10,入口 main:run,启动前 source ROS2 和 SDK 环境;
  • capabilities:逐条声明要用的接口,比如 SetMcInputSource 的参数写死 name=carry_clothes_skill, priority=30, timeout=1000,速度话题写死 minRateHz=50, maxForward=0.35, maxYaw=0.5;
  • selfProvided:明确写出 SDK 不提供、要开发者自建的能力,这里是目标检测和视觉伺服;
  • safety:最大前进速度 0.35 m/s、电量底线 20%(搬运中 25%)、关节限位钳制、动作间隔 500 ms、异常中止时平滑回正、必须设备端确认;
  • stages:把任务拆成 10 个带超时的阶段,从响应指令、切直立、走到用户跟前,到抬臂、等待接衣、合臂、找洗衣机、前往、放下、完成。

这份清单最值得借鉴的地方,是它把“不能做什么”写在了安装之前。selfProvided 里说得很清楚:SDK 不提供目标检测,不提供 SLAM/导航;safety.notes 里还有三句:SDK 无夹爪接口,接物是双臂合拢托住;SDK 无 ASR 接口,用户确认改用头部触摸事件;上肢位姿是推算值,上机前必须示教标定。这里的“无 ASR 接口”指的是技能运行时没有可调用的识别服务;/aima/agent/asr_result 话题仍然存在,只是技能拿不到一次同步的识别结果。

技能层不直接控制电机。它做的是任务编排:什么时候切状态、什么时候发速度、什么时候播报、什么条件下中止。真正的控制仍然落在第 3 层。把这两层分开,技能才能在没有真机的时候用 Mock 跑通,也才能被审查、被打包、被分发。

七、工具链与开发模式:从读到跑

五层讲完,回到开发者这一侧。

启元给的入口是 PrimeConsole:一个跨 macOS、Windows、Linux 的桌面工作台,能连机器人看视频和日志、控运动、跑仿真、验证技能。它本质上是一组标准 DDS 节点加图形界面;不装它,用 ros2 topic list、rqt、rosbag 也能做同样的事,只是要自己配环境。

仿真侧有官方 URDF、MuJoCo XML、Gazebo launch,还有三套 Docker 工具链:ARM 原生编译(Orin / RK)、x86 交叉编译 ARM、x86 原生编译。SDK 里直接带了 OpenCV 4.13.0 和 Ruckig 轨迹库的源码,版本钉死,减少“本地能跑、板上编译不过”的环境漂移。

开发者模式分五层:运行模式(Standard / Develop)、开发方式(API / ROS2)、开发层级(Basic / Advanced)、领域设置、能力配置。当前版本 API 方式没开放,默认只支持 ROS2;领域设置和能力配置暂时合并,只生效“运动控制—低层运控开发”。

Basic 和 Advanced 的差别不是权限多一点少一点,而是接管方式不同。Basic 保持原厂业务和安全策略,外部指令并发注入;Advanced 允许关闭特定官方模块,拿传感器裸流和底层运控的独占权。代价也写在文档里:开启开发者功能后不再享受维保服务,切模式要重新上下电。

如果只想跑通一次“走过来”,最短路径是五步:ros2 node list 确认节点;GetMcAction 确认当前状态;SetMcInputSource 注册一个 p=30 的源;50 Hz 发 0.2 m/s 走两秒;零速度加 DELETE 收尾。真机先架空或平躺,手边留急停。

八、三处对不上的地方

读到这儿,你已经能把一条指令从头走到尾。但真上手时,还有三处文档、枚举和示例代码对不上的地方,值得提前知道。

第一处:官方速度示例把 SDK 源注册成了 p=80。 mc_locomotion_velocity.py 第 149–151 行是 name = "node"、priority = 80、timeout = 1000,第 16 行注释也写 “priority 80”;而《接口说明》把“SDK 二次开发信号”放在 39–20。按示例抄,SDK 和遥控器同级;按文档写,SDK 应该低一档。我倾向前者只是为了让新手脚本“一跑就动”,产品里应该改成 30。

第二处:文档的状态图画了 LYING_DEFAULT → STAND_UP,代码的表里没有。 《接口说明》2.1.1.1 的 mermaid 图里,躺姿有一条指向站起的虚线;但 Python 和 C++ 两份 mc_action_switcher 的 _ACTION_RULES 里,LYING_DEFAULT 只有 STORE_DEFAULT 一条出边,而 STORE_DEFAULT 又不能当中间态。结果就是:官方规划器认为“躺姿 → 走跑”不可达。这不等于底层状态机拒绝这条切换,但意味着你按示例的规划器办事,会在这一步停住。

第三处:状态图里有三个状态,枚举表里没有。 BIPED_WALK_RUN_DEFAULT、BIPED_GROUND_POSE、BIPED_RECORD_UPPER 出现在 _ACTION_RULES 里,McAction.msg 的 Q1 枚举段却没有给它们数值。它们只能通过 action_desc 字符串下发,不能靠 action.value。反过来,MIMIC、MIMIC_LINKCRAFT、MIMIC_OPENSOURCE 等 7 个枚举又不在图里。

三处差异指向同一件事:这套 SDK 的权威顺序是“代码 > 枚举 > 文档图”。文档适合建立框架,真正下发之前,用 ros2 service call 和 GetMcAction 各验一次,比抄示例稳。

九、边界与取舍

最后说说这套架构的边界。

开放的层次是扎实的:ROS2 Humble、FastDDS、标准 Topic/Service、URDF、MuJoCo、Docker,没有私有格式;接口给到了关节力矩、刚度、电池状态字这一级;状态机、输入源、速度话题都有明确的错误码和超时。对做研究和做技能的人来说,这是一套能落地的开放平台。

没开放的部分也要说清楚:没有导航、SLAM、语义地图;没有夹爪接口;没有现成的目标检测;语音只给识别结果,不给唤醒词和对话模型;API 方式还没上线;Advanced 模式会失去维保。社区里已经有人问 T1 Pro 的声纹、人脸识别结果从哪读,问 Orin Nano 是 4GB 还是 8GB,问音频通道为什么和文档对不上——这些问题恰好说明,参数表之外,开发者还需要一份“哪些有接口、哪些是黑盒、哪些要自己补”的边界文档。

这套架构适合谁?适合愿意按 ROS2 的方式做事、需要关节级控制、或者想把技能做成可分发包的人。它不适合想“装个 App 就能让机器人干活”的人——那部分工作在技能层和智能层,SDK 只给到原料。

十、再回到那条指令

现在再看“走过来”这句话。

技能层把它拆成阶段,智能层判断人在哪,运动控制层确认“现在允许走、我有权走、走多快”,通信层把速度送到运控板,本体层把电流变成力矩。走的过程中,关节状态、电池、触摸事件又沿着相反的方向回到上层,变成下一次判断。五层各管一段,缺一层,这句话就落不了地。

如果你想自己走一遍:SDK、URDF、桌面端 PrimeConsole、技能仓库都在启元机器人开发者社区(dev.primebot.com),AtomGit 组织是 atomgit.com/primebot。本文用到的状态图数据、仲裁模型、Mock 会话和 URDF 提取脚本整理在 primebot-control-path 仓库,按 README 的顺序跑,就能复现文中的输出。社区里已经有 Q1 仿真挥手、T1 搬运、语音叫车这些例子,遇到问题先去论坛搜,比从头啃文档快。


参考资料

  1. 启元 Q1 产品页:https://www.primebot.com/q1.html
  2. 启元 Q1 参数页:https://www.primebot.com/product_spec4.html
  3. 启元 T1 参数页:https://www.primebot.com/product_spec1.html
  4. 启元机器人开发者社区下载页:https://dev.primebot.com/download
  5. 启元 Q1 SDK v1.0.0.0:《接口说明》《PrimeBot SDK 快速入门与集成指南》,2026-10-10
  6. 启元 Q1 URDF v1.0.0(q1_v3),2026-09-24
  7. 官方技能 carry-clothes 的 manifest.json:https://atomgit.com/primebot/carry-clothes
  8. 新华网:《启元个人机器人正式发售,AI模型、生态布局同步公布》,2026-09-22:https://www.news.cn/tech/20260922/770e10d4acdb48ed865eee514b26e06d/c.html

AtomGitx启元机器人具身智能原创内容征文活动#

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐