AGIBOT · AimDK 二次开发手册

智元远征 A3 Ultra 软件开发手册

面向开发者的完整二次开发指南 —— 覆盖系统架构、环境搭建、运动控制、底盘导航、地图、语音交互、资源管理、技能播放与故障诊断的接口说明与代码示例。

SDK 版本:AimDK-A3_ultra-V3.2-0815(a3_aimdk-3.2.0)|适配软件版本:3.2.x|主机平台:Ubuntu 24.04 / ROS2 Jazzy

0. 快速上手与分步操作

本章动作为主、概述从简:先按步骤把环境跑通、让机器人动起来,再深入各能力域。若已熟悉环境,可直接进入 第 3 章

0.1 环境自检清单

逐条执行,全部通过后再进行运动控制:

步骤命令 / 操作判定
1. 连机器人网络开发机加入机器人所在局域网能分配到同网段地址
2. 登节点ssh agi@10.42.10.12(密码 1进入 shell 即通过
3. 测连通ping 10.42.10.10(HDU)/ ping 10.42.10.11(ADU)有回包
4. 测 RPCGetAction,见下返回 JSON
5. 搭 Python 环境python3 -m venv mydev && source mydev/bin/activate提示符出现 (mydev)
# 速测:确认能调通运动控制 RPC
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/GetAction' \
     -H 'Content-Type: application/json' -d '{}'
# 期望输出里出现 "current_action" 字段,即链路正常

0.2 分阶推进路线

按序推进,每一阶都留一个可验证的收尾动作:

目标操作完成标志
连通0.1 清单全过GetAction 返回 JSON
发声6.1机器人播出一句 TTS
动作4.1 切 MOTION + 4.2 行走发速度后移动
组合见 0.3 示例端到端小应用跑通

0.3 端到端示例:语音互动机器人

三模块分别验证,再串成主循环:

  1. 播报警示语:调 PlayTTS6.1)。
  2. 走一段 / 挥手:切 MOTION 后发行走速度(4.2)、控制手臂(4.4)。
  3. 用唤醒串起来:订阅 /agent/wakeup6.4),把 1、2 包进主循环。

完整操作链:

#操作命令要点
1停 motion_playerMDU/50080 调 stop_app,见 4.5
2切 MOTIONSetAction,见 4.1
3播 TTS 提示PlayTTS,见 6.1
4发行走速度 2slocomotion_velocity,见 4.2
5等待唤醒,回到 3订阅 wakeup,见 6.4
上述示例只用到行走速度通道。若场景需要直接控制腰 / 腿关节(如吊装挥拍、动作编排),普通 MOTION 档不生效,必须切换到 EXT 增强模式后再逐关节下发——见 第 5 章 下肢运控与全身逐关节控制

0.4 问题排查操作步骤

现象按序执行
接口无返回1) 核对端口/IP(3.1 端口表) 2) ping 节点 3) 换浏览器手测 URL
返回但不动作1) GetAction 看是否在 MOTION 2) 看 GetAlertList 告警 3) 查 motion_player 是否占用 4) 若是腰/腿逐关节命令无效,先确认是否处于普通 MOTION 档——该档腰/腿被策略接管,需切 EXT 增强模式,详见 5.5 EXT 增强模式
TTS 无声但返回成功1) 换已知可用文件 2) 核对格式:16kHz/16bit/单声道
关节 topic 无效1) 确认已停 motion_player 2) 确认字段非空(空 defect 会致 crash)

排查顺序:连通性 → 状态机(Action) → 占用(motion_player/控制源) → 告警(HDS)。

0.5 安全红线

  • 运动前:留出安全空间,确认可随时急停;PASSIVE/DAMPING 等安全态勿由程序直接切换。
  • 下肢/腰部逐关节控制(5.4)承重大,先在吊装/降低重心下测试,逐步放大幅度。
  • 默认口令(agi/1、热点 02270227)仅限实验室,备装环境务必修改。
  • 代码不写死明文密钥/敏感信息,统一使用占位符。

1. 机器人平台与系统架构

1.1 硬件组成(MDU / HDU / ADU)

智元远征 A3 Ultra 机器人工控机由三个核心计算节点组成,均运行 Ubuntu 24.04,使用 systemd 管理系统服务。掌握各节点分工是二次开发路由调用的前提。

节点主要硬件承载关键模块典型用途
MDU主控 / 运控板SM(状态机)、PM、gateway、hal_ethercat、mc(运动控制)运动控制、状态机、EtherCAT 总线、告警 HDS
HDU头部 / 人机交互板hal_audio、hal_hdu_camera、hal_imu、data_exporter、motion_player、skillpilot语音、摄像头、IMU、动作播放器、技能分发
ADU感知 / 决策板agivslam、embodied_agent、legged_odometry、mm(地图)、pnc(导航)、slam建图、定位、导航规划、具身智能体
典型 IP 约定:HDU=10.42.10.10,ADU=10.42.10.11,MDU=10.42.10.12。实际以 AimMaster 无线局域网页面显示的 IP 为准。

1.2 软件系统与 AimDK 定位

A3 Ultra 出厂预搭载完整运动控制、感知、导航程序,二次开发只需调用高层接口,无需开发底层控制模型。

  • 通信底座 AimRT:机器人内部框架,提供 Channel(主题通信)与 RPC(请求响应)两种基本通信方式。
  • AimDK(Aim Developer Kit):面向第三方开发者的统一接口层,将内部 AimRT 能力封装为 HTTP JSON RPC 与 ROS2 Topic 两种通用形式。
  • 官方文档:https://open.agibot.com/docs/aimdk/a3-ultra/v3_2/

开发涉及三大能力域

· 身体能力
运动控制(走/手臂/头/手/腰)、底盘、地图、导航、技能(舞蹈/动作)。
· 交互能力
TTS 播报、音频播放、麦克风、唤醒、音频焦点、表情。
· 系统能力
资源管理、故障告警、BMS 电池、系统模式(急停)、音量。

2. 二次开发环境搭建

2.1 网络连接与 SSH

  1. 开发机与机器人连接到同一无线网络
  2. AimMaster → 设置 → 无线局域网,获取机器人各节点 IP。
  3. 通过 SSH 登录目标节点。
# HDU(音频/交互/资源/技能)
ssh agi@10.42.10.10
# ADU(地图/定位/导航 PNC)
ssh agi@10.42.10.11
# MDU(运动控制 Action/关节)
ssh agi@10.42.10.12
账号 agi,密码 1。ORIN AP 热点默认密码 02270227。生产环境请务必修改默认口令。默认 IP 归属:10.42.10.10=HDU / 10.42.10.11=ADU / 10.42.10.12=MDU,示例与 SDK 均沿用此约定。

2.2 部署目录约定

二次开发统一部署在 /agibot/ 下,示例使用桌面目录:

mkdir -p /agibot/data/home/agi/Desktop

2.3 Python 虚拟环境

cd /agibot/data/home/agi/Desktop
python3 -m venv mydev
source mydev/bin/activate
# 按需安装 requests / rclpy(若走 ROS2 需在 ROS 环境内)

2.4 ROS2 与依赖环境

使用 ROS2 Topic 接口前需加载机器上的 ROS2 与插件环境:

# 1) 机器人运行时环境
source /agibot/software/v0/entry/env/env.sh
# 2) ROS2 Jazzy 基础
source /opt/ros/jazzy/setup.bash
# 3) ros2_plugin_proto 消息(RosMsgWrapper),需在 SDK 的 prebuilt 目录下执行
source /path/to/prebuilt/ros2_plugin_proto_aarch64/share/ros2_plugin_proto/local_setup.bash
机器上话题默认 QoS 为 history: keep_last / depth: 10 / reliability: best_effort,订阅握手建议保持兼容。

2.5 快速上手流程

1
联网并 SSH 到目标节点,创建部署目录与虚拟环境。
2
保存 SDK 示例脚本到 Desktop(本站其余章节可复制)。
3
按章节加载 ROS2 环境变量。
4
运动控制前,先通过 SetAction 将机器人切换到力控模式的 MOTION(见 4.1)。
5
若使用手臂/脖子/腰部/手指关节 topic,需先在 MDU 关闭 motion_player
运动控制安全须知:开发阶段务必在周围留出安全空间、准备急停;安全模式(PASSIVE / DAMPING)程序不建议直接切换,遥操作等特殊状态仅可手动操作。

3. 接口总览

3.1 HTTP JSON RPC HTTP

低频、多对一调用;语言无关,仅需能发 HTTP 请求。统一格式:

POST http://<node_ip>:<port>/rpc/<Service>/<Method>
Header: Content-Type: application/json
Body   : { "header": {...}, ...业务字段 }

各节点 RPC 端口依据服务而定,常用示例:

服务端口节点
MotionControlActionService(运动状态机)56322MDU
MotionCommandService(动作播放)56444MDU
TTSService / AgentControlService(语音)59301HDU
ResourceService(资源)51049HDU
HalAudioService(硬音量/文件播放)56666HDU
MappingService / LocalizationService / RelocalizationService50807ADU
PncService(规控导航)53176ADU
HDSService(告警)50587MDU

3.2 ROS2 Topic / Service ROS2

高频、多对多调用,需支持 ROS2 Jazzy(Fast DDS)。主题有两种消息载体:

载体消息类型适用载荷
标准 ROS2 消息sensor_msgs/JointState手臂/脖子/手关节、关节状态标准字段
通用包装消息ros2_plugin_proto/msg/RosMsgWrapper行走、腰部、表情、TTS状态、BMS 等data(bytes list) + serialization_type + context

3.3 消息序列化(JSON / PB)PROTO

RosMsgWrapper 的 serialization_type 决定 data 编码方式:

  • json:可直接解析的 JSON 字符串(常用于行走速度控制)。
  • pb:protobuf 字节流,需用 aimdk.protocol.* 中对应消息解析。示例中 data = [bytes([x]) for x in json_str] 为按字节切分,解析时用 b"".join(msg.data) 还原。
# 发送(PB 编码,以腰部为例)
from aimdk.protocol.motion_control.motion.mc_motion_channel_pb2 import MotionControlMoveWaistChannel
cmd = MotionControlMoveWaistChannel()
cmd.header.timestamp.seconds = int(now.timestamp())
cmd.waist_pitch = 0.1
raw = cmd.SerializeToString()
wrapper = RosMsgWrapper()
wrapper.serialization_type = "pb"
wrapper.context = ["aimdk.protocol.MotionControlMoveWaistChannel"]
wrapper.data = [bytes([b]) for b in raw]

3.4 控制源 与 状态机 Action

控制源(control_source) 用于标识请求来源与抢占优先级,由安全模块按来源分配。RequestHeader 中的该字段一般保持默认(AUTO=0)即可,仅在需要从特定来源(如安全模块 ControlSource_SAFE=2)发起时显式指定。A3 Ultra 运动控制内置状态机,通过 Action 表达当前运动模式(详见第 4 章)。

同一时间仅一个控制源持控;切换动作前确认目标 Action 可达,避免多端抢占冲突。

3.5 RequestHeader 完整字段 与 接口鉴权

多数 RPC 请求体首层即为 request_header(或 header),其字段用于链路追踪与控制源标识。依据 common/header.proto

字段类型说明
timestampTimestamp请求时间戳(秒/纳秒)
control_source枚举控制源,默认 AUTO=0,安全模块触发用 SAFE=2
uuidstring请求唯一标识
trace_idstring追踪链路 ID(TTS 打断等按此定位)
dominstring业务域(官方原始字段名即 domin

响应侧 ResponseHeadercode(0=成功,非 0 失败,msg 含原因)、msgtimestamptrace_iddomin。阻塞式调用另有 blocked / id 字段。

接口鉴权(JWT)

aimdk.protocol.InteractionAuthService/GetInteractionAuthJWT 用于申请交互鉴权 JWT(agent→gateway 方向),返回:

{
  "header": {...}, "auth_jwt_status": 0,   // AuthJWTStatus_SUCCESS=0
  "jwt": "", "expire_at": <毫秒时间戳>
}
auth_jwt_status 取值:SUCCESS=0 / EMPTY=1 / EXPIRE=2jwtexpire_at 有效期,需在过期前刷新;EMPTY 表示尚无可用令牌。MasterAccessControlService.AccessControl 负责多端登陆/权限转移/登出(AccessControlRequestType:BEGIN_LOGIN / CONFIRM_TRANSFER / REFUSE_TO_TRANSFER / ABANDON_APPLY / LOGOUT_APPLY),并广播 RobotLoginStatusChannel + MasterHeartBeatChannel 心跳。多数交互/控制 RPC 建议携带/维护 JWT,具体是否强制以对应 gateway 服务校验为准。

3.6 错误码与告警等级对照

依据 common/rpc.protoCommonState:RPC 响应顶层的 code 非 0 即失败,msg 含原因。

codeCommonState含义 / 处理
0UNKNOWN未知(框架初始占位)
1SUCCESS成功
2FAILURE失败,查 msg
3ABORTED被中止
4TIMEOUT超时,重试或降频
5INVALID入参无效
6IN_MANUAL处于手动/占用态,先释放控制源
100NOT_READY未就绪,稍后重试
200PENDING等待中
300CREATED已创建
400RUNNING运行中

链路告警等级(HDS,AlertLevel,1~13):

级别说明
H1_FATAL(1) / H2_CRITICAL(2) / H2_PERMANENT(3)致命 / 严重 / 永久,须处理后方可继续
H3_ERROR(4) / H3_PERMANENT(5)错误级,通常需人工介入
H4_WARNING(6) / H4_EVENT(7)警告 / 事件
H5_EVENT(8) / H5_TRIVIAL(9) / H5_STATUS(10)次要事件 / 状态
H6_RESERVE(11) / H7_EVENT(12) / H7_DELETE(13)保留 / 已删除事件
实际排查中还会遇到模块内部错误(如关节服务 expected 12 of leg or 3 of waist 提示未全量下发、非 0 的大整型 code 表示该模块自定义错误)。此时以对应服务的 GetAlertList(见 10.1)追加定位。

4. 上肢与运动控制基础

本章介绍运动控制的基础(Action 状态机)以及上肢各部位的控制方法。下肢控制(行走、逐关节、腰部、增强模式、AVATAR)请见 第 5 章 下肢运控与全身逐关节控制

4.1 Action 状态机切换 RPC

运动控制模块地址 10.42.10.12:56322,服务 aimdk.protocol.MotionControlActionService

方法说明Action 限制
GetAvailableActions获取当前所有可用动作列表
GetNextActions获取当前状态下可切换到的动作
GetAction查询当前 Action
SetAction切换运动控制状态机(异步)无(业务上在力控模式间切换)
# 查询当前 Action
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/GetAction' \
     -H 'Content-Type: application/json' -d '{}'
# 切换 Action —— 先 GetAvailableActions/GetNextActions 取列表,再把列表项塞给 command
# 列表项即 MotionControlActionCommand 对象(其 action 为 MotionControlAction 数字枚举),示例取 MOTION=210
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/SetAction' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": "ControlSource_SAFE", "trace_id": "user_example", "domin": ""},
       "command": {"action": 210, "ext_action": "MotionControlAction_MOTION"}
     }'
