资讯动态

启元 T1 技能开发实录:抓拍、50 Hz 速度环与 .rpk 打包!

发布时间:2026/10/23 3:00:23 来源:尧图企业网站定制
文章目录先说结论一、物理拓扑三块板子一个网段二、aimdk_msgs一包消息定义四层语义2.1 命名空间/aima 之下三段式2.2 一条完整的调用链长什么样三、运控层一台会拒绝你的状态机3.1 动作是一台状态机不是一个函数3.2 两条时序红线3.3 输入源仲裁为什么你的技能抢不到控制权3.4 一次动作切换的时序长什么样四、感知通路一个服务一条流4.1 “1 fps”是怎么来的五、交互层为什么“表情”是服务“触摸”是消息5.1 为什么“触摸”是最可靠的确认通道六、PrimeConsole它不是遥控器是 IDE七、从技能到包.rpk 的结构7.1 一个技能的完整生命周期八、这套架构的三个优点三个缺口8.1 为什么不用“私有 RPC SDK 封装”8.2 四道安全闸缺一道都危险九、给开发者的阅读与上机顺序9.1 五个“文档没写但要命”的细节结语判断一台机器人“能不能二次开发”不看发布会上说了什么看它 SDK 目录里有什么。一个完整的 SDK 目录等于把整台机器人的能力边界摊在桌面上哪一层负责运动、哪一层负责说话、哪些能力压根没有。这篇不做功能罗列按“分层”把启元 Q1/T1 的软件栈拆一遍——从上位机的 PrimeConsole到中间那包aimdk_msgs再到底层的运控状态机。先说结论启元的软件栈可以压缩成一句话一套 ROS2 FastDDS 的去中心化节点图按“运控 / 硬件抽象 / 交互 / Agent”四层组织消息任何人都能在 PC、运控板或大脑板上挂一个节点用同一套接口访问全部能力。这个设计有三个直接后果后面会逐一验证部署位置自由。程序跑在哪儿不重要只要能连上同一个 DDS 域。接口即权限。你能调哪些服务就等于你被允许动哪些硬件——没有额外的“权限层”。能力缺口会立刻暴露。没有导航服务就是没有没有夹爪话题就是没有。SDK 目录里找不到的东西写代码时一定绕不过去。一、物理拓扑三块板子一个网段先看硬件怎么连这决定了代码往哪儿放。节点地址社区文档口径角色开发 PC10.1.1.99/24有线网卡跑你自己的 ROS2 节点、编译 SDK运控板10.1.1.100关节、步态、动作状态机SSH 用户run大脑板10.1.1.101算力密集任务、视觉模型、技能常驻进程这三个地址来自社区开源技能 carry-clothes 的实测记录不是官方文档的正式命名但足以说明架构运控板管“身体”大脑板管“脑子”两者用同一条 DDS 总线通信。这个分工解释了 SDK 目录里两个容易混淆的词mcmotion control运控和halhardware abstraction layer硬件抽象。前者是“让机器人怎么动”后者是“让机器人看见、听见、说话、亮灯”。官方 README 给出的 SDK 目录树agent/hal/interaction/mc四层外加common与config两个支撑层。看一个 SDK 的分层比看它的功能列表更能判断它能不能长期用。 另外注意三份文档的分工README.md讲结构、快速入门讲环境、接口说明讲参数。先看物理层。这套栈里最容易被忽略的事实是三块板子不是“主从”关系而是同一个 DDS 域里的对等节点。这决定了一件很实用的事——你的代码写在哪儿都行。三块板子的拓扑。开发 PC、运控板、大脑板各跑各的节点靠 DDS 互相发现。所以“部署位置”不是架构问题只是网络配置问题真正要小心的是把实时任务和通用任务混在一台机器上。二、aimdk_msgs一包消息定义四层语义官方 README 给出的目录树是理解这套架构最直接的材料primebot_sdk/ ├── README.md ├── PrimeBot_SDK快速入门与集成指南.md ├── 接口说明.md ├── 友好用户使用声明.md ├── aimdk_msgs/ │ ├── agent/ # AI Agent 层ASR 语音识别结果 │ ├── config/ # SDK 默认 FastDDS 通信配置 │ ├── env-hooks/ # colcon setup 自动加载的环境钩子 │ ├── common/ # 任务响应与基础类型定义 │ ├── hal/ # 硬件抽象层 │ │ ├── audio/ # 音频采集/播放 │ │ ├── camera/ # 相机图像/RTSP 流 │ │ ├── msg/ # BMS / 触摸 / 关节 等状态 │ │ └── srv/ # 灯带控制 等服务 │ ├── interaction/ # 交互层 │ │ ├── msg/ # TTS 请求/响应 / 优先级 │ │ └── srv/ # 表情播放 / TTS 语音播报 │ └── mc/ # 运控层 │ ├── action/ # 动作定义 / 动作状态 / 动作指令 │ └── motion/ # 运动速度 / 预设动作 / 自定义关节指令 └── examples/ # cpp / python / opencv / ruckig 例程这张树里有两个细节值得停留。细节一agent只放 ASR。语音识别没有归到hal/audio下而是单独开了一层。这是个语义上的判断——麦克风采样是“硬件”把声波变成文字是“理解”。放在 agent 层等于承认“语音转文字”属于智能层不属于驱动层。这个划法在未来接大模型时是加分项换 ASR 引擎不用动硬件抽象。细节二common是单独一层。里面是“任务响应与基础类型定义”说白了就是统一的Response{code, msg} 统一的 token 结构。全 SDK 的错误码、来源校验都靠它。一个 SDK 有没有认真做就看它敢不敢统一错误码——各家自己编一套-1的通常维护三年就烂了。2.1 命名空间/aima之下三段式接口路径的实际前缀是/aima往下按层切前缀归属典型内容/aima/mc/...运控动作切换、速度指令、上肢关节指令、动作状态/aima/hal/...硬件抽象camera/CaptureJpegImage、touch/state、BMS、灯带/aima/interaction/...交互TTS 播报、表情播放、优先级/aima/agent/...智能ASR 结果三段式命名带来的好处是可发现性你不用背接口表ros2 service list | grep /aima/mc就能知道自己能干什么。这也意味着——想知道一台启元机器人有什么能力列一次服务列表就够了。2.2 一条完整的调用链长什么样把四层串起来看一次“让它走过来抱衣服”的动作在软件上发生了什么agent 层麦克风阵列拾音ASR 出文本得到“把衣服拿到洗衣机旁”。interaction 层TTS 回一句“好的我来了”表情切到“开心”给用户一个已接收的反馈。mc 层查询当前动作状态从100 RUNNING切到300 BIPED_LOCOMOTION_WBC等状态回落到 100然后以 ≥50 Hz 持续发布速度指令。hal 层相机按需抓拍服务返回 JPEG 元信息视觉模块算出目标在画面里的偏移回喂给第 3 步的速度指令。这条链最有意思的地方是第 2 步和第 4 步的对称性一个往人身上走TTS/表情一个往机器身上走相机/关节。四层不是按“技术栈”切的是按“跟谁打交道”切的——跟人打交道归 interaction跟硬件打交道归 hal跟身体运动打交道归 mc跟语义理解打交道归 agent。理解了这条切法你就能预判想加一个“挥手打招呼”改的是 mc预设动作 interactionTTS想加一个“认人脸”改的是 hal相机 agent识别。把消息包拆开看会发现它的分层依据不是“技术栈”而是“跟谁打交道”。这个划分方式直接决定了你写技能时该去哪一层找接口。四层加两个支撑层。agent只放 ASR 结果这件事值得单独说语音识别属于理解不属于驱动所以它没有被塞进hal/audio。换 ASR 引擎不用动硬件抽象层这就是分层带来的自由度。三、运控层一台会拒绝你的状态机运控是整套架构里最“有脾气”的部分。社区技能 README 里记下了几条硬约束每一条都是踩坑换来的3.1 动作是一台状态机不是一个函数动作切换有个明确的编号体系社区文档口径编号名称含义100RUNNING已进入稳定运行态200TRANSITION切换中正在补中间状态300BIPED_LOCOMOTION_WBC双足/轮足全身控制走跑302BIPED_RECORD_UPPER上肢录制模式零力矩可手扳关键规则下发走跑指令前必须确认状态已经从 200 落到 100。在TRANSITION里发速度指令机器人不会理你或者直接报错。这不是“容错没做好”而是有意为之——动作切换过程中关节正在从一套控制律交接到另一套此时插入外部指令等于在一个正在换挡的变速箱里塞一根棍子。理解了分层再看运控层这台状态机。它最容易被误解的地方是TRANSITION期间不接受指令这不是 bug是刻意的排他窗口。状态机与三条硬约束。200 是一个“换挡期”关节正在从一套控制律交接到另一套此时插外部指令机械上不一定坏软件上一定乱。正确写法是下发后每 50 ms 轮询等到 100 再起速度环。3.2 两条时序红线SetMcAction调用间隔 500 ms → 返回-10001请求过于频繁。社区技能把TaskConfig.set_action_interval_s定成 0.6 s就是为了留余量。这类限流在服务端做说明设计者不信任调用方。走跑控制要求 ≥50 Hz 持续发布单一信源中断超过 1000 ms 直接脱锁停机。这是典型的**看门狗watchdog**设计控制指令是“心跳”不是“命令”。发一帧就去干别的机器人会认为你掉线了主动停下来。第二条对写技能的人是致命的。它意味着“发个速度指令然后阻塞等视觉结果”这种写法根本不能上真机——你必须开一个独立线程持续发且这个线程不能因为 GC、IO、模型推理被卡住 1 秒。3.3 输入源仲裁为什么你的技能抢不到控制权速度指令不是“谁发谁算”而是按信源优先级仲裁信源优先级rc/pnc/interaction80 级SDK 二次开发39–20 级社区技能如 carry-clothes30 级优先级低意味着App 或遥控器正在操作时你的技能拿不到控制权。正确做法是注册输入源后先调GetCurrentInputSource校验被占用就明确中止并告诉用户“谁在占用”而不是闷头发指令、看起来“没反应”。这套“优先级 仲裁 看门狗”的组合是机器人软件里最像汽车电子的部分任何时刻只有一个主子且主子必须持续证明自己还活着。3.4 一次动作切换的时序长什么样把 3.1–3.3 的规则串起来一次“从站立切到走跑”在时间轴上大致是这样时刻动作依据t0查询当前动作状态必须先读后写t05 ms下发SetMcAction(300)距上次调用 ≥500 ms否则 -10001t05 ms ~ t0800 ms状态停在200 TRANSITION关节在换控制律此时任何速度指令都会被忽略t0800 ms状态落到100 RUNNING每 50 ms 轮询一次最多等 10 st0805 ms启动 50 Hz 速度发布线程中断 1000 ms 会脱锁停机任意时刻上位机/遥控器抢控制权优先级 80 技能 30技能必须让位这张表解释了一个新手最常见的困惑“我发了指令机器人没反应但也没报错。”大概率是你正好卡在200 TRANSITION那 800 毫秒里。所以正确的写法不是“发完就等”而是“发完 → 轮询到 RUNNING → 再发速度”。多写这五行轮询能省掉一整天的怀疑人生。四、感知通路一个服务一条流视觉只有两个入口这个设计非常克制入口形式频率建议适合场景/aima/hal/camera/CaptureJpegImageROS2 Service请求-响应约 1 fps一次响应结束后再发下一次按需抓拍、存档、单帧识别rtsp://IP:2554/live_camera_idRTSP 流连续预览、实时推理、录像单帧服务的响应体不是一张裸图而是一个JpegImage包装camera_id、width/height、exposure、gain图像本体用sensor_msgs/CompressedImage承载。为什么要带元信息因为同一段识别代码可能今天收到 1280×720、曝光 50 的图明天收到 640×480、曝光 200 的图。没有这些字段你无法解释“为什么同一个模型昨天准、今天不准”。工程上把元信息随图存下来等于给每次失败留了证据。RTSP 那条路的坑在客户端OpenCV 的VideoCapture优先用 FFmpeg 后端失败再退默认后端read()一次调用里同时完成取帧、解码、返回图像。于是“模型接在哪”非常明确——read()返回有效 frame 之后。但这里有个几乎所有人都会犯的错把耗时模型直接塞进读帧循环。结果是读一帧、推一遍、写一次盘、再读下一帧模型越慢取流越卡最后帧率被模型拖到个位数。正确做法是“取流与消费分离”一个线程只管把最新帧放进有界缓存推理线程取走最新的一帧慢就丢帧。实时系统里丢帧永远优于积压。4.1 “1 fps”是怎么来的文档建议单帧抓拍按约 1 fps且要“一次响应结束后再发下一次”。这不是性能上限是排队成本的考虑。一次抓拍的完整链路是请求进服务 → 等服务端拿到一帧新数据曝光 读出 JPEG 编码→ 序列化 → 走 DDS → 客户端反序列化。任何一环变慢请求就在队列里等着。服务端默认等待新帧的时间是 1000 ms客户端还有自己的 RPC 超时——两层超时任意一层触发都表现为“调用失败”。如果你按 30 fps 去刷这个服务会发生两件坏事请求在队列里堆积越等越久相机被频繁占用其它模块比如视觉识别、录像拿不到图。想看实时画面请走 RTSP那是为连续流设计的抓拍服务是为“我要一张确定的图”设计的。用错入口怎么调参数都不顺。感知层只有两个入口但这两个入口的服务对象完全不同一个要“确定的这一张”一个要“连续的那一帧”。混用就会出现各种玄学问题。两条视觉通路。抓拍是请求—响应适合存档与单帧识别RTSP 是持续流适合预览与实时推理。最容易犯的错是把耗时模型塞进取帧循环结果取流被推理拖慢缓冲区越积越旧。五、交互层为什么“表情”是服务“触摸”是消息这一层有个很能说明设计思路的区分服务srvTTS 播报、表情播放、灯带控制。特点是“我要你做一件事并告诉我结果”。消息msg触摸状态、BMS 电量、关节状态。特点是“状态一直在变谁关心谁订阅”。这不是随意划分而是通信语义的必然请求-响应适合一次性动作发布-订阅适合持续状态。顺带说一个真机上的现实约束启元的能力清单里没有 ASR 服务语音识别在 agent 层属于可选能力。所以社区技能用“头部触摸”当确认通道——用户摸一下头表示“我放好了”。这是个很聪明的降级没有语音识别就用触觉没有视觉就用超时。做技能的人必须学会这种“能力降级链”的思维。5.1 为什么“触摸”是最可靠的确认通道交互层里最不起眼的接口是触摸但它在真机上往往是唯一稳定的输入。原因有三层。第一带宽极低但语义明确。一次触摸只能表达“是/否”恰好覆盖了技能里 90% 的确认需求开始、继续、找到了、停下。第二不依赖声学环境。语音识别在混响、多人说话、电视背景音下会掉点触摸不会。第三抗遮挡。人站在机器人侧后方说话麦克风阵列可能定位不准伸手摸一下头一定会被触到。所以社区技能用“摸头”当确认不是偷懒是在能力约束下选了最稳的那条路。做产品的人要习惯这种取舍不是用最好的技术是用最不容易出错的技术。六、PrimeConsole它不是遥控器是 IDE上半部分是 PrimeConsole 的六个模块下半部分是资料包清单Q1 机器人 SDK v1.0.0.013 MB、T1 机器人 SDK v1.0.0.013 MB、ARM 原生编译环境4.8 MB支持 Orin 与 RK 平台。六项功能不是堆叠是调试顺序——先确认在线再看画面再验运动最后才整包验证而 13 MB 的 SDK 里装的就是aimdk_msgs与示例代码。官方列出的六个模块恰好对应开发者的六件事模块解决什么连接状态与日志设备在不在线、通信正不正常 —— 排障第一现场实时视频流监控相机画面与传输状态 —— 感知类问题的眼睛语音与运动控制方向控制、急停、复位 —— 验证运动响应与安全策略机器人仿真虚拟全身关节运动提前验证轨迹 —— 降低真机风险动作与表情测试挥手、握手、舞蹈、表情预设 —— 检查表现是否符合预期Skill 验证与 AI 中心验证 Skill、管理模型与算力 —— 从“能跑”到“能装”注意第四项和第六项的组合先仿真、再真机先单点验证、再整包验证。这不是功能列表是一条工作流。一个成熟的机器人工具链价值不在于功能多而在于它把“正确的调试顺序”固化进了界面。七、从技能到包.rpk的结构技能最终要变成一个能安装、能卸载、能声明能力的包。社区技能 carry-clothes 的包结构可以作为参考官方.rpkschema 尚未公开字段命名按通用机器人技能包惯例carry-clothes-2.1.0.rpk ├── manifest.json # 清单capabilities 写真实 ROS2 接口路径 ├── main.py # 入口 ├── SKILL.md / README.md # 技能说明 ├── src/ # primebot_iface / task / poses / vision ├── tools/teach_record.py # 位姿标定工具 ├── config/task_config.yaml ├── assets/icon.png └── META-INF/checksums.json最有意思的是打包器的反向能力校验逐个检查manifest.json里声明的 ROS2 接口在代码里是否真的有对应实现符号漏了直接报错。PrimeHub 的技能卡片视频电话、拿衣服、天气预报、PrimeBuddy。每张卡都标了能力范围与安装入口这是“机器人能力像软件一样流通”最朴素的产品形态——没有它每个技能都得靠文档和 QQ 群分发。这个“声明即契约”的做法值得所有做技能生态的团队抄一遍能力不能靠文档对齐要靠构建期校验。声明了没实现——打包就挂实现了没声明——权限就下不来。两边一夹清单和代码就不会走偏。7.1 一个技能的完整生命周期把散落各处的线索拼起来一个技能从想法到上架大概是六步阶段做什么落在哪个工具上1. 找能力列/aima接口确认要用的东西真存在ROS2 CLI / 《接口说明.md》2. 写流程状态机 位姿 视觉先用--dry-run打印计划本地 Python3. 仿真无真机跑全流程验证时序与分支PrimeConsole 仿真 /--sim4. 标定真机上手动掰姿态、录制、回放、取角度拖动示教 teach_record.py5. 上机切开发者模式、调内核缓冲、连真机调试PC 机器人同网段6. 打包发布生成.rpk、能力自检、发布到 PrimeHub打包脚本 技能市场这一步里第 4 阶段最容易被跳过也最容易翻车。纸面上算出来的关节角和真机上能托住衣服的关节角往往差 10–20 度。官方给出的解法是物理拖动示教切到零力矩录制模式302用手把手臂掰到想要的姿态回放取末帧角度粘进配置。这套流程听着原始但它把“不可言说的手感”变成了可复现的数字。八、这套架构的三个优点三个缺口优点扁平。没有网关、没有中间件服务、没有私有协议栈。ROS2 FastDDS 就是全部开发者已有的 ROS 知识直接复用学习成本接近零。位置无关。同一个节点跑在 PC 上调试、跑在大脑板上常驻代码不用改只改ROS_DOMAIN_ID和网络配置。接口即能力。ros2 service list就是能力清单缺什么一目了然不用猜、不用试。缺口截至 2026 年 10 月的公开资料缺口影响社区现状的替代方案无 SLAM / 导航 / 语义地图不能“导航到某点”视觉伺服闭环用相机把误差吃掉无夹爪 / 末端执行器接口不能抓取上肢关节插值双臂合拢托住无 ASR 服务听不懂口令确认头部触摸 / 超时兜底无末端力 / 负载传感感知不到重量视觉判据 触摸 超时三件套这份缺口清单不是黑稿恰恰相反——它是官方接口诚实的证据。一个 SDK 如果什么都“有”通常意味着它把没实现的东西也写进了文档那才是灾难。8.1 为什么不用“私有 RPC SDK 封装”很多机器人厂商的做法是底层私有协议外面包一层 C/Python SDK开发者只能调函数。启元选了更“裸”的路——直接把 ROS2 接口暴露出来。维度私有 RPC 封装原生 ROS2 接口上手成本学一套新 API复用已有 ROS 知识几乎为零调试手段只能靠日志和 SDK 打点ros2 topic echo/rqt/rviz全套现成生态兼容自成孤岛能直接接 Nav2、MoveIt、Foxglove 等可控性高能锁能力低接口一旦公开就收不回责任边界清晰需要靠优先级、限流、校验来兜选第二条路等于把“接口设计”这件事一次做到位代价是没有回头路一个接口名一旦被一百个技能引用就再也不能改。从这个角度看aimdk_msgs里那个common层统一响应 统一 token才是整套设计里最关键的一块——它决定了这套接口能不能撑过三年。各家自己编错误码的 SDK通常第三年就开始出现“同一个 -1 有七种含义”的问题。8.2 四道安全闸缺一道都危险这套架构里安全不是单独一个模块是四层各管一段闸位置拦什么失效后果① 优先级仲裁运控层多信源抢控制权两套指令打架机器人抽搐② 调用限流运控层500 ms指令风暴-10001或被高频指令带乱节拍③ 看门狗运控层1000 ms上位机崩溃/断连机器人带着最后一条速度指令一直走④ 力控/急停驱动与硬件碰撞、堵转伤人、烧电机值得注意的是第 ③ 道——它把控制变成了心跳。这个设计在工业机器人里很常见示教器松开就停在消费级产品上尤其重要用户的笔记本随时可能休眠、Wi-Fi 随时可能掉机器人不能因为上位机睡着就继续往前走。第 ④ 道则说明一件事最终的兜底永远在电流环不在应用层。你写的任何保护逻辑都比不上驱动器的过流保护快。九、给开发者的阅读与上机顺序按这套架构我建议的顺序是先列接口连上机器人ros2 node list/ros2 service list/ros2 topic list把/aima开头的全部抄一遍。这一步比读文档快。再读接口说明对着抄下来的清单看文档重点看参数单位弧度还是角度、米还是毫米和错误码。切开发者模式SSH 进10.1.1.100走“开发者功能”开关重启。不开这个开关网口根本连不上。调内核缓冲net.core.rmem_max/wmem_max调到 24 MB 级别否则高频 topic 会丢帧——这个坑几乎人人踩一次。先仿真后真机PrimeConsole 的仿真模块和--sim参数先用起来把 10 步流程跑通再上机。打包前做能力自检manifest 里写的每个接口都要能在代码里指出实现位置。9.1 五个“文档没写但要命”的细节单位是弧度不是角度。关节指令、位姿数组全部用 rad。传度数不会报错只会让机器人摆出一个很怪的姿势。关节顺序是写死的。官方示例里上肢按固定顺序给 6 个数顺序错了不报错姿态全歪。camera_id拼错不会提示相机不存在。通常表现为超时很容易被误判成网络问题。两层超时要分开调。请求里的timeout_ms管等新帧客户端的等待管等 RPC。调错层白折腾。ROS_DOMAIN_ID不一致节点互相看不见。多机调试时先对一下这个环境变量比查网络快。carry-clothes的 README 直接把“缺什么”列成表没有 SLAM/导航、没有夹爪、没有 ASR、没有末端力传感并给出每一项的替代方案。在开源技能里看到这种表格说明作者真的上过机。结语把架构拆完回头看那个最初的问题“这台机器人能不能二次开发”答案不在参数表里而在这三件事上接口是否分层清晰、部署是否位置无关、能力边界是否诚实。启元这套栈在前两点做得干净第三点做得罕见地坦白——它把“没有导航”“没有夹爪”直接摆在社区技能里让人看见。对开发者来说这种坦白其实是好消息你不需要猜它能干什么你只需要决定在它的边界内做什么。过来kk https://dev.primebot.com/

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

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

免费获取报价 →
↑