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. 测 RPC | 调 GetAction,见下 | 返回 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 端到端示例:语音互动机器人
三模块分别验证,再串成主循环:
- 播报警示语:调
PlayTTS(6.1)。 - 走一段 / 挥手:切 MOTION 后发行走速度(4.2)、控制手臂(4.4)。
- 用唤醒串起来:订阅
/agent/wakeup(6.4),把 1、2 包进主循环。
完整操作链:
| # | 操作 | 命令要点 |
|---|---|---|
| 1 | 停 motion_player | MDU/50080 调 stop_app,见 4.5 |
| 2 | 切 MOTION | SetAction,见 4.1 |
| 3 | 播 TTS 提示 | PlayTTS,见 6.1 |
| 4 | 发行走速度 2s | locomotion_velocity,见 4.2 |
| 5 | 等待唤醒,回到 3 | 订阅 wakeup,见 6.4 |
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 | 建图、定位、导航规划、具身智能体 |
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
- 开发机与机器人连接到同一无线网络。
- 在 AimMaster → 设置 → 无线局域网,获取机器人各节点 IP。
- 通过 SSH 登录目标节点。
# HDU(音频/交互/资源/技能)
ssh agi@10.42.10.10
# ADU(地图/定位/导航 PNC)
ssh agi@10.42.10.11
# MDU(运动控制 Action/关节)
ssh agi@10.42.10.12
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
history: keep_last / depth: 10 / reliability: best_effort,订阅握手建议保持兼容。2.5 快速上手流程
SetAction 将机器人切换到力控模式的 MOTION(见 4.1)。motion_player。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(运动状态机) | 56322 | MDU |
| MotionCommandService(动作播放) | 56444 | MDU |
| TTSService / AgentControlService(语音) | 59301 | HDU |
| ResourceService(资源) | 51049 | HDU |
| HalAudioService(硬音量/文件播放) | 56666 | HDU |
| MappingService / LocalizationService / RelocalizationService | 50807 | ADU |
| PncService(规控导航) | 53176 | ADU |
| HDSService(告警) | 50587 | MDU |
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 章)。
3.5 RequestHeader 完整字段 与 接口鉴权
多数 RPC 请求体首层即为 request_header(或 header),其字段用于链路追踪与控制源标识。依据 common/header.proto:
| 字段 | 类型 | 说明 |
|---|---|---|
timestamp | Timestamp | 请求时间戳(秒/纳秒) |
control_source | 枚举 | 控制源,默认 AUTO=0,安全模块触发用 SAFE=2 |
uuid | string | 请求唯一标识 |
trace_id | string | 追踪链路 ID(TTS 打断等按此定位) |
domin | string | 业务域(官方原始字段名即 domin) |
响应侧 ResponseHeader:code(0=成功,非 0 失败,msg 含原因)、msg、timestamp、trace_id、domin。阻塞式调用另有 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=2。jwt 有 expire_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.proto 的 CommonState:RPC 响应顶层的 code 非 0 即失败,msg 含原因。
| code | CommonState | 含义 / 处理 |
|---|---|---|
| 0 | UNKNOWN | 未知(框架初始占位) |
| 1 | SUCCESS | 成功 |
| 2 | FAILURE | 失败,查 msg |
| 3 | ABORTED | 被中止 |
| 4 | TIMEOUT | 超时,重试或降频 |
| 5 | INVALID | 入参无效 |
| 6 | IN_MANUAL | 处于手动/占用态,先释放控制源 |
| 100 | NOT_READY | 未就绪,稍后重试 |
| 200 | PENDING | 等待中 |
| 300 | CREATED | 已创建 |
| 400 | RUNNING | 运行中 |
链路告警等级(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 | 身外身模式(遥操作基座) |
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 填手部类型(AgiHand 或 O10Hand,缺省 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 | 手指关节状态 |
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 占用。直接控制上肢关节前,请先停掉 motion_player(stop_app motion_player),避免通道冲突。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.3 | 5.4 + 5.5 |
5.2 31 DOF 全身关节图谱
A3 Ultra 标准全身布局为 TaJointLayout_BODY_31,共 31 个自由度,按部位分类如下。所有关节名、顺序均与 SDK 中 TaWholeBodyCommand / TaWholeBodyState 定义一致。
| 部位 | DOF | 全局序号 | 关节名 | 说明 |
|---|---|---|---|---|
| 左腿 | 6 | 0 | left_hip_pitch_joint | 左髋俯仰 |
| 1 | left_hip_roll_joint | 左髋横滚 | ||
| 2 | left_hip_yaw_joint | 左髋偏航 | ||
| 3 | left_knee_joint | 左膝 | ||
| 4 | left_ankle_pitch_joint | 左踝俯仰 | ||
| 5 | left_ankle_roll_joint | 左踝横滚 | ||
| 右腿 | 6 | 6 | right_hip_pitch_joint | 右髋俯仰 |
| 7 | right_hip_roll_joint | 右髋横滚 | ||
| 8 | right_hip_yaw_joint | 右髋偏航 | ||
| 9 | right_knee_joint | 右膝 | ||
| 10 | right_ankle_pitch_joint | 右踝俯仰 | ||
| 11 | right_ankle_roll_joint | 右踝横滚 | ||
| 腰部 | 3 | 12 | waist_yaw_joint | 腰部偏航 |
| 13 | waist_roll_joint | 腰部横滚 | ||
| 14 | waist_pitch_joint | 腰部俯仰 | ||
| 头部 | 2 | 15 | head_yaw_joint | 头部偏航 |
| 16 | head_pitch_joint | 头部俯仰 | ||
| 左臂 | 7 | 17 | left_shoulder_pitch_joint | 左肩俯仰 |
| 18 | left_shoulder_roll_joint | 左肩横滚 | ||
| 19 | left_shoulder_yaw_joint | 左肩偏航 | ||
| 20 | left_elbow_joint | 左肘 | ||
| 21 | left_wrist_roll_joint | 左腕横滚 | ||
| 22 | left_wrist_pitch_joint | 左腕俯仰 | ||
| 23 | left_wrist_yaw_joint | 左腕偏航 | ||
| 右臂 | 7 | 24 | right_shoulder_pitch_joint | 右肩俯仰 |
| 25 | right_shoulder_roll_joint | 右肩横滚 | ||
| 26 | right_shoulder_yaw_joint | 右肩偏航 | ||
| 27 | right_elbow_joint | 右肘 | ||
| 28 | right_wrist_roll_joint | 右腕横滚 | ||
| 29 | right_wrist_pitch_joint | 右腕俯仰 | ||
| 30 | right_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.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)
}
操作步骤
McAction_RL_WHOLE_BODY_EXT_JOINT_SERVO),用 GetAction 确认切换成功。# 腿部
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 '{}'
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}
]
}'
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_* 系列)是实现下肢逐关节控制的必要前提。它本质是一组"让渡控制权"的运动模式——把特定身体部位(上肢/腰腿/全身)的控制权从内置策略手中让出来,交给外部程序。
McAction_RL_* 系列。请以 GetAvailableActions 返回为准。增强模式对比(常用 5 种)
| 模式 | 编号 | 下肢 | 上肢 | 腰 | 适用场景 |
|---|---|---|---|---|---|
LOCOMOTION_DEFAULT | 301 | 自主行走 | 禁止外部控制 | — | 基础行走(非增强) |
RL_LOCOMOTION_DEFAULT | 401 | RL自主行走 | 禁止外部控制 | — | RL强化行走 |
RL_LOCOMOTION_ARM_EXT_JOINT_SERVO | 402 | 自主行走 | 外部逐关节 | — | 走路上肢作业 |
RL_LOCOMOTION_ARM_EXT_PLANNING_MOVE | 403 | 力控站立 | 外部规划 | — | 站立上肢作业 |
RL_WHOLE_BODY_EXT_JOINT_SERVO | 405 | 外部逐关节 | 外部逐关节 | 外部 | 全身逐关节控制 |
RL_WHOLE_BODY_EXT_ONLINE_PLANNING | 407 | 力控站立 | 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=5000 即 MotionControlAction_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 Topic | RPC |
| 前置模式 | 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、骨骼流)实时控制机器人全身。
5.7.1 TaWholeBodyCommand 全身指令通道
TA 通过 topic /ta/whole_body_command 以 60Hz 发布全身运动指令,MC 订阅。消息类型为 TaWholeBodyCommandChannel(PB 格式),核心数据 TaWholeBodyCommand 字段如下:
| 字段 | 类型 | 维度 | 说明 |
|---|---|---|---|
joint_layout | 枚举 | — | 关节布局:BODY_31=1 或 BODY_HANDS_55=2 |
pelvis_pose | TaPelvisPose | — | 骨盆位姿(世界坐标系):quat_wxyz + position_xyz |
pelvis_velocity | TaPelvisVelocity | — | 骨盆速度(局部坐标系):linear_xyz + angular_xyz |
leg_command | TaLegJointCommand | 12 | 腿部关节角度(弧度),顺序同关节图谱 0~11 |
foot_contact | TaFootContact | — | 足底接触力:left_contact + right_contact + detailed_contacts[16] |
waist_command | TaWaistJointCommand | 3 | 腰部关节角度(弧度),顺序同关节图谱 12~14 |
head_command | TaHeadJointCommand | 2 | 头部关节角度(弧度),顺序同关节图谱 15~16 |
arm_command | TaArmJointCommand | 14 | 手臂 5 组 14 维:angles_rad + velocities_rad_s + feedforward_efforts + stiffness + damping |
left_hand_command | TaHandJointCommand | 12 | 左手手指(仅 BODY_HANDS_55 布局) |
right_hand_command | TaHandJointCommand | 12 | 右手手指(仅 BODY_HANDS_55 布局) |
joint_velocities | TaJointVelocities | 31 | 全身关节速度(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()
: → _3A,. → _2E)。实际 topic 名以机器人上 ros2 topic list 输出为准。5.7.2 TA 接入完整流程
TA 模块运行于 service preset 下,所有功能由外部编排。完整接入需以下步骤:
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 = 未标定基准值);足部旋转/平移偏置为足部补偿参数。具体数值需根据机器人实际标定获取,以上为占位默认值。
curl -X POST '<TA节点IP>:<端口>/rpc/aimdk.protocol.TaService/StartSession' \
-H 'Content-Type: application/json' -d '{"header": {"control_source": 0}}'
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
TA_SOURCE_MOCAP_RETARGET=1(动捕重定向模式)。# source: TA_SOURCE_MOCAP_RETARGET=1 / MOTION_MATCHING=2 / ACTION_PLAYER=3
/ta/whole_body_command 发布 PB 格式的全身指令。TaUpperBodyDeadmanCommand(左右扳机量,归一化 [0,1],≥阈值视为按下)。有 TTL 超时机制,停止发布自动归零(松开)。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()
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=SUCCEEDED 且 safe_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_ABSOLUTE | 1 | mc=AVATAR | 全身绝对遥操 |
| FULL_INCREMENTAL | 2 | mc=AVATAR | 全身增量遥操 |
| UPPER_BODY_INCREMENTAL | 3 | mc=MOTION | 半身增量遥操(上半身) |
| UPPER_BODY_ABSOLUTE | 4 | mc=MOTION | 半身绝对遥操(上半身) |
5.7.5 TA 服务方法速查
| 类别 | 方法 | 说明 |
|---|---|---|
| 生命周期 | StartSession | 启动会话(需先标定) |
PauseSession | 暂停会话 | |
| 标定 | StartCalibration | T-pose 标定(需骨骼流) |
InjectCalibration | 直接注入标定参数 | |
| MC 切换 | SwitchMcAction | AVATAR / MOTION / PASSIVE / PD_STAND |
| 姿态转换 | RunPostureTransition | 趴下 / 起身(独占) |
| 急停 | EmergencyStop | 急停(→ EMERGENCY_STOPPED) |
EmergencyClear | 清除急停(→ PAUSED) | |
| 数据源 | SelectSource | mocap_retarget / motion_matching / action_player |
| 上半身模式 | SetUpperBodyMode | 全身/半身 × 绝对/增量 |
| 全身复位 | StartWholeBodyReset | 原地踏步 / 拳击 |
| 状态查询 | GetServiceStatus | 完整工作状态 |
5.8 全身关节状态读取
获取机器人当前关节状态有两种方式:RPC 拉取(按部位,适合调试)和 Topic 订阅(全身/分部位,适合实时控制闭环)。
方式一:RPC 拉取(按部位)
服务 MotionControlJointService(MDU:56322)提供 5 个部位的状态查询:
| 方法 | 返回 | 关节数 |
|---|---|---|
GetLegJointState | JointStateResponse | 12 |
GetArmJointState | JointStateResponse | 14 |
GetWaistJointState | JointStateResponse | 3 |
GetNeckJointState | NeckStateResponse | 2 |
GetHandJointState | HandStateResponse | 视手型 |
每个 JointState 含字段:name / sequence / position / velocity / effort。
方式二:Topic 订阅
| Topic | 消息类型 | 说明 |
|---|---|---|
/motion/control/arm_joint_state | sensor_msgs/JointState | 手臂关节状态(ROS2 原生) |
/motion/control/neck_joint_state | sensor_msgs/JointState | 脖子关节状态(ROS2 原生) |
/wbc/whole_body_state | TaWholeBodyStateChannel | 全身关节状态(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 数组中,JointState 含 name / sequence / position / velocity / effort 五个字段。
5.9 控制接口与 Action 模式对应总表
不同控制接口有不同的 Action 模式前提。下表汇总全身各部位的控制接口、所需 Action 模式、以及备注:
| 身体部位 | 接口 | 类型 | 所需 Action 模式 | 备注 |
|---|---|---|---|---|
| 行走(双腿整体) | locomotion_velocity topic | Topic JSON | MOTION | 最常用,整体行走 |
| PNC 导航接口 | RPC | RL_LOCOMOTION_DEFAULT | 自主导航 | |
| 腿部逐关节 | SetLegJointCommand | RPC | RL_WHOLE_BODY_EXT_JOINT_SERVO | 需 EXT 增强模式 |
| TaWholeBodyCommand.leg_command | Topic PB | AVATAR | TA 遥操链路 | |
| 腰部 | move_waist topic | Topic PB | MOTION | 四通道比例值,最简单 |
| SetWaistJointCommand | RPC | RL_WHOLE_BODY_EXT_JOINT_SERVO | 需 EXT 增强模式,精确 3 关节 | |
| 手臂 | arm_joint_command topic | Topic | MOTION(随动)/ EXT(精确) | MOTION 下随步态摆动 |
| SetArmJointCommand | RPC | RL_LOCOMOTION_ARM_EXT_* 或 405/407 | 精确上肢控制 | |
| 脖子 | neck_joint_command topic | Topic | MOTION | velocity/effort 必须设置(0 也可) |
| 手指 | hand_joint_command topic | Topic | MOTION | 视手型配置(AgiHand / O10Hand) |
| 全身 31 DOF | TaWholeBodyCommand | Topic PB | AVATAR | TA 遥操链路,60Hz |
代码示例:模式切换完整闭环(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()
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.MappingService 与 aimdk.protocol.LocalizationService。
| 方法 | 作用 | 关键入参 |
|---|---|---|
GetStoredMapNames | 获取已存储地图列表 | command=MappingCommand_GET_STORED_MAP_NAME |
GetCurrentWorkingMap | 获取当前工作地图 ID | command=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/SetVoiceEnable | RPC | 设置静默模式(false=静音/禁音) |
AgentControlService/GetVoiceEnable | RPC | 查询静默模式 |
AgentControlService/SetAgentPropertiesRequest / GetAgentPropertiesRequest | RPC | 设置/查询交互运行模式 |
HalAudioService/SetMicSourceRequest / GetMicSourceRequest | RPC | 切换内/外置麦克风 |
/agent/process_audio_output | Topic | 降噪麦克音频输出 |
/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。开放六类资源:动作、表情、音频、技能、地图、创作作品。
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,可组合动作+表情+音频,支持 NormalMotion 与 WholeBodyDance)。
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
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 | 告警唯一标识 / 告警码 |
| state | AlertState_ACTIVE / AlertState_CLEARED |
| level | H1_FATAL 级到 H7_EVENT / H7_DELETE 级 |
| appeared_timestamp / disappeared_timestamp | 出现 / 消失时间 |
| description / alert_text / alert_module | 描述文本与模块 |
其他:GetTotalAlertList、GetAlertCount、GetExceptionEvent(较冗杂,优先 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 mc、activate motion_player。系统模式/工作模式相关 Topic 见 aimdk.protocol.hal.state.* 与 mc.base.work_mode。
急停复位完整流程
触发急停后(物理急停按钮 / SystemService.TriggerEStop),MC 进入 deactivate、机器人不可运动。恢复前先确认危险已排除,再按序复位:
EmergencyStateChannel 或 HalEmergencyService.GetEmergencyState 确认 reason 非空。SYSTEM RELEASE E-STOP(SystemService.ReleaseEStop)释放软件急停;若由物理按钮触发,先复位实体急停按钮。GetAlertList,见 10.1)后,重新 activate mc;再按需 deactivate motion_player(若此前被策略占用,见 0.5)。SetAction 重新切入目标 Action(如 MOTION),并用 GetAction 确认生效后再生效下发。10.4 音频音量 RPC
服务 aimdk.protocol.HalAudioService,地址 10.42.10.10:56666:GetAudioVolume / 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)
| 服务 | 方法 | 作用 / 关键入参 |
|---|---|---|
| PerceptionService | AddMultiScaleObjects | 注入多尺度目标(MultiScaleObjectsRequest)→ CommonResponse |
| PerceptionService | SendEnvObjInfos | 下发环境物体信息(EnvObjectArrayInfoReq)→ CommonResponse |
| Object2dDetectionService | Get2dDection | 2D 目标检测(header, camera_id, image, target_type)→ box2d |
| Object6dPoseEstimationService | Get6dPose | 6D 位姿估计(header, camera_id, image, target_type)→ box2d, bbox6d |
| Object6dPoseEstimationService | StartMultiTracking / SetMultiTrackingIds | 多目标跟踪启停 / 设定跟踪目标(prompts / obj_ids) |
| TargetGuidanceService | GetTargetPoint / 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)
| 服务 | 方法 | 作用 |
|---|---|---|
| HalCameraService | GetCameraIntrinsicsState / TakeShot / GetCameraMetrics / EnableCameraImgTopic | 相机内参 / 单帧拍照 / 指标 / 使能图像主题(open_dma_topic) |
| HalCameraFirmwareService | GetCameraFirmwareVersion | 相机固件版本 |
| CameraService | GetCameraInfo / GetCameraData | 相机信息 / 取图(name, stream_type,返回 color_info / color_image / depth_info / depth_image) |
| CameraSnapshotsService | GetCameraSnapshots | 批量相机快照(names → responses) |
| CamerasIntrinsicService | GetCamerasIntrinsic | 全相机内参 |
图像类型枚举 CameraImageType:UNKNOWN / COLOR / DEPTH / IR;单目模型 CameraModel:UNKNOWN / PINHOLE / FISHEYE / CMEI。实时流通过 image_channel.proto / color_depth_image_channel.proto 提供的主题订阅。
图像流订阅(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)) 反序列化
ImageChannel 含 header + 图像 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/)
调度多步具身任务:
- TaskEngineService:
GetTask / GetAllTasks / GetAllFSMs / SetTask / SetCurrentTask / DeleteTask / DeleteTaskMap / LaunchTask / CtrlTaskState - TaskWorkerService:
CtrlTaskWorker(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,用于多机器人组网、任务分发与资源同步。
| 服务 | 方法 | 作用 |
|---|---|---|
| LinkSwarmRobotService | TimeSync / SetHeartbeatFrequency / GetHeartbeat / FindRobot | 多机时间同步、心跳、找机 |
| LinkSwarmRobotService | SyncUwbAnchors / InitImu / SetVolume / SetInteractionEnabled / SetFallDetectionEnabled | UWB 锚点 / IMU / 音量 / 交互 / 摔倒检测开关 |
| LinkSwarmRobotService | SetGroupControlMode / GetRobotConfig | 群控模式 / 机器人配置 |
| LinkSwarmTaskService | CreateTask / StopTask / ExecuteTask | 群组任务创建/停止/执行 |
| LinkSwarmResourceService | UploadResource / FinishUploadResource / CheckResources | 资源上传与校验 |
| LinkSwarmServiceA3 | ReleaseTLControl | TL 控制权释放 |
任务消息含 Task、TaskAudio / TaskEmoticon / TaskMotion / TaskMove;轨迹用 TrajectoryPos / TrajectoryVel;心跳经 LinkSwarmHeartbeatChannel 广播。
10.4 系统管理(setting / OTA / 紧急模式)
设置服务(setting/)
| 服务 | 方法(摘录) | 作用 |
|---|---|---|
| RobotSettingService | SystemVolumeControl / SystemWifiControl / GetSystemWifiState / SystemBlueToothControl / GetSystemBlueToothState / RobotInfoSetting / RobotMotionModeCtrl / SystemWifiHotSpotControl / ResetRobot / FactoryReset | 音量、Wi-Fi、蓝牙、机器人信息、运动模式、热点、复位 |
| RobotFunctionSettingService | AuthorizationPasswordControl / 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 入口:查询 / 启动 / 停止 / 继续 / 进度 / 文件上传 |
| 主控 | OTAMasterService | A3 Ultra 主控级 OTA:状态机 / 任务查询 / 下载控制 / 升级 / 结果 |
| 网关 | OTAGatewayService | 网关侧 OTA 代理(状态机 / 下载 / 升级) |
| 从机 | OTASlaveService | 从节点 OTA:文件上传 / 启动 / 继续 / 重置 / 执行命令 |
| 固件 | FotaSlaveService | 固件 OTA 从机 |
| 软件 | SotaSlaveService | 软件 OTA 从机 |
| 子 SOC | OTASubSocService | 子 SOC OTA(下载 / 上传 / 进度 / 重命名) |
| MCU | OTAMcuService | MCU OTA(信息 / 升级 / 分区切换 / 重启) |
标准升级流程(OTAMasterService)
主控级 OTA 共 6 步,按序调用:
StateMachineQuery,响应 state(OTAGatewayStateMachine:INIT=0 / IDLE=1 / DOWNLOADING=2 / DOWNLOAD_PAUSE=3 / DOWNLOAD_FINISH=4 / UPGRADE_IN_PROGRESS=5 / UPGRADE_FINISH=6)。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。StartDownload → (可 PauseDownload / ContinueDownload / AbortDownload)。下载进度通过 OTAMasterHeartbeatChannel 心跳广播(download_info.progress / result)。StartUpgrade,机器人进入升级状态,期间不可控。OTAService.GetCurrentOtaProgress 返回 current_states / percentage / error_count / current_apk_version;或订阅 /ota/schedule 话题。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/schedule | OTAScheduleChannel | 升级进度、排期 |
/ota/result | OTAResultChannel | 升级结果(code / msg / version) |
/ota/heartbeat | OTAHeartbeatChannel | OTA 心跳(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)
- 升级前确认电量充足(建议 50% 以上)、电源稳定,升级中断电可能导致变砖。
- 先
NewTaskQuery确认有可用版本,再StartDownload下载;下载完成后再StartUpgrade执行升级。 - 升级期间机器人不可控,会自动重启多次,不要断电、不要拔插任何线缆。
- 升级完成后用
GetOTAResult确认结果;失败可通过OtaContinue(ROLLBACK)回滚(版本支持时)。 - 恢复出厂(
FactoryReset)会清除用户数据,执行前务必备份配置与资源文件。 - examples/ 目录暂无 OTA 示例代码,需按 proto 定义直接调用。
系统 / 紧急模式(hal/state + sm/)
| 服务 | 方法 | 作用 |
|---|---|---|
| HalOperationModeService | GetOperationModeState / SetOperationModeCommand | 工作模式查询 / 下发(OperationMode) |
| HalEmergencyService | GetEmergencyState / 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. 接口速查总表
| 能力 | 接口 / 主题 | 方式 | 节点:端口 |
|---|---|---|---|
| 运动状态机 | GetAvailableActions | RPC | MDU:56322 |
| GetNextActions | RPC | ||
| GetAction | RPC | ||
| SetAction | RPC | ||
| 行走 | /motion/control/locomotion_velocity/pb_:.MotionControlLocomotionVelocityChannel | Topic | — |
| 腿部关节 | MotionControlJointService/SetLegJointCommand、GetLegJointState | RPC | MDU:56322 |
| 腰部关节 | MotionControlJointService/SetWaistJointCommand | RPC | MDU:56322 |
| 手臂 | /motion/control/arm_joint_command / arm_joint_state | Topic | — |
| 脖子 | /motion/control/neck_joint_command / neck_joint_state | Topic | — |
| 手指 | /motion/control/hand_joint_command / hand_joint_state | Topic | — |
| 腰部 | /motion/control/move_waist/pb_:.MotionControlMoveWaistChannel | Topic | — |
| 动作播放 | MotionCommandService/SendMotionCommand | RPC | MDU:56444 |
| 地图 | MappingService/*、LocalizationService/GetTopoMsgs | RPC | ADU:50807 |
| 重定位 | RelocalizationService/*、SLAMRelocalizationService/* | RPC | ADU:50807 |
| 导航 | PncService/PlanningNaviTo*、LinearNaviTo*、SpinTurn*、MoveForward、Action* | RPC | ADU:53176 |
| 导航前置Action | McActionService/SetAction(切 McAction_RL_LOCOMOTION_DEFAULT) | RPC | ADU:56322 |
| TTS | TTSService/PlayTTS、PlayMediaFile、GetAudioStatus、StopTTSTraceId | RPC | HDU:59301 |
| TTS状态 | /interaction/tts_status/pb_:.TTSStatus | Topic | — |
| 麦克风/模式 | AgentControlService/Set*、Get*、Voice/Properties;HalAudioService/SetMicSource | RPC | HDU:59301 |
| 唤醒 | /agent/wakeup/pb_:.WakeUpResult | Topic | — |
| 麦克风音频 | /agent/process_audio_output | Topic | — |
| 音频焦点 | /audio_5Fmsgs/srv/RequestAudioFocus、AbandonAudioFocus | Service | — |
| 流式音频 | /audiohal/audio/playback | Topic | — |
| 资源管理 | ResourceService/CreateResource、DeleteResource、UpdateResource、GetResource、GetResourceList、ResourceMigrationIn/Out | RPC | HDU:51049 |
| 表情 | /skill/pilot/face/play/pb_:.HFAEmoction | Topic | — |
| 技能/舞蹈 | SkillPilotService/SkillPackage、AutoCharging | RPC | MDU:52893 |
| 告警 | HDSService/GetAlertList、GetTotalAlertList、GetAlertCount、GetExceptionEvent | RPC | MDU:50587 |
| BMS | /aima/bms/data/pb_:.BmsStateChannel | Topic | — |
| 急停 | /hal_state/emergency/pb_:.EmergencyStateChannel | Topic | — |
| 音量/文件 | HalAudioService/GetAudioVolume、SetAudioVolume、PlayFile、StopPlay | RPC | HDU:56666 |
| 工程管理 | 50080 /json/start_app、stop_app(控制 motion_player 等) | RPC | MDU:50080 |
| 2D/6D 感知 | Object2dDetectionService/Get2dDection、Object6dPoseEstimationService/Get6dPose | RPC | ADU(以设备实际发布为准) |
| 目标跟踪 / 目标点 | StartMultiTracking、TargetGuidanceService/GetTargetPoint | RPC | ADU(以设备实际发布为准) |
| 相机 | HalCameraService/TakeShot、GetCameraIntrinsicsState、EnableCameraImgTopic | RPC | HDU(以设备实际发布为准) |
| 机械臂操作 | ManipulationService/Manipulate、GetState、UpdateConfig | RPC | 本地:39110 |
| 任务引擎 | TaskEngineService/LaunchTask、CtrlTaskState、TaskWorkerService | RPC | ADU(以设备实际发布为准) |
| 多机群组 | LinkSwarmRobotService、LinkSwarmTaskService、LinkSwarmResourceService | RPC | — |
| 系统设置 | RobotSettingService/SystemVolumeControl、SystemWifiControl、RobotInfoSetting | RPC | HDU(以设备实际发布为准) |
| OTA 升级 | OTAMasterService/StateMachineQuery、NewTaskQuery、StartDownload、StartUpgrade、GetOTAResult | RPC | —(见 10.4) |
| 系统急停 | SystemService/TriggerEStop、ReleaseEStop、GetSystemState | RPC | — |
| HAL 工作模式 | HalOperationModeService/GetOperationModeState、SetOperationModeCommand | RPC | — |
注:上表 "节点:端口" 沿用文档与示例约定 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。