启元 Q1 二次开发实战:从 JSON 动作编排到 RPK 仿真验证
没有真机也能做启元 Q1 二次开发:从 JSON 动作剧本到 RPK 仿真验证
本文围绕启元 Q1 完成一个可复现的二次开发项目:不直接把动作顺序写死在控制程序中,而是设计一套 JSON 动作剧本格式,加入白名单、时长和安全复位校验,再构建为 RPK 技能包,最终导入 PrimeConsole 进行本地上肢模拟仿真。
实验边界:本文没有连接实体机器人。文中的命令行结果与 PrimeConsole 画面均来自真实操作。
1. 为什么要给 Q1 增加“动作剧本层”
调用一次预设动作并不困难,真正影响二次开发质量的是:多个动作如何组织、错误配置如何提前发现、技能包能否稳定复现,以及没有真机时能验证到哪一步。
如果把动作 ID、等待时间和执行顺序全部写死在 Python 代码里,每次调整流程都要修改程序。本文换一个思路:把“做什么”放进 JSON,把“是否合法”交给独立校验器,把“如何调用 Q1”留给运行时入口。
整个数据流如下:
scene.json
│
├── 静态校验:动作白名单 / 单步时长 / 总时长 / 安全复位
│
├── 编译输出:skill/cfg/compiled_scene.json
│
├── 自动化测试:正常用例 + 非法动作 + 时长越界
│
└── 确定性打包:q1_action_storyboard.rpk
│
└── PrimeConsole 本地上肢模拟仿真
这个项目不追求复杂算法,而是补齐机器人技能开发中常被忽略的工程链路:配置、校验、失败保护、构建和仿真证据。
2. 实验环境与项目结构
本次真实使用的环境如下:
| 项目 | 实际版本或状态 |
|---|---|
| 操作系统 | Windows,本地开发环境 |
| 离线脚本 | Python 3.14.7 |
| PrimeConsole | 1.0.2 |
| Skill | q1_action_storyboard 1.0.0 |
| 目标模型 | 启元 Q 系列 Q1 |
| 真机连接 | 未连接 |
| 仿真范围 | PrimeConsole 本地上肢动作 |
目录结构如下:
q1-action-storyboard/
├─ scene.json # 动作剧本源文件
├─ storyboard.py # 校验与编译核心
├─ validate_scene.py # 命令行校验入口
├─ dry_run.py # 不依赖 ROS 2 的时间线预演
├─ build.py # 确定性 RPK 打包
├─ tests/
│ ├─ test_storyboard.py
│ └─ fixtures/
│ └─ invalid_unknown_motion.json
├─ skill/
│ ├─ main.py # Q1 ROS 2 运行时入口
│ ├─ README.md
│ └─ cfg/
│ ├─ pkg.yaml
│ └─ compiled_scene.json
└─ dist/
└─ q1_action_storyboard.rpk
这里要区分两个环境:storyboard.py、测试和打包脚本可以在普通 Python 环境执行;skill/main.py 引用了 rclpy 与 aimdk_msgs,真机运行仍需要官方 Q1 SDK、ROS 2 Humble、正确控制模式和安全条件。
3. 用 JSON 描述三步动作剧本
本次剧本包含“招手欢迎—双手比心—恢复默认姿态”三步:
{
"schema_version": 1,
"skill_name": "q1_action_storyboard",
"version": "1.0.0",
"steps": [
{
"name": "招手欢迎",
"action": "beckon",
"motion_id": 3001,
"duration_ms": 2600
},
{
"name": "双手比心",
"action": "make_heart",
"motion_id": 3007,
"duration_ms": 3200
},
{
"name": "恢复默认姿态",
"action": "return_neutral",
"motion_id": 0,
"duration_ms": 1800
}
],
"safety": {
"max_total_duration_ms": 12000,
"require_neutral_end": true,
"stop_on_service_error": true
}
}