# 注意:PNC 章节用的是另一个服务 McActionService,其 action 才是字符串枚举(如 McAction_USE_EXT_CMD),勿混用

Action 取值语义

类型Action说明
安全模式(1~99)PASSIVE / DAMPING默认启动态;程序不建议直接切换
位控模式(100~199)PD_STAND关节位置控制(站立等);本身不下发行走速度
力控模式(200~4999)MOTION可行走、做上肢动作、跳舞等;大部分控制 topic 需要此态
力控模式SIT_DOWN / STAND_UP坐下 / 站起(联用)
力控模式LIE_DOWN / GET_UP躺下 / 起身(联用)
力控模式PACKAGE_LIE_DOWN / PACKAGE_GET_UP包装箱躺入 / 起身
力控模式AVATAR身外身模式(遥操作基座)
SetAction 为异步接口,调用后需配合 GetAction 轮询确认生效;实际可切换的目标 Action 以 GetAvailableActions/GetNextActions 实时返回值 + 当前状态为准。

4.2 手臂控制 ROS2 Topic

主题 /motion/control/arm_joint_command,类型 sensor_msgs/JointState仅 MOTION 态。14 个关节固定名称:

left_shoulder_pitch_joint,  left_shoulder_roll_joint, left_shoulder_yaw_joint,
left_elbow_joint,           left_wrist_roll_joint,    left_wrist_pitch_joint,    left_wrist_yaw_joint,
right_shoulder_pitch_joint, right_shoulder_roll_joint,right_shoulder_yaw_joint,
right_elbow_joint,          right_wrist_roll_joint,   right_wrist_pitch_joint,   right_wrist_yaw_joint
msg = JointState()
msg.header.stamp = self.get_clock().now().to_msg()
msg.header.frame_id = "user_McScript"
msg.name = ARM_NAMES        # 上述 14 个名称
msg.position = [0.0]*14
msg.velocity = [0.0]*14
msg.effort   = [0.0]*14

4.3 脖子控制 ROS2 Topic

主题 /motion/control/neck_joint_command仅 MOTION 态,仅支持 位控。仅 2 个关节:

msg.name = ["head_yaw_joint", "head_pitch_joint"]
msg.position = [0.0, 0.2]
# velocity / effort 无实际作用,但必须设置(空会导致运控 crash)
msg.velocity = [0.0, 0.0]
msg.effort   = [0.0, 0.0]

4.4 手指控制 ROS2 Topic

主题 /motion/control/hand_joint_command仅 MOTION 态frame_id 填手部类型(AgiHandO10Hand,缺省 AgiHand)。如 O10 手 20 个关节:

msg.header.frame_id = "O10Hand"
# position 范围 0~2000:0=完全张开,2000=完全并拢
# state 主题 position 范围为 0~4096

4.5 关节状态订阅 ROS2 Topic

以下主题类型为 sensor_msgs/JointState,订阅端 BEST_EFFORT。官方示例 examples/mc/joint_state.py 演示了 arm_joint_state 的订阅,脖子/手指状态 topic 可按同样模式订阅:

主题说明
/motion/control/arm_joint_state手臂关节实时状态
/motion/control/neck_joint_state脖子关节状态(需关闭 motion_player)
/motion/control/hand_joint_state手指关节状态
除行走速度外的关节控制 topic 默认被 motion_player 占用;下发前需在 MDU 关闭 motion_player,关闭后资源管理中的动作内容将无法播放。可用下面的调用启停:
# 停止 motion_player
curl -X POST 'http://127.0.0.1:50080/json/stop_app' -H 'content-type:application/json' -d '{"app_name":"motion_player"}'
# 重启 motion_player
curl -X POST 'http://127.0.0.1:50080/json/start_app' -H 'content-type:application/json' -d '{"app_name":"motion_player"}'

4.6 上肢控制注意事项

motion_player 占用:除行走外的关节 topic 默认被 motion_player 占用。直接控制上肢关节前,请先停掉 motion_player(stop_app motion_player),避免通道冲突。
MOTION 态下上肢摆动:普通 MOTION 档下上肢随步态策略自然摆动,精确控制需切到对应增强模式(如 McAction_RL_LOCOMOTION_ARM_EXT_JOINT_SERVO)。详见 5.5 EXT 增强模式

5. 下肢运控与全身逐关节控制专题

本章集中梳理下肢控制与全身逐关节控制的所有路径、接口、适用场景与前提条件。A3 Ultra 标准配置为 31 DOF(腿 12 + 腰 3 + 头 2 + 臂 14),根据控制方式不同可通过分部位 RPC、分部位 Topic 或 TA 全身通道进行控制。

5.1 下肢控制总览:两条路径

下肢控制有两条完全不同的路径,互斥不可同时使用,请根据场景选择:

维度路径 A:行走速度控制路径 B:逐关节位控
控制粒度双腿整体(前进/横移/转向)单关节独立(12 腿关节 + 3 腰关节)
接口ROS2 Topic(locomotion_velocity)RPC(MotionControlJointService)
前置模式MOTION 即可需 EXT 增强模式(固件依赖)
难度低(一条命令搞定)高(全量下发 + 50Hz 刷新 + 安全考量)
典型场景导航、避障、定点移动吊装实验、动作编排、全身控制
所在小节5.35.4 + 5.5
互斥关系:行走速度通道与下肢逐关节位控互斥——二者不能同时接管双腿。按需二选一。

5.2 31 DOF 全身关节图谱

A3 Ultra 标准全身布局为 TaJointLayout_BODY_31,共 31 个自由度,按部位分类如下。所有关节名、顺序均与 SDK 中 TaWholeBodyCommand / TaWholeBodyState 定义一致。

部位DOF全局序号关节名说明
左腿60left_hip_pitch_joint左髋俯仰
1left_hip_roll_joint左髋横滚
2left_hip_yaw_joint左髋偏航
3left_knee_joint左膝
4left_ankle_pitch_joint左踝俯仰
5left_ankle_roll_joint左踝横滚
右腿66right_hip_pitch_joint右髋俯仰
7right_hip_roll_joint右髋横滚
8right_hip_yaw_joint右髋偏航
9right_knee_joint右膝
10right_ankle_pitch_joint右踝俯仰
11right_ankle_roll_joint右踝横滚
腰部312waist_yaw_joint腰部偏航
13waist_roll_joint腰部横滚
14waist_pitch_joint腰部俯仰
头部215head_yaw_joint头部偏航
16head_pitch_joint头部俯仰
左臂717left_shoulder_pitch_joint左肩俯仰
18left_shoulder_roll_joint左肩横滚
19left_shoulder_yaw_joint左肩偏航
20left_elbow_joint左肘
21left_wrist_roll_joint左腕横滚
22left_wrist_pitch_joint左腕俯仰
23left_wrist_yaw_joint左腕偏航
右臂724right_shoulder_pitch_joint右肩俯仰
25right_shoulder_roll_joint右肩横滚
26right_shoulder_yaw_joint右肩偏航
27right_elbow_joint右肘
28right_wrist_roll_joint右腕横滚
29right_wrist_pitch_joint右腕俯仰
30right_wrist_yaw_joint右腕偏航

记忆口诀:腿 12(左 6 + 右 6)→ 腰 3 → 头 2 → 臂 14(左 7 + 右 7),合计 31。全局顺序与 TaWholeBodyCommand.joint_velocities 一致。

手部扩展:若配置灵巧手,还有 TaJointLayout_BODY_HANDS_55 布局(31 + 双手各 12 = 55 DOF)。SDK 示例 hand.py 中使用 20 个手指关节名(左右手各 10),名称以实际手型为准。

代码示例:Python 关节索引映射

在程序中建议使用索引字典,避免硬编码序号。以下为 31 DOF 完整映射:

# 31 DOF 关节名 → 全局索引 映射字典
# 顺序: leg(12) + waist(3) + head(2) + arm(14)
JOINT_NAME_TO_INDEX = {
    # 左腿 (0-5)
    "left_hip_pitch_joint": 0,
    "left_hip_roll_joint": 1,
    "left_hip_yaw_joint": 2,
    "left_knee_joint": 3,
    "left_ankle_pitch_joint": 4,
    "left_ankle_roll_joint": 5,
    # 右腿 (6-11)
    "right_hip_pitch_joint": 6,
    "right_hip_roll_joint": 7,
    "right_hip_yaw_joint": 8,
    "right_knee_joint": 9,
    "right_ankle_pitch_joint": 10,
    "right_ankle_roll_joint": 11,
    # 腰部 (12-14)
    "waist_yaw_joint": 12,
    "waist_roll_joint": 13,
    "waist_pitch_joint": 14,
    # 头部 (15-16)
    "head_yaw_joint": 15,
    "head_pitch_joint": 16,
    # 左臂 (17-23)
    "left_shoulder_pitch_joint": 17,
    "left_shoulder_roll_joint": 18,
    "left_shoulder_yaw_joint": 19,
    "left_elbow_joint": 20,
    "left_wrist_roll_joint": 21,
    "left_wrist_pitch_joint": 22,
    "left_wrist_yaw_joint": 23,
    # 右臂 (24-30)
    "right_shoulder_pitch_joint": 24,
    "right_shoulder_roll_joint": 25,
    "right_shoulder_yaw_joint": 26,
    "right_elbow_joint": 27,
    "right_wrist_roll_joint": 28,
    "right_wrist_pitch_joint": 29,
    "right_wrist_yaw_joint": 30,
}

# 反向索引:序号 → 关节名
JOINT_INDEX_TO_NAME = {v: k for k, v in JOINT_NAME_TO_INDEX.items()}

# 按部位分组的关节名列表(与 JointCommand 全量下发顺序一致)
LEG_JOINT_NAMES = [
    "left_hip_pitch_joint", "left_hip_roll_joint", "left_hip_yaw_joint",
    "left_knee_joint",
    "left_ankle_pitch_joint", "left_ankle_roll_joint",
    "right_hip_pitch_joint", "right_hip_roll_joint", "right_hip_yaw_joint",
    "right_knee_joint",
    "right_ankle_pitch_joint", "right_ankle_roll_joint",
]  # 12 个

WAIST_JOINT_NAMES = [
    "waist_yaw_joint", "waist_roll_joint", "waist_pitch_joint",
]  # 3 个

ARM_JOINT_NAMES = [
    "left_shoulder_pitch_joint", "left_shoulder_roll_joint",
    "left_shoulder_yaw_joint", "left_elbow_joint",
    "left_wrist_roll_joint", "left_wrist_pitch_joint",
    "left_wrist_yaw_joint",
    "right_shoulder_pitch_joint", "right_shoulder_roll_joint",
    "right_shoulder_yaw_joint", "right_elbow_joint",
    "right_wrist_roll_joint", "right_wrist_pitch_joint",
    "right_wrist_yaw_joint",
]  # 14 个

使用方法:下发前用 LEG_JOINT_NAMES 按顺序构造 12 条 JointCommand,确保全量、顺序正确。

5.3 路径 A:行走速度控制 ROS2 Topic

主题完整名 /motion/control/locomotion_velocity/pb_:aimdk.protocol.MotionControlLocomotionVelocityChannel。按官方示例用 serialization_type="json",需持续高频发布(50Hz),停止发布即停。仅 MOTION 态有效。

