资讯动态

从零创建一个启元 Q1 技能包:JSON 五要素、动作编号约束与 PrimeConsole 仿真验证的完整实战教程

发布时间:2026/10/23 2:55:36 来源:尧图企业网站定制
从零创建一个启元 Q1 技能包JSON 五要素、动作编号约束与 PrimeConsole 仿真验证的完整实战教程这篇不讲概念直接动手。假设你已经知道技能包是什么现在要从零创建一个能跑起来的技能包。我们会拆解 JSON 五要素、动作编号约束、main.py 代码结构、打包流程以及在 PrimeConsole 里仿真验证的完整流程。一、技能包文件结构一个技能包.rpk本质是 ZIP 压缩包解压后的目录结构如下q1_emotion_encourage.rpkZIP 压缩包 ├── cfg/ │ └── pkg.yaml # 元数据包名、机型、版本 ├── main.py # 入口代码四服务执行链 └── README.md # 说明文档关键约束cfg/pkg.yaml 必须位于压缩包根目录的 cfg/ 子目录下多套一层文件夹如 my_package/cfg/pkg.yaml会导致 PrimeConsole 读不到元数据包名显示 unknownpkg.yaml 必须含 robot_model: q1否则机型识别失败pkg.yaml 示例user_id:robot_localversion:1.0.0sdk_version:v1.0.0package_name:q1_emotion_encourageauthor:Halcyonrobot_model:q1description:情绪助手·鼓励模式加油、比心暖粉呼吸灯温柔陪伴。二、JSON 五要素详解技能包的核心配置是一份 JSON 文件通常叫 skin.json定义五个要素。以下是一份真实的鼓励模式技能包配置{id:encourage,display_name:鼓励模式,package_name:q1_emotion_encourage,description:情绪助手·鼓励模式加油、比心暖粉呼吸灯温柔陪伴。,lines:[没关系你已经很棒了。,加油我相信你],motions:[3008,3007],emotion_id:3003,led:{mode:254,rgb:[255,100,150],period:2500}}这份配置定义了包名 q1_emotion_encourage、台词池2 条鼓励话语、动作序列3008 加油 → 3007 双手比心、表情3003 开心、灯效254 呼吸模式、粉色 RGB[255,100,150]、周期 2500ms。下面逐一讲解五个核心要素要素一lines台词池台词池是一个字符串数组机器人执行时会随机或按顺序播放{lines:[没关系你已经很棒了。,加油我相信你]}设计建议台词数量2-5 条为宜太少单调太多冗余语气风格根据场景统一鼓励/问候/讲解长度每条 10-20 字太长 TTS 播放时间长影响节奏要素二motions动作编号数组motions 是预设动作编号的数组机器人按顺序执行{motions:[3008,3007]}这个例子表示先执行 3008加油再执行 3007双手比心。可用动作编号Q1 SDK v1.0.0.0编号动作名称类型3001招手上肢3003碰拳上肢3004挥手上肢3007双手比心上肢3008加油上肢3046上半身舞蹈 1上肢3047上半身舞蹈 2上肢重要约束Q1 只能仿真上肢动作含下肢或移动的动作会提示无法仿真。要素三emotion_id表情 ID表情 ID 是整数对应预置表情{emotion_id:3003}可用表情 IDID表情名称3002耍酷3003开心要素四led灯效配置led 是一个对象包含三个字段{led:{mode:254,rgb:[255,182,193],period:2.5}}mode灯效模式254 暖光呼吸、2 彩虹、255 闪烁rgb颜色值三元组 [R, G, B]范围 0-255period呼吸周期秒仅 mode254 时有效常用灯效配置场景modergbperiod鼓励/温暖254[255, 182, 193]粉色2.5元气/活力254[255, 165, 0]橙色1.5科技/专业254[0, 191, 255]蓝色2.0炫酷/表演2[0, 0, 0]彩虹自动0警示/提醒255[255, 0, 0]红色0.3要素五package_name包名包名是字符串用于标识技能包{package_name:q1_emotion_encourage}命名建议格式q1_场景_变体如 q1_emotion_encourage小写 下划线避免空格和特殊字符与 pkg.yaml 里的 package_name 保持一致字段说明package_name技能包标识与 pkg.yaml 保持一致lines台词池执行时随机或按顺序播放motions动作编号数组按顺序执行emotion_id表情 ID3002 耍酷、3003 开心led.mode灯效模式254 呼吸、2 彩虹、255 闪烁led.rgb颜色值 [R, G, B]范围 0-255led.period呼吸周期秒仅 mode254 有效三、main.py 代码结构main.py 是技能包的入口代码基于 ROS2 节点架构负责调用四个服务客户端并按顺序执行。以下是一份真实的鼓励模式技能包代码#!/usr/bin/env python3# -*- coding: utf-8 -*-鼓励模式 —— 启元 Q1 情绪助手技能 皮肤encourage 说明情绪助手·鼓励模式加油、比心暖粉呼吸灯温柔陪伴。 真机运行 source /opt/ros/humble/setup.bash source ~/workspace/sdk_q1/install/setup.bash python3 main.py PrimeConsole 不会执行本文件它静态扫描代码里引用的 接口和动作编号把动作匹配到本地预设动作后播放。 importrandomimportsysimportrclpyfromrclpy.nodeimportNodefromaimdk_msgs.msgimport(CommonRequest,McControlArea,PlayTtsRequest,TtsPriorityLevel,)fromaimdk_msgs.srvimport(LedStripCommand,PlayEmotion,PlayTts,SetMcPresetMotion,)LINES[没关系你已经很棒了。,加油我相信你]EMOTION_ID3003LED_MODE254LED_RGB(255,100,150)LED_PERIOD2500NODENoneclassSkinNode(Node):def__init__(self)-None:super().__init__(q1_emotion_encourage)self.tts_clientself.create_client(PlayTts,/aimdk_5Fmsgs/srv/PlayTts)self.motion_clientself.create_client(SetMcPresetMotion,/aimdk_5Fmsgs/srv/SetMcPresetMotion)self.emotion_clientself.create_client(PlayEmotion,/aimdk_5Fmsgs/srv/PlayEmotion)self.led_clientself.create_client(LedStripCommand,/aimdk_5Fmsgs/srv/LedStripCommand)defspeak(text:str)-bool:ifnotNODE.tts_client.wait_for_service(timeout_sec5.0):NODE.get_logger().error(PlayTts 服务不可用)returnFalsereqPlayTtsRequest()req.header.header.stampNODE.get_clock().now().to_msg()req.tts_req.texttext req.tts_req.priority_level.valueTtsPriorityLevel.INTERACTION_L6 req.tts_req.priority_weight0req.tts_req.domainq1_emotion_encouragereq.tts_req.trace_idreq.tts_req.is_interruptedFalsefutureNODE.tts_client.call_async(req)rclpy.spin_until_future_complete(NODE,future,timeout_sec10.0)returnbool(future.result())defset_emotion(emotion_id:int)-bool:ifnotNODE.emotion_client.wait_for_service(timeout_sec5.0):NODE.get_logger().error(PlayEmotion 服务不可用)returnFalsereqPlayEmotion.Request()req.header.header.stampNODE.get_clock().now().to_msg()req.typeemotionreq.emotion_ids[emotion_id]req.file_paths[]req.priority0req.loop_count1futureNODE.emotion_client.call_async(req)rclpy.spin_until_future_complete(NODE,future,timeout_sec5.0)returnbool(future.result())defset_led(mode:int,rgb,period_ms:int)-bool:ifnotNODE.led_client.wait_for_service(timeout_sec5.0):NODE.get_logger().error(LedStripCommand 服务不可用)returnFalsereqLedStripCommand.Request()req.request.header.stampNODE.get_clock().now().to_msg()req.led_strip_modemode req.r,req.g,req.brgb req.periodperiod_ms futureNODE.led_client.call_async(req)rclpy.spin_until_future_complete(NODE,future,timeout_sec5.0)returnbool(future.result())defset_preset_motion(motion_id:int)-bool:ifnotNODE.motion_client.wait_for_service(timeout_sec5.0):NODE.get_logger().error(SetMcPresetMotion 服务不可用)returnFalsereqSetMcPresetMotion.Request()req.header.stampNODE.get_clock().now().to_msg()req.sourceSDK_RPCreq.area.valueMcControlArea.RIGHT_HAND req.motion.valuemotion_id req.interruptTruereq.ani_pathfutureNODE.motion_client.call_async(req)rclpy.spin_until_future_complete(NODE,future,timeout_sec15.0)returnbool(future.result())defplay_sequence()-None:set_preset_motion(3008)set_preset_motion(3007)defmain()-int:globalNODE rclpy.init()NODESkinNode()try:set_led(LED_MODE,LED_RGB,LED_PERIOD)set_emotion(EMOTION_ID)forlineinrandom.sample(LINES,kmin(2,len(LINES))):speak(line)play_sequence()finally:NODE.destroy_node()rclpy.shutdown()return0if__name____main__:sys.exit(main())这段代码展示了技能包的完整结构。下面讲解关键部分代码结构解析1. 导入依赖importrclpyfromrclpy.nodeimportNodefromaimdk_msgs.srvimport(LedStripCommand,PlayEmotion,PlayTts,SetMcPresetMotion,)技能包基于 ROS2 节点架构需要导入 rclpy 和四个服务客户端。2. 创建 SkinNode 节点classSkinNode(Node):def__init__(self)-None:super().__init__(q1_emotion_encourage)self.tts_clientself.create_client(PlayTts,/aimdk_5Fmsgs/srv/PlayTts)self.motion_clientself.create_client(SetMcPresetMotion,/aimdk_5Fmsgs/srv/SetMcPresetMotion)self.emotion_clientself.create_client(PlayEmotion,/aimdk_5Fmsgs/srv/PlayEmotion)self.led_clientself.create_client(LedStripCommand,/aimdk_5Fmsgs/srv/LedStripCommand)创建一个 ROS2 节点初始化四个服务客户端分别对应 LED 灯效、表情切换、台词播放、动作执行。3. 四个服务调用函数每个服务都有独立的调用函数以 set_preset_motion 为例defset_preset_motion(motion_id:int)-bool:ifnotNODE.motion_client.wait_for_service(timeout_sec5.0):NODE.get_logger().error(SetMcPresetMotion 服务不可用)returnFalsereqSetMcPresetMotion.Request()req.header.stampNODE.get_clock().now().to_msg()req.sourceSDK_RPCreq.area.valueMcControlArea.RIGHT_HAND req.motion.valuemotion_id req.interruptTruereq.ani_pathfutureNODE.motion_client.call_async(req)rclpy.spin_until_future_complete(NODE,future,timeout_sec15.0)returnbool(future.result())这个函数等待服务可用5秒超时构造请求消息异步调用服务等待结果返回15秒超时。4. 执行顺序灯效 → 表情 → 台词 → 动作defmain()-int:globalNODE rclpy.init()NODESkinNode()try:set_led(LED_MODE,LED_RGB,LED_PERIOD)# 1. LED 灯效set_emotion(EMOTION_ID)# 2. 表情切换forlineinrandom.sample(LINES,kmin(2,len(LINES))):speak(line)# 3. 台词播放play_sequence()# 4. 动作执行finally:NODE.destroy_node()rclpy.shutdown()return0执行顺序固定先亮灯再换表情然后说话最后做动作。这个顺序是 PrimeConsole 的设计约束不能自定义。关键约束set_preset_motion 必须用字面量PrimeConsole 不执行 Python而是把所有 .py 拼接后用正则识别能力声明并提取 set_preset_motion(数字) 的字面量去匹配本地动作索引 preset-actions-q1/index.json。这意味着必须写成 set_preset_motion(3008)字面量不能写成 set_preset_motion(motion_id)变量不能写成 set_preset_motion(3000 8)表达式不能写成 set_preset_motion(config[“motion”])从配置读取否则动作全部未匹配机器人不会动。在上面的真实代码中play_sequence 函数就是字面量调用的典型示例defplay_sequence()-None:set_preset_motion(3008)# 加油 - 字面量set_preset_motion(3007)# 双手比心 - 字面量动作编号直接写成数字字面量这是 PrimeConsole 静态扫描能够识别的格式。代码模板与占位符缩进如果用模板生成 main.py占位符必须自带目标缩进4 空格# template/main.py.tpldefplay_sequence()-None:__MOTION_CALLS__# 这里必须自带 4 空格缩进build.py 用 str.replace 渲染时只有替换文本的首行继承占位符前的缩进续行必须自带 \n缩进# build.py 渲染逻辑motion_calls\n .join([fset_preset_motion({m})forminmotions])# 结果# set_preset_motion(3008)# set_preset_motion(3007)两侧都写缩进会导致首行 8 空格双重缩进basedpyright 等静态检查会报错。四、打包流程步骤一准备文件my_skill/ ├── cfg/ │ └── pkg.yaml ├── main.py ├── skin.json └── README.md步骤二压缩为 ZIPcdmy_skillzip-r../q1_my_skill.rpk cfg/ main.py skin.json README.md或用 Pythonimportzipfilewithzipfile.ZipFile(q1_my_skill.rpk,w,zipfile.ZIP_DEFLATED)asz:z.write(cfg/pkg.yaml,cfg/pkg.yaml)z.write(main.py,main.py)z.write(skin.json,skin.json)z.write(README.md,README.md)注意ZIP 内部路径必须是 cfg/pkg.yaml相对路径不能带顶层文件夹如 my_skill/cfg/pkg.yaml。步骤三验证结构解压 .rpk 检查unzip-lq1_my_skill.rpk# 应输出# cfg/pkg.yaml# main.py# skin.json# README.md如果看到 my_skill/cfg/pkg.yaml说明多套了一层文件夹PrimeConsole 会读不到元数据。五、PrimeConsole 仿真验证导入技能包打开 PrimeConsole 1.0.2点击导入技能包选择 .rpk 文件检查包名、机型、版本是否正确仿真运行点击仿真按钮观察机器人模型执行动作序列仿真限制PrimeConsole 仿真只验证动作轨迹与时序以下功能在仿真中不可见不发声TTS 不播放不切表情emotion_id 无效无灯效LED 不亮Q1 只能仿真上肢动作含下肢或移动的动作会提示无法仿真这意味着仿真只能验证动作编号是否正确、动作顺序是否合理、时序是否流畅。声音、表情、灯效需要真机验证。真机验证清单导入真机后逐项验证LED 灯效是否按配置亮起颜色/模式/周期表情是否切换emotion_id 对应表情TTS 是否播放台词音量/语速/内容动作是否执行编号/顺序/流畅度四个服务的执行顺序是否正确LED→表情→台词→动作常见错误与排查现象可能原因解决方案包名显示 unknownpkg.yaml 不在根目录或多套一层文件夹检查 ZIP 结构确保 cfg/pkg.yaml 路径正确机型识别失败pkg.yaml 缺少 robot_model: q1添加该字段动作不执行动作编号写成变量或表达式改用字面量 set_preset_motion(3008)仿真看不到灯效/表情这是正常的仿真只验证动作真机验证动作提示无法仿真使用了下肢或移动动作Q1 只能仿真上肢动作TTS 不播放仿真环境不支持真机验证表情不切换仿真环境不支持真机验证调试技巧先用 PrimeConsole 仿真验证动作序列再导入真机验证声音/表情/灯效查看 PrimeConsole 日志确认四个服务调用顺序六、启元 Q1 相关工具与文档开发工具PrimeConsole 1.0.2技能包导入、仿真验证、真机执行Q1 SDK v1.0.0.0机器人底层 SDK提供四个服务客户端Python 3.8编写 main.py 和打包脚本文档与资源启元 Q1 开发者文档技能包格式规范、API 参考preset-actions-q1/index.jsonQ1 可用动作编号索引表情索引3002 耍酷、3003 开心灯效模式254 暖光呼吸、2 彩虹、255 闪烁版本信息本文基于 Q1 SDK v1.0.0.0 PrimeConsole 1.0.2后续版本可能新增动作或表情编号。访问启元机器人开发者社区获取 SDK、仿真工具、开发文档完成从代码仿真到真机落地的全流程开发https://dev.primebot.com/

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