图 1 启元 Q1 动作剧本的 JSON 配置。剧本依次执行招手、双手比心和默认姿态复位,并配置总时长与异常停止约束。
动作 ID 不是自行编造的数字。根据启元 Q1 SDK 中 aimdk_msgs/mc/motion/McPresetMotion.msg 的定义,本项目使用的映射为:
| 官方符号 | ID | 本文用途 |
|---|---|---|
Q_BECKON | 3001 | 招手欢迎 |
Q_MAKE_HEART | 3007 | 双手比心 |
DEFAULT_POS | 0 | 恢复默认姿态 |
配置驱动的价值在于:业务人员可以调整动作顺序与时长,而校验规则仍由程序统一执行。JSON 不是直接下发给机器人,而是先经过编译和安全检查。
4. 在动作调用之前建立安全契约
校验器中的核心白名单只包含本项目实际使用的三个动作:
OFFICIAL_Q1_MOTIONS = {
0: "DEFAULT_POS",
3001: "Q_BECKON",
3007: "Q_MAKE_HEART",
}
MIN_STEP_MS = 500
MAX_STEP_MS = 6000
随后逐项检查 motion_id、动作名称和时长,并计算累计时间线:
if motion_id not in OFFICIAL_Q1_MOTIONS:
errors.append(
f"steps[{index}].motion_id={motion_id!r} 不在 Q1 动作白名单"
)
if not isinstance(duration_ms, int) or not MIN_STEP_MS <= duration_ms <= MAX_STEP_MS:
errors.append(
f"steps[{index}].duration_ms 必须在 {MIN_STEP_MS}..{MAX_STEP_MS} ms"
)
最后再执行两项剧本级约束:累计时长不得超过配置上限;启用 require_neutral_end 后,最后一步必须为 motion_id=0。
在项目目录执行:
$env:PYTHONIOENCODING='utf-8'
python .\validate_scene.py
真实运行得到三段连续时间线,总时长为 7600 ms,白名单、时长和安全复位检查均通过。

图 2 动作剧本静态校验结果。三个步骤均通过动作白名单、单步时长和中立姿态结尾检查。
这里的 duration_ms 是剧本的调度等待时间,不等同于机器人控制器内部每个轨迹点的持续时间。真机接入时仍需结合动作完成状态、服务返回值和现场安全策略,不能仅依赖固定 sleep。
5. 把剧本接到 Q1 预设动作服务
Q1 SDK 提供 SetMcPresetMotion 服务,官方接口名称为:
/aimdk_5Fmsgs/srv/SetMcPresetMotion
运行时入口创建 ROS 2 客户端,并把配置中的动作转换为官方预设动作请求:
from aimdk_msgs.srv import SetMcPresetMotion
self.client = self.create_client(
SetMcPresetMotion,
"/aimdk_5Fmsgs/srv/SetMcPresetMotion"
)
request = SetMcPresetMotion.Request()
request.source = "q1_action_storyboard"
request.interrupt = True
if motion_id == 3001:
request.motion.value = 3001 # Q_BECKON
elif motion_id == 3007:
request.motion.value = 3007 # Q_MAKE_HEART
elif motion_id == 0:
request.motion.value = 0 # DEFAULT_POS
else:
return False
interrupt=True 表示新请求允许中断当前动作。它并不意味着可以忽略安全条件:官方接口说明指出,预设动作需要在全身控制模式 BIPED_WHOLE_BODY_CTRL 下调用。本文没有实体 Q1,因此没有执行控制模式切换和真实 ROS 2 服务调用;这里只完成了符合 SDK 接口定义的运行时入口与 PrimeConsole 可识别的技能包。
6. 不只展示成功:用自动化测试验证失败路径
为了避免“能跑一次就算完成”,项目增加了 5 个自动化测试:
- 单步时长越界必须被拒绝;
- 剧本必须以默认姿态结束;
pkg.yaml必须包含正确的技能身份信息;- 未知动作 ID 必须被拒绝;
- 正常剧本应编译为 3 个步骤。
执行命令:
python -m unittest discover -s tests -v

图 3 测试覆盖时长越界、默认姿态结尾、技能包身份、未知动作拦截和正常剧本编译,5 项测试全部通过。
仅有成功截图不能证明保护逻辑真的工作,因此我又准备了一个包含 motion_id=9999 的非法剧本:
python .\validate_scene.py .\tests\fixtures\invalid_unknown_motion.json