{"data": {
  "mode": 0,     // LocomotionMode_DEFAULT = 0
  "forward_velocity": 0.1,   // 前进速度,单位 m/s,正=前
  "lateral_velocity": 0.0,   // 横向速度,单位 m/s,正=左
  "angular_velocity": 0.0    // 角速度,单位 rad/s,正=左转
}}

示例 examples/mc/walk.py 以 0.1 m/s 前进做保守测试(实际速度上限由机器人决定),50Hz 定时以 mode=0(DEFAULT)、前进 0.1(比例系数)发布,目标 2s 共 100 次。data 逐字节拆分填入 RosMsgWrapper.data

行走速度指令驱动的是"双腿整体";如需逐关节独立控制下肢,走 5.3 的关节服务,而非本主题。

5.4 路径 B:逐关节位控(腿部 + 腰部) RPC

服务 aimdk.protocol.MotionControlJointService,RPC 端口 10.42.10.12:56322。允许绕过行走速度通道,逐关节直接下发下肢指令。

前置条件(必看):腰腿逐关节控制在普通 MOTION不会生效(会被内置步态策略覆盖)。必须先确认固件支持 EXT 增强模式并切入对应模式,再操作。详见 5.5 EXT 增强模式

方法总览

方法作用入参 / 返回
GetLegJointState读取腿部关节实时状态CommonRequest → JointStateResponse
SetLegJointCommand下发腿部(下肢)关节指令JointCommandRequest → CommonResponse
GetArmJointState读取手臂关节实时状态CommonRequest → JointStateResponse
SetArmJointCommand下发手臂关节指令JointCommandRequest → CommonResponse
GetWaistJointState读取腰部关节状态CommonRequest → JointStateResponse
SetWaistJointCommand下发腰部关节指令JointCommandRequest → CommonResponse
GetNeckJointState读取脖子关节状态CommonRequest → JointStateResponse
SetNeckJointCommand下发脖子关节指令JointCommandRequest → CommonResponse
GetHandJointState读取手部关节状态CommonRequest → JointStateResponse
SetHandJointCommand下发手部关节指令JointCommandRequest → CommonResponse

JointCommand 字段

JointCommand {
  name       = 关节名称
  sequence   = 关节序号 (0-based)
  position   = 关节角度 (弧度) 或位置 (米)
  velocity   = 关节角速度 (rad/s)
  effort     = 关节扭矩
  stiffness  = 刚度 (N·m/rad)
  damping    = 阻尼 (N·m·s/rad)
}

操作步骤

1
确认 EXT 增强模式可用:GetAvailableActions 确认固件是否开放 McAction_RL_* 增强模式,详见 5.5
2
切入 EXT 增强模式:按 5.4 操作切到对应模式(如 McAction_RL_WHOLE_BODY_EXT_JOINT_SERVO),用 GetAction 确认切换成功。
3
读状态确认关节名:先取回实际关节名与当前位姿,不要盲目下发。
# 腿部
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService/GetLegJointState' \
     -H 'Content-Type: application/json' -d '{}'
# 响应 states[] 含 12 个腿部关节,每个含 name/position/velocity/effort

# 腰部
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService/GetWaistJointState' \
     -H 'Content-Type: application/json' -d '{}'
4
下发腿部关节指令——一次必须全量 12 个(单发会提示 expected 12 of leg)。腿部固定关节名与示例(单位:弧度):
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService/SetLegJointCommand' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "commands": [
         {"name":"left_hip_pitch_joint","sequence":0,"position":0.10,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"left_hip_roll_joint","sequence":1,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"left_hip_yaw_joint","sequence":2,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"left_knee_joint","sequence":3,"position":0.10,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"left_ankle_pitch_joint","sequence":4,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"left_ankle_roll_joint","sequence":5,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_hip_pitch_joint","sequence":6,"position":0.10,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_hip_roll_joint","sequence":7,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_hip_yaw_joint","sequence":8,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_knee_joint","sequence":9,"position":0.10,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_ankle_pitch_joint","sequence":10,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
         {"name":"right_ankle_roll_joint","sequence":11,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0}
       ]
     }'
5
下发腰部关节指令同理,一次必须全量 3 个(单发会提示 expected 3 of waist):
curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService/SetWaistJointCommand' \
     -H 'Content-Type: application/json' \
     -d '{"header":{"control_source":0},"commands":[
       {"name":"waist_yaw_joint","sequence":0,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
       {"name":"waist_roll_joint","sequence":1,"position":0.0,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0},
       {"name":"waist_pitch_joint","sequence":2,"position":-0.15,"velocity":0.0,"effort":0.0,"stiffness":0,"damping":0}
     ]}'

关节名以上述固定名为准;程序中请按 sequence 顺序全量下发并持续高频刷新(推荐 50Hz)。

安全提醒:下肢是整机承重支撑,直接下发关节指令(尤其实力/扭矩/阻抗模式)可能导致失衡跌倒。必须先吊装/降低重心下测试,周围无障碍、备好急停,从"小步幅位置逼近"开始。

5.5 EXT 增强模式详解

EXT 增强模式(McAction_RL_* 系列)是实现下肢逐关节控制的必要前提。它本质是一组"让渡控制权"的运动模式——把特定身体部位(上肢/腰腿/全身)的控制权从内置策略手中让出来,交给外部程序。

重要:EXT 增强模式是高级功能,是否开放取决于固件版本和配置。出厂 v0 固件可能仅开放基础 Action(PASSIVE/MOTION/AVATAR/PD_STAND 等),不包含 McAction_RL_* 系列。请以 GetAvailableActions 返回为准。

增强模式对比(常用 5 种)

模式编号下肢上肢适用场景
LOCOMOTION_DEFAULT301自主行走禁止外部控制基础行走(非增强)
RL_LOCOMOTION_DEFAULT401RL自主行走禁止外部控制RL强化行走
RL_LOCOMOTION_ARM_EXT_JOINT_SERVO402自主行走外部逐关节走路上肢作业
RL_LOCOMOTION_ARM_EXT_PLANNING_MOVE403力控站立外部规划站立上肢作业
RL_WHOLE_BODY_EXT_JOINT_SERVO405外部逐关节外部逐关节外部全身逐关节控制
RL_WHOLE_BODY_EXT_ONLINE_PLANNING407力控站立NMPC 规划外部全身操作规划

上表列举常用 6 种,完整列表以 GetAvailableActions 返回为准。编号 300~499 为 McAction 枚举区间,其中 400+ 为 RL 增强模式。

如何确认固件支持

curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/GetAvailableActions' \
     -H 'Content-Type: application/json' -d '{}'
# 查看 commands[] 中是否包含 McAction_RL_* 开头的枚举

若返回中只有 MotionControlAction_*(PASSIVE/MOTION/AVATAR 等)而无 McAction_RL_*,说明当前固件未开放增强模式,需升级固件或联系官方解锁。

切换方法

通过 MotionControlActionService/SetAction 的扩展命令桥切入:

curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/SetAction' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": "ControlSource_SAFE"},
       "command": {
         "action": 5000,
         "ext_action": "McAction_RL_WHOLE_BODY_EXT_JOINT_SERVO"
       }
     }'

action=5000MotionControlAction_USE_EXT_CMD(扩展命令桥),ext_action 填目标增强模式名。

注意:SetAction 返回 code=0 仅表示请求已受理,不代表切换成功。必须用 GetAction 二次确认当前 Action 是否真的变成了目标模式。若目标模式不可达,SetAction 仍返回成功但状态不变。

切回普通模式

curl -X POST 'http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/SetAction' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": "ControlSource_SAFE", "trace_id": "user_example", "domin": ""},
       "command": {"action": 210, "ext_action": "MotionControlAction_MOTION"}
     }'
# 切回后,腰腿恢复内置策略自主控制

5.6 腰部控制(两种方式对比)

腰部有两条控制路径,分别对应不同场景:

维度move_waist(PB Topic)SetWaistJointCommand(RPC)
接口类型ROS2 TopicRPC
前置模式MOTION 即可需 EXT 增强模式
控制维度yaw/roll/pitch/height 四通道yaw/roll/pitch 三关节
与下肢关系独立控制腰,不影响腿全身 EXT 模式的一部分
适用场景行走时调腰部姿态全身逐关节精确控制
难度

方式一:move_waist(推荐,MOTION 态可用)

主题:/motion/control/move_waist/pb_:aimdk.protocol.MotionControlMoveWaistChannel,PB 序列化,需 context 指定类型。

# MoveWaistChannel 数据字段(WaistMoveValue,比例值 [-1, 1],映射到实际运动范围):
x      = 前后位移 (x)
y      = 左右位移 (y)
z      = 垂直升降 (z)
roll   = 左右倾斜 (roll)
pitch  = 前后俯仰 (pitch)
yaw    = 左右旋转 (yaw)

# 范围(来自 SDK 示例 WAIST_LIMITS,仅供参考,以实际为准):
# pitch:  [-0.50, 0.50] rad  ≈ [-28.6°, +28.6°]
# roll:   [-0.30, 0.30] rad  ≈ [-17.2°, +17.2°]
# yaw:    [-1.57, 1.57] rad  ≈ [-90°, +90°]
# height: [-0.40, 0.00] m    ≈ 下降 40cm / 平齐

PB 发布示例(Python):

from aimdk.protocol.motion_control.move_waist_pb2 import MotionControlMoveWaistChannel
from ros2_plugin_proto.msg import RosMsgWrapper

ch = MotionControlMoveWaistChannel()
ch.yaw, ch.roll, ch.pitch, ch.z = 0.0, 0.0, -0.3, -0.1  # 比例值,z 对应高度
raw = ch.SerializeToString()

wrapper = RosMsgWrapper()
wrapper.serialization_type = "pb"
wrapper.context = ["aimdk.protocol.MotionControlMoveWaistChannel"]
wrapper.data = [bytes([b]) for b in raw]
# publish 到 move_waist topic,持续高频刷新

方式二:SetWaistJointCommand(精确逐关节)

见 5.4 步骤 5。需 EXT 增强模式,直接下发 3 个腰部关节的精确角度。

5.7 备选:AVATAR 全身接管(TA 链路)

若固件未开放 EXT 增强模式,但 GetAvailableActions 中有 MotionControlAction_AVATAR,可考虑走 AVATAR 遥操模式接管全身(含腰腿)。AVATAR 由 TA(Teleop Avatar)模块驱动,设计目标是让外部动作输入源(动捕、VR、骨骼流)实时控制机器人全身。

定位说明:AVATAR / TA 是为动捕 / VR 遥操设计的完整链路,包含标定、会话管理、死人开关、复位等一整套机制。若只需逐关节控制,优先考虑 EXT 增强模式(5.5);AVATAR 仅作为备选路线,接入成本较高。

5.7.1 TaWholeBodyCommand 全身指令通道

TA 通过 topic /ta/whole_body_command60Hz 发布全身运动指令,MC 订阅。消息类型为 TaWholeBodyCommandChannel(PB 格式),核心数据 TaWholeBodyCommand 字段如下:

字段类型维度说明
joint_layout枚举关节布局:BODY_31=1 或 BODY_HANDS_55=2
pelvis_poseTaPelvisPose骨盆位姿(世界坐标系):quat_wxyz + position_xyz
pelvis_velocityTaPelvisVelocity骨盆速度(局部坐标系):linear_xyz + angular_xyz
leg_commandTaLegJointCommand12腿部关节角度(弧度),顺序同关节图谱 0~11
foot_contactTaFootContact足底接触力:left_contact + right_contact + detailed_contacts[16]
waist_commandTaWaistJointCommand3腰部关节角度(弧度),顺序同关节图谱 12~14
head_commandTaHeadJointCommand2头部关节角度(弧度),顺序同关节图谱 15~16
arm_commandTaArmJointCommand14手臂 5 组 14 维:angles_rad + velocities_rad_s + feedforward_efforts + stiffness + damping
left_hand_commandTaHandJointCommand12左手手指(仅 BODY_HANDS_55 布局)
right_hand_commandTaHandJointCommand12右手手指(仅 BODY_HANDS_55 布局)
joint_velocitiesTaJointVelocities31全身关节速度(rad/s),用于 MC 前馈补偿。顺序:leg[0:12] + waist[12:15] + head[15:17] + arm[17:31]

发布方式:构造 TaWholeBodyCommandChannel PB 消息 → SerializeToString() → 封装为 RosMsgWrapper(serialization_type="pb",context=["aimdk.protocol.TaWholeBodyCommandChannel"])→ 发布到 /ta/whole_body_command。参考 5.6 中 move_waist 的 PB 发布模式。

代码示例:Python PB 发布全身指令

以下示例构造 TaWholeBodyCommand 并发布到 /ta/whole_body_command topic,风格与 SDK move_waist.py 一致:

#!/usr/bin/env python3
"""
TA 全身指令发布示例
向 /ta/whole_body_command 以 60Hz 发布 TaWholeBodyCommandChannel (PB)

依赖:
    pip install aimdk-protocol ros2-plugin-proto rclpy
"""
from datetime import datetime, timezone
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSHistoryPolicy, QoSProfile, QoSReliabilityPolicy
from ros2_plugin_proto.msg import RosMsgWrapper

# PB 消息导入
from aimdk.protocol.ta.ta_channel_pb2 import TaWholeBodyCommandChannel
from aimdk.protocol.ta.ta_whole_body_command_pb2 import (
    TaJointLayout,
    TaPelvisPose,
    TaPelvisVelocity,
    TaLegJointCommand,
    TaFootContact,
    TaWaistJointCommand,
    TaHeadJointCommand,
    TaArmJointCommand,
    TaJointVelocities,
)

CONTROL_SOURCE_MANUAL = 1
PUBLISH_RATE = 60  # Hz


def fill_header(header, seq: int) -> None:
    """填充消息头(时间戳、序号、控制源)"""
    now = datetime.now(timezone.utc)
    ts = now.timestamp()
    header.seq = seq
    header.timestamp.seconds = int(ts)
    header.timestamp.nanos = now.microsecond * 1000
    header.timestamp.ms_since_epoch = int(ts * 1000)
    header.control_source = CONTROL_SOURCE_MANUAL


class TaWholeBodyPublisher(Node):
    def __init__(self):
        super().__init__("ta_whole_body_publisher")

        # QoS 与 MC 端订阅保持一致:BEST_EFFORT + KEEP_LAST(10)
        qos = QoSProfile(
            history=QoSHistoryPolicy.KEEP_LAST,
            depth=10,
            reliability=QoSReliabilityPolicy.BEST_EFFORT,
        )
        self.pub = self.create_publisher(
            RosMsgWrapper,
            "/ta/whole_body_command/pb_3Aaimdk_2Eprotocol_2ETaWholeBodyCommandChannel",
            qos,
        )
        self.seq = 0
        self.timer = self.create_timer(1.0 / PUBLISH_RATE, self._on_timer)
        self.get_logger().info(f"TA 全身指令发布器启动,频率 {PUBLISH_RATE}Hz")

    def _build_command(self) -> TaWholeBodyCommandChannel:
        """构造一帧全身指令(站立基准姿态 + 微幅手臂摆动测试)"""
        ch = TaWholeBodyCommandChannel()
        fill_header(ch.header, self.seq)
        cmd = ch.data

        # --- 关节布局:31 DOF ---
        cmd.joint_layout = TaJointLayout.TaJointLayout_BODY_31

        # --- 骨盆位姿(世界坐标系,单位四元数 + 位置) ---
        cmd.pelvis_pose.quat_wxyz.extend([1.0, 0.0, 0.0, 0.0])  # 初始朝向
        cmd.pelvis_pose.position_xyz.extend([0.0, 0.0, 0.0])    # 原点

        # --- 骨盆速度(局部坐标系) ---
        cmd.pelvis_velocity.linear_xyz.extend([0.0, 0.0, 0.0])
        cmd.pelvis_velocity.angular_xyz.extend([0.0, 0.0, 0.0])

        # --- 腿部 12 DOF(站立姿态,双膝微屈) ---
        knee_bend = 0.05  # rad,约 2.9°
        cmd.leg_command.angles_rad.extend([
            0.0, 0.0, 0.0,  knee_bend, 0.0, 0.0,  # 左腿
            0.0, 0.0, 0.0,  knee_bend, 0.0, 0.0,  # 右腿
        ])

        # --- 足底接触(双脚完全接触 = 支撑相) ---
        cmd.foot_contact.left_contact = 1.0
        cmd.foot_contact.right_contact = 1.0
        cmd.foot_contact.detailed_contacts.extend([1.0] * 16)

        # --- 腰部 3 DOF ---
        cmd.waist_command.angles_rad.extend([0.0, 0.0, 0.0])  # yaw, roll, pitch

        # --- 头部 2 DOF ---
        cmd.head_command.angles_rad.extend([0.0, 0.0])  # yaw, pitch

        # --- 手臂 14 DOF(角度 + 速度 + 刚度 + 阻尼) ---
        cmd.arm_command.angles_rad.extend([0.0] * 14)
        cmd.arm_command.velocities_rad_s.extend([0.0] * 14)
        cmd.arm_command.feedforward_efforts.extend([0.0] * 14)
        cmd.arm_command.stiffness.extend([0.0] * 14)  # 0 = 默认刚度
        cmd.arm_command.damping.extend([0.0] * 14)

        # --- 全身关节速度(31 DOF,用于 MC 前馈) ---
        cmd.joint_velocities.velocities_rad_s.extend([0.0] * 31)

        return ch

    def _on_timer(self):
        ch = self._build_command()
        raw = ch.SerializeToString()

        msg = RosMsgWrapper()
        msg.serialization_type = "pb"
        msg.context = ["aimdk.protocol.TaWholeBodyCommandChannel"]
        msg.data = [bytes([b]) for b in raw]

        self.pub.publish(msg)
        self.seq += 1


def main(args=None):
    rclpy.init(args=args)
    node = TaWholeBodyPublisher()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == "__main__":
    main()
Topic 名注意:topic 完整路径中的 PB 类型名会被 URL 编码(如 :_3A._2E)。实际 topic 名以机器人上 ros2 topic list 输出为准。

5.7.2 TA 接入完整流程

TA 模块运行于 service preset 下,所有功能由外部编排。完整接入需以下步骤:

1
标定(InjectCalibration):先完成骨骼标定,使 mocap_calibrated=true。无动捕源时可直接注入标定参数。
curl -X POST '<TA节点IP>:<端口>/rpc/aimdk.protocol.TaService/InjectCalibration' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "normalization_scale": 1.0,
       "left_foot_rotation_z_deg": 0.0,
       "left_foot_rotation_y_deg": 0.0,
       "left_foot_rotation_x_deg": 0.0,
       "right_foot_rotation_z_deg": 0.0,
       "right_foot_rotation_y_deg": 0.0,
       "right_foot_rotation_x_deg": 0.0,
       "left_foot_translation_z": 0.0,
       "right_foot_translation_z": 0.0,
       "torso_limb_translation_z": 0.0
     }'

字段说明:normalization_scale 为骨架归一化缩放系数(1.0 = 未标定基准值);足部旋转/平移偏置为足部补偿参数。具体数值需根据机器人实际标定获取,以上为占位默认值。

2
启动会话(StartSession):标定完成后启动遥操会话,生命周期从 PAUSED → ACTIVE。
curl -X POST '<TA节点IP>:<端口>/rpc/aimdk.protocol.TaService/StartSession' \
     -H 'Content-Type: application/json' -d '{"header": {"control_source": 0}}'
3
切到 AVATAR 模式(SwitchMcAction):要求当前 mc = MOTION 或 PD_STAND。
curl -X POST '<TA节点IP>:<端口>/rpc/aimdk.protocol.TaService/SwitchMcAction' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "target": 1,
       "avatar_mode": 0
     }'
# target: TA_MC_ACTION_AVATAR = 1
# avatar_mode: MotionControlAvatarMode_DEFAULT = 0
4
选择数据源(SelectSource):选择 WBC 数据源。若自己发布 whole_body_command,可选 TA_SOURCE_MOCAP_RETARGET=1(动捕重定向模式)。
# source: TA_SOURCE_MOCAP_RETARGET=1 / MOTION_MATCHING=2 / ACTION_PLAYER=3
5
持续发布全身指令:以 60Hz 向 /ta/whole_body_command 发布 PB 格式的全身指令。
6
上半身模式选择:AVATAR 模式下可选全身绝对(FULL_ABSOLUTE=1)或全身增量(FULL_INCREMENTAL=2)。
7
死人开关(Deadman):持续发布 TaUpperBodyDeadmanCommand(左右扳机量,归一化 [0,1],≥阈值视为按下)。有 TTL 超时机制,停止发布自动归零(松开)。
8
查询状态:通过 GetServiceStatus 或订阅 /ta/service/status 获取完整工作状态。

代码示例:TA 服务 RPC 调用(Python)

以下为 TA 服务 8 步接入流程的 Python 封装(使用 requests 调用 HTTP JSON RPC):

import requests
import time

# TA 服务地址(请替换为实际 TA 节点 IP 和端口)
TA_RPC_BASE = "http://10.42.10.12:56322/rpc/aimdk.protocol.TaService"
# 注:TA 服务端口可能与 MC 不同,具体以实际部署为准


def ta_rpc(method: str, payload: dict) -> dict:
    """通用 TA RPC 调用封装"""
    url = f"{TA_RPC_BASE}/{method}"
    resp = requests.post(url, json=payload, timeout=5)
    resp.raise_for_status()
    return resp.json()


def ta_full_setup():
    """
    TA 全身遥操完整接入流程(8 步)
    前置条件:机器人已上电、MC 在 MOTION 或 PD_STAND 态
    """
    print("=== Step 1: 注入标定参数 ===")
    calib_resp = ta_rpc("InjectCalibration", {
        "header": {"control_source": 0},
        "normalization_scale": 1.0,
        "left_foot_rotation_z_deg": 0.0,
        "left_foot_rotation_y_deg": 0.0,
        "left_foot_rotation_x_deg": 0.0,
        "right_foot_rotation_z_deg": 0.0,
        "right_foot_rotation_y_deg": 0.0,
        "right_foot_rotation_x_deg": 0.0,
        "left_foot_translation_z": 0.0,
        "right_foot_translation_z": 0.0,
        "torso_limb_translation_z": 0.0,
    })
    print(f"  标定注入结果: code={calib_resp.get('header',{}).get('code')}")

    print("=== Step 2: 启动遥操会话 ===")
    start_resp = ta_rpc("StartSession", {"header": {"control_source": 0}})
    print(f"  会话启动结果: code={start_resp.get('header',{}).get('code')}")
    time.sleep(1.0)  # 等待会话就绪

    print("=== Step 3: 切换 MC 到 AVATAR 模式 ===")
    # target=1 = TA_MC_ACTION_AVATAR, avatar_mode=0 = DEFAULT
    switch_resp = ta_rpc("SwitchMcAction", {
        "header": {"control_source": 0},
        "target": 1,
        "avatar_mode": 0,
    })
    print(f"  切换 AVATAR 结果: code={switch_resp.get('header',{}).get('code')}")
    time.sleep(2.0)  # 等待模式切换完成

    print("=== Step 4: 选择数据源(动捕重定向模式) ===")
    # source=1 = TA_SOURCE_MOCAP_RETARGET
    src_resp = ta_rpc("SelectSource", {
        "header": {"control_source": 0},
        "source": 1,
    })
    print(f"  数据源选择结果: code={src_resp.get('header',{}).get('code')}")

    print("=== Step 5: 设置上半身模式(全身绝对) ===")
    # mode=1 = TA_UPPER_BODY_MODE_FULL_ABSOLUTE
    ubm_resp = ta_rpc("SetUpperBodyMode", {
        "header": {"control_source": 0},
        "mode": 1,
    })
    print(f"  上半身模式结果: code={ubm_resp.get('header',{}).get('code')}")

    print("=== Step 6: 查询服务状态确认 ===")
    status = ta_rpc("GetServiceStatus", {"header": {"control_source": 0}})
    print(f"  当前 MC action: {status.get('mc_current_action')}")
    print(f"  接管状态: {status.get('takeover_state')}")
    print(f"  标定状态: {status.get('calibration_state')}")

    print("=== 接入完成,可以开始发布全身指令了 ===")
    print("提示: 持续发布 /ta/whole_body_command(60Hz) + /ta/upper_body_deadman_command")


if __name__ == "__main__":
    ta_full_setup()
注意:TA 服务 RPC 端口不一定是 56322(那是 MC 端口)。TA 作为独立服务运行,端口需根据实际部署确认。可通过 GetServiceStatus 返回的 mc_current_action 判断是否切到了 AVATAR。

5.7.3 全身复位(WholeBodyReset)

进入 AVATAR 后可播放内置全身复位动作,使机器人回到安全姿态后再切换运动模式:

复位类型枚举值说明
原地踏步TA_WHOLE_BODY_RESET_TYPE_YUANDITABU = 1原地踏步类复位动作(默认)
拳击TA_WHOLE_BODY_RESET_TYPE_BOXING = 2拳击类复位动作

复位状态机:IDLE → STARTING → RUNNING → SUCCEEDED(成功)/ FAILED / CANCELED / TIMED_OUT。

安全切换:复位完成后需同时满足 whole_body_reset_state=SUCCEEDEDsafe_to_switch_motion=true,才能切换 MC action。safe_to_switch_motion 表示复位动作自然完成、末帧已发布、旧输出已释放,可安全切换。

代码示例:全身复位调用

AVATAR 模式下播放内置复位动作,完成后安全切回 MOTION:

def ta_whole_body_reset_and_exit():
    """播放全身复位动作 → 等待完成 → 切回 MOTION"""
    print("=== 启动全身复位(原地踏步) ===")
    # reset_type=1 = TA_WHOLE_BODY_RESET_TYPE_YUANDITABU
    ta_rpc("StartWholeBodyReset", {
        "header": {"control_source": 0},
        "reset_type": 1,
    })

    # 轮询等待复位完成
    print("等待复位完成...", end="", flush=True)
    timeout = 30  # 最长等 30 秒
    for i in range(timeout * 2):  # 2Hz 轮询
        time.sleep(0.5)
        status = ta_rpc("GetServiceStatus", {"header": {"control_source": 0}})
        reset_state = status.get("whole_body_reset_state", "IDLE")
        safe = status.get("safe_to_switch_motion", False)
        print(f".", end="", flush=True)

        # 复位成功且可安全切换
        if reset_state == "SUCCEEDED" and safe:
            print("\n复位完成,安全切换就绪")
            break

        # 异常状态
        if reset_state in ("FAILED", "CANCELED", "TIMED_OUT"):
            print(f"\n复位异常: {reset_state}")
            return False
    else:
        print("\n复位超时")
        return False

    # 切回 MOTION 模式
    print("=== 切回 MOTION 模式 ===")
    # target=2 = TA_MC_ACTION_MOTION
    ta_rpc("SwitchMcAction", {
        "header": {"control_source": 0},
        "target": 2,
    })
    time.sleep(2.0)
    return True