图 4 非法动作注入测试。校验器同时识别出未知动作 ID 和缺少默认姿态结尾,并以非零状态退出。
这张失败结果不是程序故障,而是预期行为。它说明错误配置在生成技能包之前就被阻断,没有进入仿真或机器人执行阶段。
7. 构建可重复的 RPK 技能包
RPK 本质上是具有固定目录结构的压缩包。本项目写入以下四个文件:
cfg/compiled_scene.json
cfg/pkg.yaml
main.py
README.md
打包程序还会检查是否遗漏必要文件,以及是否错误地多嵌套了一层 skill/ 目录。为了让相同源码产生相同二进制结果,构建脚本固定了 ZIP 条目的时间戳、权限和文件排序:
for path in sorted(SKILL_DIR.rglob("*")):
arcname = path.relative_to(SKILL_DIR).as_posix()
info = zipfile.ZipInfo(arcname, date_time=(2026, 1, 1, 0, 0, 0))
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o644 << 16
archive.writestr(info, path.read_bytes())
执行:
python .\build.py

图 5 RPK 构建结果。技能包共包含 3 个剧本步骤,文件大小为 2613 bytes,并输出 SHA-256 摘要。
本次产物数据如下:
| 指标 | 结果 |
|---|---|
| 文件 | q1_action_storyboard.rpk |
| 大小 | 2613 bytes |
| SHA-256 | 2e2f9b6968f577d7d92ad5413fe3569138581701ff6caa1656555eee0e96ecb7 |
| 连续两次构建 | 哈希一致 |
固定时间戳的目的不是伪装构建时间,而是排除 ZIP 元数据变化,便于在代码评审、发布和回滚时确认技能包是否由同一份源码产生。
8. 导入 PrimeConsole 并完成本地仿真
在 PrimeConsole 的“Skill 验证”页面选择“导入本地 Skill”,载入刚生成的 .rpk。软件成功解析出:
- Skill:
q1_action_storyboard; - 版本:
v1.0.0; - 原子能力:预设动作;
- 入口:
prime.motion.preset; - ID:
motion.preset。

图 6 PrimeConsole 成功导入本地 RPK 技能包,并解析出技能身份与预设动作原子能力。
点击“开始模拟仿真”后,Q1 本地模型首先执行招手:

图 7 PrimeConsole 正在执行第 1 个预设动作“招手”。页面同时显示本地驱动模型和未连接真机状态。
随后切换到第 2 个动作“双手比心”:

图 8 PrimeConsole 正在执行第 2 个预设动作“双手比心”。
最后模型恢复默认姿态,界面显示“仿真播放完成(共 2 个预设动作)”。

图 9 两个预设动作播放完成后,Q1 模型恢复默认姿态。
这里有一个容易产生疑问的细节:JSON 明明配置了 3 个步骤,为什么 PrimeConsole 只显示 2 个预设动作?原因是 3001 和 3007 是可播放动作,motion_id=0 用于安全复位,模拟器不把它计入动作数量。因此,“3 步剧本”和“2 个预设动作”并不矛盾。
验证报告区域仍显示“暂无验证记录”。这说明本地模拟播放完成不会自动生成正式验证报告,不能把该页面描述为“平台验证报告通过”。本文能够确认的是 RPK 成功解析、两个上肢动作成功播放、默认姿态成功恢复。
9. 结果、局限与下一步
这次实践完成了从配置到仿真的闭环:
- 动作 ID 来自 Q1 SDK 协议定义,而不是自行猜测;
- JSON 剧本与 ROS 2 运行时解耦;
- 正常配置经过静态校验和 5 项自动化测试;
- 非法动作能够在打包前被阻断;
- RPK 可以确定性构建,两次产物哈希一致;
- PrimeConsole 成功解析技能并播放招手、双手比心;
- 播放结束后恢复默认姿态。
如果后续接入真机,建议先在隔离区域完成低风险动作测试,并将固定等待改为“服务返回值 + 动作状态 + 超时”的联合判断;任何预设动作都应在确认机器人型号、控制模式、周边空间和急停能力后执行。
这次项目带来的启发不是“没有机器人也能完成所有机器人开发”,而是:在真机到位之前,可以先把配置格式、接口映射、失败保护、测试和技能包构建做扎实。这样进入真机阶段时,调试重点会更集中,也更容易定位问题究竟来自业务逻辑、SDK 接口还是物理系统。
更多启元机器人 SDK、工具和社区资料可访问启元机器人开发者社区:
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)