5.7.4 上半身控制模式(UpperBodyMode)

模式枚举值前置条件说明
FULL_ABSOLUTE1mc=AVATAR全身绝对遥操
FULL_INCREMENTAL2mc=AVATAR全身增量遥操
UPPER_BODY_INCREMENTAL3mc=MOTION半身增量遥操(上半身)
UPPER_BODY_ABSOLUTE4mc=MOTION半身绝对遥操(上半身)

5.7.5 TA 服务方法速查

类别方法说明
生命周期StartSession启动会话(需先标定)
PauseSession暂停会话
标定StartCalibrationT-pose 标定(需骨骼流)
InjectCalibration直接注入标定参数
MC 切换SwitchMcActionAVATAR / MOTION / PASSIVE / PD_STAND
姿态转换RunPostureTransition趴下 / 起身(独占)
急停EmergencyStop急停(→ EMERGENCY_STOPPED)
EmergencyClear清除急停(→ PAUSED)
数据源SelectSourcemocap_retarget / motion_matching / action_player
上半身模式SetUpperBodyMode全身/半身 × 绝对/增量
全身复位StartWholeBodyReset原地踏步 / 拳击
状态查询GetServiceStatus完整工作状态

5.8 全身关节状态读取

获取机器人当前关节状态有两种方式:RPC 拉取(按部位,适合调试)和 Topic 订阅(全身/分部位,适合实时控制闭环)。

方式一:RPC 拉取(按部位)

服务 MotionControlJointService(MDU:56322)提供 5 个部位的状态查询:

方法返回关节数
GetLegJointStateJointStateResponse12
GetArmJointStateJointStateResponse14
GetWaistJointStateJointStateResponse3
GetNeckJointStateNeckStateResponse2
GetHandJointStateHandStateResponse视手型

每个 JointState 含字段:name / sequence / position / velocity / effort

方式二:Topic 订阅

Topic消息类型说明
/motion/control/arm_joint_statesensor_msgs/JointState手臂关节状态(ROS2 原生)
/motion/control/neck_joint_statesensor_msgs/JointState脖子关节状态(ROS2 原生)
/wbc/whole_body_stateTaWholeBodyStateChannel全身关节状态(PB,TA/WBC 输出,含 IMU)

/wbc/whole_body_state 是结构化全身状态消息,含 leg_state / waist_state / head_state / arm_state / pelvis_imu / torso_imu 六部分,每个部位为 repeated JointState。适合需要全身状态闭环的场景。

代码示例 1:RPC 拉取腿部状态(Python)

import requests

MC_JOINT_RPC = "http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService"


def get_leg_joint_state() -> list[dict]:
    """
    读取腿部 12 关节实时状态。

    返回:
        list[dict],每个 dict 含 name/sequence/position/velocity/effort
    """
    resp = requests.post(
        f"{MC_JOINT_RPC}/GetLegJointState",
        json={},
        timeout=3,
    )
    resp.raise_for_status()
    data = resp.json()
    states = data.get("states", [])

    # 打印格式化结果
    print(f"=== 腿部关节状态(共 {len(states)} 个) ===")
    for s in states:
        print(f"  [{s['sequence']:2d}] {s['name']:30s}  "
              f"pos={s['position']:+.4f} rad  "
              f"vel={s['velocity']:+.4f} rad/s  "
              f"eff={s['effort']:+.4f} N·m")
    return states


def get_all_joint_state() -> dict:
    """一次性读取所有部位关节状态"""
    methods = {
        "leg":   "GetLegJointState",
        "arm":   "GetArmJointState",
        "waist": "GetWaistJointState",
        "neck":  "GetNeckJointState",
    }
    result = {}
    for part, method in methods.items():
        resp = requests.post(f"{MC_JOINT_RPC}/{method}", json={}, timeout=3)
        result[part] = resp.json().get("states", [])
    return result


if __name__ == "__main__":
    get_leg_joint_state()

代码示例 2:订阅 /wbc/whole_body_state(Python ROS2)

#!/usr/bin/env python3
"""
订阅全身关节状态 /wbc/whole_body_state (PB)
"""
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSHistoryPolicy, QoSProfile, QoSReliabilityPolicy
from ros2_plugin_proto.msg import RosMsgWrapper

from aimdk.protocol.ta.ta_whole_body_state_pb2 import (
    TaWholeBodyStateChannel,
    TaWholeBodyState,
)


class WholeBodyStateSubscriber(Node):
    def __init__(self):
        super().__init__("whole_body_state_sub")

        qos = QoSProfile(
            history=QoSHistoryPolicy.KEEP_LAST,
            depth=10,
            reliability=QoSReliabilityPolicy.BEST_EFFORT,
        )
        self.sub = self.create_subscription(
            RosMsgWrapper,
            "/wbc/whole_body_state/pb_3Aaimdk_2Eprotocol_2ETaWholeBodyStateChannel",
            self._on_msg,
            qos,
        )
        self.get_logger().info("等待全身状态消息...")

    def _on_msg(self, msg: RosMsgWrapper):
        # 反序列化 PB 数据
        raw = b"".join(msg.data)
        ch = TaWholeBodyStateChannel()
        ch.ParseFromString(raw)
        state: TaWholeBodyState = ch.data

        # 打印关键信息(示例:只打印腿部+骨盆 IMU)
        leg_count = len(state.leg_state.states)
        knee_left  = state.leg_state.states[3].position   # left_knee
        knee_right = state.leg_state.states[9].position   # right_knee

        pelvis_quat = list(state.pelvis_imu.quat_wxyz[:4])

        self.get_logger().info(
            f"全身状态: 腿={leg_count}关节, "
            f"左膝={knee_left:+.3f}rad, 右膝={knee_right:+.3f}rad, "
            f"骨盆四元数=[{pelvis_quat[0]:.3f}, {pelvis_quat[1]:.3f}, "
            f"{pelvis_quat[2]:.3f}, {pelvis_quat[3]:.3f}]"
        )


def main(args=None):
    rclpy.init(args=args)
    node = WholeBodyStateSubscriber()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == "__main__":
    main()

TaWholeBodyState 包含六个部位:leg_state / waist_state / head_state / arm_state / pelvis_imu / torso_imu。每个部位的 states 数组中,JointStatename / sequence / position / velocity / effort 五个字段。

5.9 控制接口与 Action 模式对应总表

不同控制接口有不同的 Action 模式前提。下表汇总全身各部位的控制接口、所需 Action 模式、以及备注:

身体部位接口类型所需 Action 模式备注
行走(双腿整体)locomotion_velocity topicTopic JSONMOTION最常用,整体行走
PNC 导航接口RPCRL_LOCOMOTION_DEFAULT自主导航
腿部逐关节SetLegJointCommandRPCRL_WHOLE_BODY_EXT_JOINT_SERVO需 EXT 增强模式
TaWholeBodyCommand.leg_commandTopic PBAVATARTA 遥操链路
腰部move_waist topicTopic PBMOTION四通道比例值,最简单
SetWaistJointCommandRPCRL_WHOLE_BODY_EXT_JOINT_SERVO需 EXT 增强模式,精确 3 关节
手臂arm_joint_command topicTopicMOTION(随动)/ EXT(精确)MOTION 下随步态摆动
SetArmJointCommandRPCRL_LOCOMOTION_ARM_EXT_* 或 405/407精确上肢控制
脖子neck_joint_command topicTopicMOTIONvelocity/effort 必须设置(0 也可)
手指hand_joint_command topicTopicMOTION视手型配置(AgiHand / O10Hand)
全身 31 DOFTaWholeBodyCommandTopic PBAVATARTA 遥操链路,60Hz
经验法则:只控手臂/脖子/手 → MOTION 态 topic 即可;控腰部 → 用 move_waist(MOTION 态);控腿部/全身逐关节 → 需要 EXT 增强模式或 AVATAR。

代码示例:模式切换完整闭环(MOTION → EXT → 控制 → 回 MOTION)

以下为完整的模式切换 + 控制 + 回退流程示例,可作为开发脚手架:

import requests
import time

MC_ACTION_RPC = "http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService"
MC_JOINT_RPC  = "http://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlJointService"
CONTROL_SOURCE = 0  # ControlSource_SAFE


def get_action() -> str:
    """获取当前 MC Action"""
    resp = requests.post(f"{MC_ACTION_RPC}/GetAction", json={}, timeout=3)
    return resp.json().get("state", {}).get("action", "UNKNOWN")


def set_ext_action(ext_action_name: str) -> bool:
    """
    切入 EXT 增强模式。
    action=5000 = MotionControlAction_USE_EXT_CMD(扩展命令桥)
    """
    resp = requests.post(
        f"{MC_ACTION_RPC}/SetAction",
        json={
            "header": {"control_source": CONTROL_SOURCE,
                       "trace_id": "user_demo", "domin": ""},
            "command": {
                "action": 5000,
                "ext_action": ext_action_name,
            },
        },
        timeout=3,
    )
    # SetAction 返回成功仅表示受理,需二次确认
    if resp.json().get("header", {}).get("code") != 0:
        print(f"SetAction 请求被拒绝: {resp.json()}")
        return False
    return True


def wait_for_action(target_action_keyword: str, timeout: float = 10.0) -> bool:
    """轮询等待 Action 切换完成"""
    deadline = time.time() + timeout
    while time.time() < deadline:
        current = get_action()
        if target_action_keyword in current:
            print(f"  ✓ 已切换到 {current}")
            return True
        time.sleep(0.5)
    print(f"  ✗ 切换超时,当前: {get_action()}")
    return False


def ext_joint_control_demo():
    """
    完整流程:
    MOTION → EXT 全身逐关节 → 控制测试 → 回 MOTION
    """
    # --- Step 1: 确认当前在 MOTION ---
    current = get_action()
    print(f"当前 Action: {current}")
    if "MOTION" not in current:
        print("错误:需先处于 MOTION 模式")
        return

    # --- Step 2: 切入 EXT 增强模式 ---
    ext_mode = "McAction_RL_WHOLE_BODY_EXT_JOINT_SERVO"
    print(f"\n切入 EXT 模式: {ext_mode}")
    if not set_ext_action(ext_mode):
        return
    if not wait_for_action("EXT_JOINT_SERVO", timeout=10):
        print("切换失败,终止")
        return

    # --- Step 3: 控制(示例:双膝微屈 0.05rad) ---
    print("\n下发腿部关节指令(微屈膝测试)")
    knee_bend = 0.05
    positions = [
        0.0, 0.0, 0.0,  knee_bend, 0.0, 0.0,  # 左腿
        0.0, 0.0, 0.0,  knee_bend, 0.0, 0.0,  # 右腿
    ]
    leg_cmd = build_leg_joint_request(positions)  # 见 5.4 辅助函数
    # 转 JSON 格式
    cmd_json = {
        "header": {"control_source": CONTROL_SOURCE},
        "commands": [
            {"name": c["name"], "sequence": c["sequence"],
             "position": c["position"], "velocity": c["velocity"],
             "effort": c["effort"], "stiffness": c["stiffness"],
             "damping": c["damping"]}
            for c in [
                {"name": LEG_JOINT_NAMES[i], "sequence": i,
                 "position": positions[i], "velocity": 0.0,
                 "effort": 0.0, "stiffness": 0.0, "damping": 0.0}
                for i in range(12)
            ]
        ]
    }
    resp = requests.post(
        f"{MC_JOINT_RPC}/SetLegJointCommand",
        json=cmd_json,
        timeout=3,
    )
    print(f"  下发结果: code={resp.json().get('header',{}).get('code')}")

    # 持续发布 3 秒(50Hz = 约 150 帧)
    print("  持续发布 3s...")
    for _ in range(150):
        requests.post(
            f"{MC_JOINT_RPC}/SetLegJointCommand",
            json=cmd_json,
            timeout=3,
        )
        time.sleep(0.02)
    print("  发布完成")

    # --- Step 4: 切回 MOTION ---
    print("\n切回 MOTION 模式")
    resp = requests.post(
        f"{MC_ACTION_RPC}/SetAction",
        json={
            "header": {"control_source": CONTROL_SOURCE,
                       "trace_id": "user_demo", "domin": ""},
            "command": {"action": 210,
                        "ext_action": "MotionControlAction_MOTION"},
        },
        timeout=3,
    )
    if wait_for_action("MOTION", timeout=10):
        print("✓ 已安全回到 MOTION 模式")
    else:
        print("⚠ 回切超时,请手动检查")


if __name__ == "__main__":
    ext_joint_control_demo()
务必遵守:任何 EXT 模式操作前,先吊装测试;持续高频刷新关节指令(50Hz),停止发布可能导致关节位置漂移;回退时务必确认切回 MOTION 后再退出程序。

5.10 常见问题与排查

现象可能原因排查 / 解决
行走 topic 发了不动不在 MOTION 态 / QoS 不匹配 / 模式字段错GetAction 确认 MOTION;mode 应=10(DEFAULT);检查 QoS
SetLegJointCommand 返回 expected 12 of leg只发了部分关节腿必须一次全量 12 个,腰必须一次全量 3 个
腰腿 RPC 返回 SUCCESS 但关节不动处于普通 MOTION 档,被策略覆盖先切 EXT 增强模式;GetAction 确认切换成功
SetAction 返回成功但 GetAction 不变目标 Action 不可达(固件未开放)GetAvailableActions 确认枚举是否存在;无则需升级固件
GetAvailableActions 里没有 McAction_RL_*当前固件未开放增强模式联系官方升级固件 / 解锁配置
腰部 move_waist 发了没反应不在 MOTION 态 / 数值超限 / PB 序列化错确认 MOTION 态;检查数值范围;确认 context 填对
AVATAR 切不过去前置条件不满足(未标定/未启会话)先 InjectCalibration → StartSession → 再 SwitchMcAction

排查顺序口诀:先看 Action 对不对 → 再看模式支不支持 → 最后查命令格不格式。

6. 底盘 / 地图 / 导航

5.1 地图管理 RPC

地图模块地址 10.42.10.11:50807,服务 aimdk.protocol.MappingServiceaimdk.protocol.LocalizationService

方法作用关键入参
GetStoredMapNames获取已存储地图列表command=MappingCommand_GET_STORED_MAP_NAME
GetCurrentWorkingMap获取当前工作地图 IDcommand=MappingCommand_GET_CURRENT_WORKING_MAP
SetCurrentWorkingMap设置当前工作地图map_id
Get2DWholeMap获取 2D 地图数据
StartMapping开始建图command=MappingCommand_START_MAPPING、no_realtime_data
StopMapping停止建图并保存command=MappingCommand_STOP_MAPPING
GetRealtimeMapData实时建图数据command=MappingCommand_GET_REALTIME_MAP
RenameMap重命名地图map_id + new name
SyncRegion修改地图
LocalizationService/GetTopoMsgs获取地图拓扑(导航点)map_id
# 获取地图列表
curl -X POST 'http://10.42.10.11:50807/rpc/aimdk.protocol.MappingService/GetStoredMapNames' \
     -H 'Content-Type: application/json' \
     -d '{"header":{},"command":"MappingCommand_GET_STORED_MAP_NAME"}'

# 开始建图
curl -X POST 'http://10.42.10.11:50807/rpc/aimdk.protocol.MappingService/StartMapping' \
     -H 'Content-Type: application/json' \
     -d '{"header":{},"command":"MappingCommand_START_MAPPING","no_realtime_data":true}'

5.2 定位与重定位 RPC

导航前需定位成功,可全局或手动重定位:

方法说明
RelocalizationService/StartGlobalRelocalization全局重定位,入参 map_id
SLAMRelocalizationService/SLAMStartNormalRelocalization手动重定位,入参 related_map_dir

手动重定位结果可用 /slam/localization/odometry 验证。

5.3 规控导航(PNC) RPC

PNC 服务地址 10.42.10.11:53176,服务 aimdk.protocol.PncService。执行前置条件:

  • 重定位成功,且任务地图 ID 与重定位地图一致。
  • MC 已切换到 McAction_RL_LOCOMOTION_DEFAULT 运动态(PNC 示例经 ADU 的 McActionService/SetAction 切换,地址 10.42.10.11:56322;与 MDU 的MotionControlActionService 是两个不同服务,勿混淆)。
方法作用关键入参
PlanningNaviToGoal规划导航到拓扑目标点task_id, map_id, target_id, guide_line_id, ackerman_mode
PlanningNaviToPose2D规划导航到 2D 位姿map_id, pose{position{x,y}, angle}
LinearNaviToRelative线性相对导航
LinearNaviToGoal线性导航到目标点
PreciseNaviToGoal精确导航到目标点
DirectNaviToRelativeGoal直接相对导航map_id, target_id
SpinTurn原地转向
SpinTurnAndMoveForward转身后前进
MoveForward前进map_id, angle, distance
# 规划导航到 2D 位姿
curl -X POST 'http://10.42.10.11:53176/rpc/aimdk.protocol.PncService/PlanningNaviToPose2D' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "task_id": 0,
       "map_id": 1,
       "pose": {"position": {"x":10.0, "y":5.0}, "angle": 3.14159},
       "ackerman_mode": false
     }'
# 前置:确认/切入 RL_LOCOMOTION_DEFAULT(pnc_demo 经 ADU 的 McActionService 操作,非运动状态机服务)
curl -X POST 'http://10.42.10.11:56322/rpc/aimdk.protocol.McActionService/SetAction' \
     -H 'Content-Type: application/json' \
     -d '{"command": {"action": 5000, "ext_action": "McAction_RL_LOCOMOTION_DEFAULT"}}'

导航任务控制

方法作用
ActionCancel取消任务(入参 task_id)
ActionPause暂停任务
ActionResume恢复任务
ActionGetState查询任务状态(task_id → state)

返回状态:IDLE / RUNNING / PAUSED / SUCCESS / FAILED(示例使用 PncServiceState_*)。完整可交互 demo 见 examples/pnc/pnc_demo.py,包含"取地图→取拓扑→选点→切 Action→下发→轮询→取消"全链路。

7. Agent 语音交互

6.1 TTS 语音合成 RPC

服务 aimdk.protocol.TTSService,地址 10.42.10.10:59301

# 播报一段文本(文本上限约 1024 字节 / ~200 个中英文字符)
curl -X POST 'http://10.42.10.10:59301/rpc/aimdk.protocol.TTSService/PlayTTS' \
     -H 'Content-Type: application/json' \
     -d '{
       "text":"你好,我是智元远征 A3 Ultra",
       "priority_level":"INTERACTION_L6",
       "domain":"example",
       "trace_id":"demo_trace_001",
       "is_interrupted":true
     }'

6.2 音频文件播放 RPC

同服务 PlayMediaFile。支持 16kHz / 16bit / 单声道 PCM,以及带标准 44 字节头 Linear PCM 的 WAV。

curl -X POST 'http://10.42.10.10:59301/rpc/aimdk.protocol.TTSService/PlayMediaFile' \
     -H 'Content-Type: application/json' -d '{"file_name":"/path/to/audio.wav"}'
传入错误或不存在的文件名会静默失败is_success 仍可能为 true,需自行校验文件。

6.3 播放状态与打断 RPC + Topic

状态查询:RPC GetAudioStatus;实时状态订阅主题 /interaction/tts_status/pb_3Aaimdk_2Eprotocol_2ETTSStatus(PB)。状态枚举:Begin / Playing / End / Stop / Error / InQue / NOTInQue

打断:RPC StopTTSTraceId,按 trace_id 打断单个播放。

# 订阅 TTS 状态(PB 反序列化)
from aimdk.protocol.interaction.tts_service_pb2 import TTSStatus
raw = b"".join(msg.data)
st = TTSStatus(); st.ParseFromString(raw)

6.4 麦克风与唤醒 RPC + Topic

接口类型说明
AgentControlService/SetVoiceEnableRPC设置静默模式(false=静音/禁音)
AgentControlService/GetVoiceEnableRPC查询静默模式
AgentControlService/SetAgentPropertiesRequest / GetAgentPropertiesRequestRPC设置/查询交互运行模式
HalAudioService/SetMicSourceRequest / GetMicSourceRequestRPC切换内/外置麦克风
/agent/process_audio_outputTopic降噪麦克音频输出
/agent/wakeup/pb_...(WakeUpResult)Topic唤醒结果上报
# 关闭语音(静默)
curl -X POST 'http://10.42.10.10:59301/rpc/aimdk.protocol.AgentControlService/SetVoiceEnable' \
     -H 'Content-Type: application/json' -d '{"enable_voice": false}'

7.5 音频焦点 ROS2 Service

A3 Ultra 通过 Service 串音聚焦权限,申请/释放播放权:

# 申请
ros2 service call /audio_5Fmsgs/srv/RequestAudioFocus audio_msgs/srv/RequestAudioFocus \
  "{focus_requester: {pkg_name: my_app, priority: 6, priority_weight: 1}}"
# 释放
ros2 service call /audio_5Fmsgs/srv/AbandonAudioFocus audio_msgs/srv/AbandonAudioFocus '{}'

流式音频播放主题 /audiohal/audio/playback,入参含 pkg_name / priority / priority_weight / channels / sample_rate / sample_format / coding_format / audio_bytes

8. 资源管理

服务 aimdk.protocol.ResourceService,地址 10.42.10.10:51049。开放六类资源:动作、表情、音频、技能、地图、创作作品。

资源导入前提:把数据放入 HDU 临时目录 /agibot/data/resources/tmp,再通过 RPC 触发同步;重启后 tmp 会被清空。系统持久化到 /agibot/data/resources/custom/agibot/data/resources/default
方法作用
CreateResource创建资源
DeleteResource删除资源
UpdateResource更新资源
GetResourceList获取资源列表
GetResource查询单个资源
ResourceMigrationOut / ResourceMigrationIn资源迁出 / 迁入(如地图导入)
GetResourceMigrationTaskStatus迁移状态查询
# 创建表情资源(emoticon_extra_info 指向 tmp 目录下的文件)
curl -X POST 'http://10.42.10.10:51049/rpc/aimdk.protocol.ResourceService/CreateResource' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "resource": {
         "resource_name":"我的表情",
         "resource_type":"RESOURCE_TYPE_EMOTICON",
         "tags":["测试"],
         "emoticon_extra_info":{
           "emoticon_file_url":"tmp/emoticon.mp4",
           "thumbnail_file_url":"tmp/thumbnail.mp4",
           "cover_file_url":"tmp/cover.png"
         }
       }
     }'

各资源类型示例见 examples/resource_manager/CreateResource.py,涵盖 motion / emotion / audio / offring_work(创作作品,对应枚举 RESOURCE_TYPE_OFFRING_WORK,可组合动作+表情+音频,支持 NormalMotionWholeBodyDance)。

9. 技能播放

8.1 动作播放 RPC

服务 aimdk.protocol.MotionCommandService/SendMotionCommand,地址 10.42.10.12:56444。播放/停止/暂停/下一个均走同一接口,通过字段组合控制:

# 播放一个 .mcap 动作
curl -X POST 'http://10.42.10.12:56444/rpc/aimdk.protocol.MotionCommandService/SendMotionCommand' \
     -H 'Content-Type: application/json' \
     -d '{
       "motion_id":"/agibot/data/resources/default/motion/演讲10s/演讲10s.mcap",
       "duration_ms":10000,
       "cmd_end":true, "cmd_pause":false, "cmd_reset":false
     }'

# 停止动作(motion_id 置空,cmd_reset=true)
{"motion_id":"","duration_ms":10000,"cmd_end":true,"cmd_pause":false,"cmd_reset":true}

# 播放列表下一个(motion_id="next_motion")

8.2 表情播放 ROS2 Topic

主题 /skill/pilot/face/play/pb_3Aaimdk_2Eprotocol_2EHFAEmoction,PB 载荷。字段含 e_path / e_id / repeat / priority / is_stop

emotion = HFAEmoction()
emotion.e_path = "/agibot/data/resources/default/emoticon/disable_voice/emoticon.mp4"
emotion.e_id = 15
emotion.repeat = 1
emotion.priority = 440
emotion.is_stop = False
默认经 iceoryx 传输;如需标准 ROS2 Topic 形式,需在 skillpilot.yaml 中将 /skill/pilot/face/play/skill/pilot/skill_status 的通信形式改为 [mqtt, ros2] 并重启机器人。

8.3 舞蹈 RPC

服务 aimdk.protocol.SkillPilotService/SkillPackage,地址 10.42.10.12:52893。V3.2 新增舞蹈播放:

curl -X POST 'http://10.42.10.12:52893/rpc/aimdk.protocol.SkillPilotService/SkillPackage' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"timestamp": {"seconds":"0","nanos":0,"ms_since_epoch":"0"}},
       "source":"custom",
       "command":"Start",
       "path":"/agibot/data/resources/default/skill/查尔斯顿舞",
       "session_id":"12333"
     }'
舞蹈播放需保证机器人周围两米内无障碍;自主充电(SkillPilotService/AutoCharging)执行前请确认地图已就绪、处于可移动姿态区,并根据设备提示核对充电桩位姿。

另提供 SkillPilotService/AutoCharging(自主充电)等接口,接口入参与返回字段以上述 skill_play 示例为准。

10. 系统状态与故障诊断

10.1 告警查询 RPC

服务 aimdk.protocol.HDSService,地址 10.42.10.12:50587。推荐主接口 GetAlertList(0.2Hz 内查询)。

curl -X POST 'http://10.42.10.12:50587/rpc/aimdk.protocol.HDSService/GetAlertList' \
     -H 'Content-Type: application/json' -d '{}'
字段含义
id / alert_code告警唯一标识 / 告警码
stateAlertState_ACTIVE / AlertState_CLEARED
levelH1_FATAL 级到 H7_EVENT / H7_DELETE 级
appeared_timestamp / disappeared_timestamp出现 / 消失时间
description / alert_text / alert_module描述文本与模块

其他:GetTotalAlertListGetAlertCountGetExceptionEvent(较冗杂,优先 GetAlertList)。

10.2 BMS 电池状态 ROS2 Topic

主题 /aima/bms/data/pb_3Aaimdk_2Eprotocol_2EBmsStateChannel,PB 载荷,订阅端 BEST_EFFORT。常用关键字段:voltage / current / power / temperature / capacity / charge / cycles_num / power_supply_status / charger_state / bms_state(毫、微、十分位缩放需按要求换算,见示例 examples/other/bms.py)。

扩展字段还包括:ver / power_supply_health / cycles_capacity / abnormal_state / max_current / battery_firmware_type / battery_pack_state / battery_comm_state / charger_output_state / battery_full_state 等,具体以 BmsState proto 定义为准。

10.3 急停与系统状态(含复位) Topic

急停主题 /hal_state/emergency/pb_3Aaimdk_2Eprotocol_2EEmergencyStateChannel。系统模式包含 EStop:其 active 列表含 EStop + Motion,触发时 deactivate mcactivate motion_player。系统模式/工作模式相关 Topic 见 aimdk.protocol.hal.state.*mc.base.work_mode

急停复位完整流程

触发急停后(物理急停按钮 / SystemService.TriggerEStop),MC 进入 deactivate、机器人不可运动。恢复前先确认危险已排除,再按序复位:

1
确认急停状态已检出:订阅 EmergencyStateChannelHalEmergencyService.GetEmergencyState 确认 reason 非空。
2
解除系统急停:调用 SYSTEM RELEASE E-STOPSystemService.ReleaseEStop)释放软件急停;若由物理按钮触发,先复位实体急停按钮。
3
恢复运动:确认无 HDS 致命/严重告警(GetAlertList,见 10.1)后,重新 activate mc;再按需 deactivate motion_player(若此前被策略占用,见 0.5)。
4
切回运动态:SetAction 重新切入目标 Action(如 MOTION),并用 GetAction 确认生效后再生效下发。
未排除危险前不得 ReleaseEStop / 重新 activate mc;复位后先用最小速度在吊装/低速场景验证,确认无异常再恢复正常作业。

10.4 音频音量 RPC

服务 aimdk.protocol.HalAudioService,地址 10.42.10.10:56666GetAudioVolume / SetAudioVolume。另同服务 PlayFile/StopPlay 播放 /agibot/data/var/hal_audio/file/ 下音频(WAV 自带格式头;PCM 需传 channels 与 samplerate)。

11. 高级能力域(感知 / 具身 / 多机 / 系统管理)

本章覆盖运动/语音/导航之外的进阶能力:环境感知、具身操作(机械臂抓取 / 任务引擎)、多机群组(linkswarm)与系统管理(设置 / OTA / 紧急模式)。这些协议子包在 SDK protocol/protobuf 下真实存在,但多数没有官方可运行示例,字段以后文为准、接口参数以对应模块实际发布格式为准。

除机械臂操作(ManipulationService 明确端口 39110)外,本章各服务未在 SDK 中标注公开 RPC 端口,调用地址以对应模块在机器人上的实际发布为准;其中感知类通常承载于 ADU,相机等传感器承载于 HDU。

10.1 环境感知(perception / camera / sensors)

感知协议位于 aimdk.protocol.perception.*,相机与传感器位于 aimdk.protocol.hal.camera.* / hal.sensors.*

感知层(perception/perception_service.proto

服务方法作用 / 关键入参
PerceptionServiceAddMultiScaleObjects注入多尺度目标(MultiScaleObjectsRequest)→ CommonResponse
PerceptionServiceSendEnvObjInfos下发环境物体信息(EnvObjectArrayInfoReq)→ CommonResponse
Object2dDetectionServiceGet2dDection2D 目标检测(header, camera_id, image, target_type)→ box2d
Object6dPoseEstimationServiceGet6dPose6D 位姿估计(header, camera_id, image, target_type)→ box2d, bbox6d
Object6dPoseEstimationServiceStartMultiTracking / SetMultiTrackingIds多目标跟踪启停 / 设定跟踪目标(prompts / obj_ids)
TargetGuidanceServiceGetTargetPoint / SetTargetPoint目标点获取 / 设定(type, pose_map);返回值含 TargetPointFailureReason 失败原因枚举

目标类型枚举 TargetType:DETECT_UNKNOWN / PLASTIC_BOX / METAL_SHELF;目标点类型 TargetPointType:TPT_UNKNOWN / TPT_COARSE_POINT / TPT_FINE_POINT。

相机与实时图像(hal/camera & hal/sensors

服务方法作用
HalCameraServiceGetCameraIntrinsicsState / TakeShot / GetCameraMetrics / EnableCameraImgTopic相机内参 / 单帧拍照 / 指标 / 使能图像主题(open_dma_topic)
HalCameraFirmwareServiceGetCameraFirmwareVersion相机固件版本
CameraServiceGetCameraInfo / GetCameraData相机信息 / 取图(name, stream_type,返回 color_info / color_image / depth_info / depth_image)
CameraSnapshotsServiceGetCameraSnapshots批量相机快照(names → responses)
CamerasIntrinsicServiceGetCamerasIntrinsic全相机内参

图像类型枚举 CameraImageType:UNKNOWN / COLOR / DEPTH / IR;单目模型 CameraModel:UNKNOWN / PINHOLE / FISHEYE / CMEI。实时流通过 image_channel.proto / color_depth_image_channel.proto 提供的主题订阅。

感知/相机接口多为点触发 RPC + 图像主题订阅的组合:先用 RPC 使能或取单帧,再按需订阅流式图像主题;具体主题名与速率以设备端公示为准。

图像流订阅(Topic)

实时图像流通过 PB 主题发布,消息定义见 image_channel.proto(彩色)与 color_depth_image_channel.proto(彩色+深度),订阅方式与第 4 章其他 PB Topic 一致:

# 以 ROS2 Python 为例(与 4.7 move_waist 相同模式)
from aimdk.protocol.hal.sensors.image_channel_pb2 import ImageChannel
from ros2_plugin_proto.msg import RosMsgWrapper

msg = RosMsgWrapper()
msg.serialization_type = "pb"
msg.context = ["aimdk.protocol.ImageChannel"]
# data 字段为 PB 序列化字节,逐字节填入
# 收到后 ImageChannel.FromString(b''.join(msg.data)) 反序列化

ImageChannelheader + 图像 image(像素数据、宽、高、编码、步长)等字段;ColorDepthImageChannel 同时含彩色与深度两路。相机型号(PINHOLE/FISHEYE/CMEI)与内参见 GetCameraIntrinsicsState

10.2 具身操作(manipulation / task_engine)

机械臂抓取操作(manipulation/manipulation_service.proto

服务 aimdk.protocol.ManipulationService,端口 10.42.10.本地:39110

方法作用 / 关键入参
Manipulate执行操作(manipulation_name, hand_type, interactive_type, stand_type, manipulation_params, interrupted, lift_type…)→ ManipulationResponse
Control运行控制(type, cancel_reset_type)
Select选择候选(index)
GetState查询操作状态 → ManipulationStateResponse
UpdateConfig更新操作配置(name, config)
GetHandState / GetHandPickState手部状态 / 抓取状态
GetServoPickEEPose伺服抓取末端位姿 → ServoPickEEPoseResponse

任务引擎(task_engine/

调度多步具身任务:

  • TaskEngineServiceGetTask / GetAllTasks / GetAllFSMs / SetTask / SetCurrentTask / DeleteTask / DeleteTaskMap / LaunchTask / CtrlTaskState
  • TaskWorkerServiceCtrlTaskWorker(type, task_data)→ CtrlTaskWorkerResponse;CheckoutTask(task_name, task_config, is_file);GetTaskWorkerState
  • 标定类:TaskCalibrationService(CalibrationStart/Stop/GetCalibrationResult)、TaskFactoryCalibrationService、TaskRobotCalibrationService、TaskCalibrationValidService
任务引擎用于把"感知→抓取→放置"等组合成可重复执行的任务流程;标定参数(CalibrationState)直接影响抓取精度,实机调试前应先完成标定。

10.3 多机 / 群组(linkswarm)

协议位于 aimdk.protocol.linkswarm.*linkswarm/a3,用于多机器人组网、任务分发与资源同步。

服务方法作用
LinkSwarmRobotServiceTimeSync / SetHeartbeatFrequency / GetHeartbeat / FindRobot多机时间同步、心跳、找机
LinkSwarmRobotServiceSyncUwbAnchors / InitImu / SetVolume / SetInteractionEnabled / SetFallDetectionEnabledUWB 锚点 / IMU / 音量 / 交互 / 摔倒检测开关
LinkSwarmRobotServiceSetGroupControlMode / GetRobotConfig群控模式 / 机器人配置
LinkSwarmTaskServiceCreateTask / StopTask / ExecuteTask群组任务创建/停止/执行
LinkSwarmResourceServiceUploadResource / FinishUploadResource / CheckResources资源上传与校验
LinkSwarmServiceA3ReleaseTLControlTL 控制权释放

任务消息含 TaskTaskAudio / TaskEmoticon / TaskMotion / TaskMove;轨迹用 TrajectoryPos / TrajectoryVel;心跳经 LinkSwarmHeartbeatChannel 广播。

10.4 系统管理(setting / OTA / 紧急模式)

设置服务(setting/

服务方法(摘录)作用
RobotSettingServiceSystemVolumeControl / SystemWifiControl / GetSystemWifiState / SystemBlueToothControl / GetSystemBlueToothState / RobotInfoSetting / RobotMotionModeCtrl / SystemWifiHotSpotControl / ResetRobot / FactoryReset音量、Wi-Fi、蓝牙、机器人信息、运动模式、热点、复位
RobotFunctionSettingServiceAuthorizationPasswordControl / ConfigControl / TimedateControl / RegionControl / FileConrtol / BrightnessControl授权密码、配置、时间、区域、文件、亮度

状态经 RobotSettingChannel 广播;操作枚举如 WifiControlOperation / WifiSecurity / VolumeControlOperation / BlueToothControlOperation / BlueToothConnectState 等定义于对应 .proto。

OTA 升级(ota/

AimDK OTA 采用三层架构(Master / Gateway / Slave),分别对应主控端、网关端和各从节点(SOC/MCU/固件/软件)。顶层服务 OTAService 提供通用入口,A3 Ultra 主控使用 OTAMasterService

层级服务名核心职责
顶层OTAService通用 OTA 入口:查询 / 启动 / 停止 / 继续 / 进度 / 文件上传
主控OTAMasterServiceA3 Ultra 主控级 OTA:状态机 / 任务查询 / 下载控制 / 升级 / 结果
网关OTAGatewayService网关侧 OTA 代理(状态机 / 下载 / 升级)
从机OTASlaveService从节点 OTA:文件上传 / 启动 / 继续 / 重置 / 执行命令
固件FotaSlaveService固件 OTA 从机
软件SotaSlaveService软件 OTA 从机
子 SOCOTASubSocService子 SOC OTA(下载 / 上传 / 进度 / 重命名)
MCUOTAMcuServiceMCU OTA(信息 / 升级 / 分区切换 / 重启)
标准升级流程(OTAMasterService)

主控级 OTA 共 6 步,按序调用:

1
状态机查询StateMachineQuery,响应 stateOTAGatewayStateMachine:INIT=0 / IDLE=1 / DOWNLOADING=2 / DOWNLOAD_PAUSE=3 / DOWNLOAD_FINISH=4 / UPGRADE_IN_PROGRESS=5 / UPGRADE_FINISH=6)。
2
查询新任务NewTaskQuery(header, language),响应 has_new_task / release_id / version / release_notes / type。升级类型:FULL_PACKAGE=2 / MODULES=3 / SW_DIFF_PACKAGE=5 / FW_FULL_PACKAGE=6 / FW_DIFF_PACKAGE=7。
3
下载控制StartDownload → (可 PauseDownload / ContinueDownload / AbortDownload)。下载进度通过 OTAMasterHeartbeatChannel 心跳广播(download_info.progress / result)。
4
开始升级StartUpgrade,机器人进入升级状态,期间不可控。
5
进度跟踪OTAService.GetCurrentOtaProgress 返回 current_states / percentage / error_count / current_apk_version;或订阅 /ota/schedule 话题。
6
获取结果OTAMasterService.GetOTAResult;或订阅 /ota/result 话题(code / msg / version)。
接口调用示例

说明:SDK 的 proto 定义中未给出 OTA 服务的端口号与运行节点(HDU/ADU/MDU 归属未在协议中声明)。以下示例中的 IP 与端口需在真机上确认后替换。真机上可通过 ss -tlnp | grep ota 或查看 OTA 进程配置来确认监听端口。

① 状态机查询

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAMasterService/StateMachineQuery' \
     -H 'Content-Type: application/json' \
     -d '{"header": {"control_source": 0}}'

② 查询是否有新版本

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAMasterService/NewTaskQuery' \
     -H 'Content-Type: application/json' \
     -d '{
       "header": {"control_source": 0},
       "language": "zh-CN"
     }'
# 响应:has_new_task / release_id / version / release_notes / type

③ 开始下载 OTA 包

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAMasterService/StartDownload' \
     -H 'Content-Type: application/json' \
     -d '{"header": {"control_source": 0}}'
# 下载进度通过 OTAMasterHeartbeatChannel 心跳或 /ota/schedule 订阅获取
# 可暂停/继续/中止:PauseDownload / ContinueDownload / AbortDownload

④ 开始升级

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAMasterService/StartUpgrade' \
     -H 'Content-Type: application/json' \
     -d '{"header": {"control_source": 0}}'

⑤ 查询升级进度(顶层 OTAService

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAService/GetCurrentOtaProgress' \
     -H 'Content-Type: application/json' \
     -d '{"header": {"control_source": 0}}'
# 响应:current_states / percentage / error_count / current_apk_version

⑥ 获取升级结果

curl -X POST 'http://<OTA节点IP>:<OTA端口>/rpc/aimdk.protocol.OTAMasterService/GetOTAResult' \
     -H 'Content-Type: application/json' \
     -d '{"header": {"control_source": 0}}'
OTA 端口号与节点需在真机上确认。升级流程中状态、进度、结果的获取也可通过订阅 OTA 话题(见上表)实现,不必轮询 RPC。
OTA 话题与广播
话题消息内容
/ota/scheduleOTAScheduleChannel升级进度、排期
/ota/resultOTAResultChannel升级结果(code / msg / version)
/ota/heartbeatOTAHeartbeatChannelOTA 心跳(OTAStates)
Master 心跳OTAMasterHeartbeatChannel任务 / 下载 / 升级信息
Slave 心跳OTASlaveHeartbeatChannel从节点状态(OTAStage / 空间占比)
OTAStage 从机升级状态枚举

Idle(1) / Upgrading(2) / Upgrading_Success(3) / Rollbacking(4) / Rollbacking_Success(5) / Pause(6) / Failure(7) / PrepareReady(8) / Upgrading_Image(9) / Wait_Active(10) / Finish_Active(11) / Peripheral_Ready(12)

OTA 操作注意事项:
  • 升级前确认电量充足(建议 50% 以上)、电源稳定,升级中断电可能导致变砖。
  • NewTaskQuery 确认有可用版本,再 StartDownload 下载;下载完成后再 StartUpgrade 执行升级。
  • 升级期间机器人不可控,会自动重启多次,不要断电、不要拔插任何线缆
  • 升级完成后用 GetOTAResult 确认结果;失败可通过 OtaContinue(ROLLBACK) 回滚(版本支持时)。
  • 恢复出厂(FactoryReset)会清除用户数据,执行前务必备份配置与资源文件。
  • examples/ 目录暂无 OTA 示例代码,需按 proto 定义直接调用。

系统 / 紧急模式(hal/state + sm/

服务方法作用
HalOperationModeServiceGetOperationModeState / SetOperationModeCommand工作模式查询 / 下发(OperationMode)
HalEmergencyServiceGetEmergencyState / SetEmergencyCommand急停状态查询 / 下发
SystemService(sm_api)TriggerEStop / ReleaseEStop / GetSystemState / GetSystemRunningStatus触发/释放急停、系统状态

SM 系统状态 SystemStatus:IN_INITIAL / IN_READY / IN_MOVE / IN_ROLLBACK / IN_RECOVERY / IN_FALLBACK / IN_FALLBACK_MOVE。紧急模式下 MC 会 deactivate,恢复后需 ReleaseEStop,再 activate mc + activate motion_player(见 0.5 安全红线与 9.3 急停复位流程)。

12. 接口速查总表

能力接口 / 主题方式节点:端口
运动状态机GetAvailableActionsRPCMDU:56322
GetNextActionsRPC
GetActionRPC
SetActionRPC
行走/motion/control/locomotion_velocity/pb_:.MotionControlLocomotionVelocityChannelTopic
腿部关节MotionControlJointService/SetLegJointCommand、GetLegJointStateRPCMDU:56322
腰部关节MotionControlJointService/SetWaistJointCommandRPCMDU:56322
手臂/motion/control/arm_joint_command / arm_joint_stateTopic
脖子/motion/control/neck_joint_command / neck_joint_stateTopic
手指/motion/control/hand_joint_command / hand_joint_stateTopic
腰部/motion/control/move_waist/pb_:.MotionControlMoveWaistChannelTopic
动作播放MotionCommandService/SendMotionCommandRPCMDU:56444
地图MappingService/*、LocalizationService/GetTopoMsgsRPCADU:50807
重定位RelocalizationService/*、SLAMRelocalizationService/*RPCADU:50807
导航PncService/PlanningNaviTo*、LinearNaviTo*、SpinTurn*、MoveForward、Action*RPCADU:53176
导航前置ActionMcActionService/SetAction(切 McAction_RL_LOCOMOTION_DEFAULT)RPCADU:56322
TTSTTSService/PlayTTS、PlayMediaFile、GetAudioStatus、StopTTSTraceIdRPCHDU:59301
TTS状态/interaction/tts_status/pb_:.TTSStatusTopic
麦克风/模式AgentControlService/Set*、Get*、Voice/Properties;HalAudioService/SetMicSourceRPCHDU:59301
唤醒/agent/wakeup/pb_:.WakeUpResultTopic
麦克风音频/agent/process_audio_outputTopic
音频焦点/audio_5Fmsgs/srv/RequestAudioFocus、AbandonAudioFocusService
流式音频/audiohal/audio/playbackTopic
资源管理ResourceService/CreateResource、DeleteResource、UpdateResource、GetResource、GetResourceList、ResourceMigrationIn/OutRPCHDU:51049
表情/skill/pilot/face/play/pb_:.HFAEmoctionTopic
技能/舞蹈SkillPilotService/SkillPackage、AutoChargingRPCMDU:52893
告警HDSService/GetAlertList、GetTotalAlertList、GetAlertCount、GetExceptionEventRPCMDU:50587
BMS/aima/bms/data/pb_:.BmsStateChannelTopic
急停/hal_state/emergency/pb_:.EmergencyStateChannelTopic
音量/文件HalAudioService/GetAudioVolume、SetAudioVolume、PlayFile、StopPlayRPCHDU:56666
工程管理50080 /json/start_app、stop_app(控制 motion_player 等)RPCMDU:50080
2D/6D 感知Object2dDetectionService/Get2dDection、Object6dPoseEstimationService/Get6dPoseRPCADU(以设备实际发布为准)
目标跟踪 / 目标点StartMultiTracking、TargetGuidanceService/GetTargetPointRPCADU(以设备实际发布为准)
相机HalCameraService/TakeShot、GetCameraIntrinsicsState、EnableCameraImgTopicRPCHDU(以设备实际发布为准)
机械臂操作ManipulationService/Manipulate、GetState、UpdateConfigRPC本地:39110
任务引擎TaskEngineService/LaunchTask、CtrlTaskState、TaskWorkerServiceRPCADU(以设备实际发布为准)
多机群组LinkSwarmRobotService、LinkSwarmTaskService、LinkSwarmResourceServiceRPC
系统设置RobotSettingService/SystemVolumeControl、SystemWifiControl、RobotInfoSettingRPCHDU(以设备实际发布为准)
OTA 升级OTAMasterService/StateMachineQuery、NewTaskQuery、StartDownload、StartUpgrade、GetOTAResultRPC—(见 10.4)
系统急停SystemService/TriggerEStop、ReleaseEStop、GetSystemStateRPC
HAL 工作模式HalOperationModeService/GetOperationModeState、SetOperationModeCommandRPC

注:上表 "节点:端口" 沿用文档与示例约定 IP;实际以 AimMaster 显示 IP 为准。Topic 名中 pb_:... 为示例缩写,实际为 URL 编码形式(如 pb_3Aaimdk_2Eprotocol_2ETTSStatus)。

附录

附录 A:SDK 目录结构

agibot_a3_Ultra_aimdk-dev3.2/
├── protocol/                  # 原始协议定义
│   ├── ros2/                  #   ROS2 消息/服务定义(按功能板块)
│   └── protobuf/              #   protobuf .proto 源(按功能板块)
├── examples/                  # 全接口示例
│   ├── agent/                 #   TTS/音频/麦克风/唤醒/焦点
│   ├── hal_audio/             #   音量
│   ├── hds/                   #   告警
│   ├── mc/                    #   运动控制(走/臂/头/手/腰/Action/关节状态)
│   ├── mm/                    #   地图(建图/定位/UI演示)
│   ├── other/                 #   BMS/急停
│   ├── pnc/                   #   规控导航(RPC 调用示例+demo)
│   ├── resource_manager/      #   资源创建/查询/删除/迁移(+示例资源文件)
│   └── skill_play/            #   动作/表情/舞蹈/技能状态
├── prebuilt/                  # 预构建协议文件
│   ├── audio_msgs_proto_aarch64/
│   ├── ros2_plugin_proto_aarch64/   # RosMsgWrapper 环境
│   └── a3_aimdk-3.2.0-py3-none-any.whl   # Python 协议包(PB 消息)
├── README.md / password.md / format.sh / sync_protobuf.py
└── .clang-format / .pycodestyle

附录 B:协议子包(示例)

Python 包顶层为 aimdk.protocol,按能力域分组如下:

基础能力域

  • motion_control / mc:action 状态机 / motion 行走 / joint 关节服务(腿/臂/腰)/ move_waist / data(joint 状态) / kinematics / safety / simulation
  • mm(地图):mapping / localization / relocalization / qr_localization / occupancy_grid
  • pnc(导航):pnc_service / path / 规控相关(见第 6 章)
  • interaction / agent:tts_service(TTSStatus) / interaction_service / agent_data(WakeUpResult) / asr_result
  • hal:audio / bms / camera / hand / neck / power / sensors / state(emergency/operation_mode) / light / thermal / uwb
  • resource_manager:资源上传 / 校验 / 列表(见第 7 章)
  • skill / aim_master:动作/表情/舞蹈播放、HFAEmoction 皮肤表情(见第 8 章)
  • hds:alert 告警 / exception 异常 / health 健康 / monitor 监控(见第 9 章)
  • common:header / rpc / timestamp — 通用请求/响应头、错误码 CommonState

高级能力域(第 10 章)

  • perception:perception_service / object_2d_detection / object_6d_pose_estimation / target_guidance / tracked_obstacles / object_mask
  • manipulation:manipulation_service / manipulation_msg — 机械臂抓取操作
  • task_engine:task_engine_service / task_engine_calibration / worker_service / grasp_objects — 任务引擎与标定
  • ta(遥操):ta_service / ta_whole_body_command / ta_whole_body_state / teleop_body_mode
  • sm(状态机):sm_rpc / sm_api / sm_state / sm_channel — 系统状态与急停
  • linkswarm:linkswarm_robot / linkswarm_task / linkswarm_resource / linkswarm_a3 — 多机群组
  • gateway:auth(InteractionAuthService)/ login(AccessControl)/ log / trace — 鉴权与多端管理
  • setting:wifi / volume / bluetooth / robot_info / function_setting / system_setting — 系统设置
  • ota:ota_master / ota_slave / ota_channel — 系统升级
  • media:tts / asr / webrtc — 媒体通道

附录 C:常见问题(FAQ)

Q1:控制 topic 发不出,手臂/头/腰/手不动?

检查:① 是否已切到力控模式的 MOTION(见 4.1);② motion_player 是否已关闭(多数关节 topic 被其占用);③ 脖子消息是否填了 velocity/effort。

Q2:腰 / 腿逐关节 RPC(SetLeg/SetWaistJointCommand)返回 SUCCESS / code=0,但关节仍然不动?

这是"位于普通 MOTION 档、腰 / 腿被内置步态策略接管"的典型表现:RPC 已受理但目标被策略覆盖,故不报错也不动。解决:先经 SetAction(action=5000 扩展桥)切到对应 EXT 增强模式(如 McAction_RL_WHOLE_BODY_EXT_JOINT_SERVO),再用 GetAction 确认切换成功后再下发。详见 5.5 EXT 增强模式。若 GetAvailableActions 中无该 EXT 枚举,则当前固件未开放该模式。

Q3:行走 topic 用 json 还是 pb?

行走按官方示例用 serialization_type="json",格式见 5.3;腰部/状态类用 pb + context。按各自示例为准。

Q4:TTS 播放成功但没声音 / is_success=true 却无声?

确认音频文件存在且格式正确(16kHz/16bit/单声道 PCM 或 44 头部 WAV),文件不存在时静默失败;可用 GetAudioStatus + 订阅 TTSStatus 校验真实状态。

Q5:导航任务失败?

检查重定位成功且任务 map_id 与重定位地图一致;MC 已切到 McAction_RL_LOCOMOTION_DEFAULT;用 ActionGetState 观察状态,必要时 ActionCancel 后重试。

Q6:如何读取实时机器人电量/急停?

订阅 BMS 与 EmergencyStateChannel 主题,PB 反序列化,见 10.2 / 10.3。

Q7:皮肤上没有表情 / skill_status 收不到?

相关 topic 默认走 iceoryx,需在 skillpilot.yaml 改成 [mqtt, ros2] 并重启,见 9.2。