本文描述当前项目已经实现并验证的 G1 高层动作接口,以及把它们封装为 Agent Tool 时必须遵守的输入、状态、完成条件和错误处理约定。
这三类数据含义不同,工具实现不能混用。
| 数据 | 示例 | 含义 |
|---|---|---|
| RPC 返回码 | code=0 |
请求已被服务接受,相当于 ACK;不代表动作已经完成 |
| FSM ID | 1、706、802 |
机器人高层控制器当前所处的有限状态机状态 |
| 动作状态 | {"id":100,"name":"Waist_Drum_Dance"} |
rt/arm/action/state 发布的当前手臂/自定义动作状态 |
当前机器人和固件上的实测含义:
FSM 1:Damp(阻尼)状态;完成下蹲后机器人停在该状态。FSM 706:蹲姿与站姿之间的转换状态。StandUp2Squat()和Squat2StandUp()都发送这个 ID,转换方向由进入前的状态决定。FSM 802:当前这台 G1 在ai高层模式下稳定站立后观测到的状态;fsm_mode=0时速度 RPC 会被接受,但不会产生行走。FSM 500/501:最新版官方 Loco 接口用于消费速度指令的行走状态集合。
706 和 802 都不是 ACK。判断一次下蹲调用至少包含两层结果:
StandUp2Squat()返回code=0:服务接受了指令。GetFsmId()最终从706变为1:下蹲状态转换完成。
{
"network_interface": "enP7s7",
"rpc_timeout_seconds": 10.0,
"diagnose_only": false,
"require_human_confirmation": true
}network_interface:连接 G1 的本机网卡,不是机器人 IP。rpc_timeout_seconds:单次 RPC 超时。diagnose_only=true:只检查网络、ai模式、FSM 和动作可用性,不发送运动指令。require_human_confirmation:真实机器人首次测试必须为true。只有动作已经验证且上层具备安全联锁时才能关闭。
{
"ok": true,
"accepted": true,
"completed": true,
"rpc_code": 0,
"fsm_before": 802,
"fsm_after": 802,
"action_name": "Waist_Drum_Dance",
"elapsed_seconds": 9.8,
"message": "动作完成"
}accepted只能根据 RPC 返回码设置。completed必须根据 FSM、动作状态 Topic 或明确的停止流程设置,不能直接复制accepted。- 失败时保留
rpc_code、最后 FSM 和最后动作状态,便于诊断。
每个运动 Tool 执行前都应检查:
- 网卡存在且处于 UP 状态。
MotionSwitcherClient.CheckMode()返回name="ai"。- 没有另一个 Tool 正在控制机器人;整个机器人应使用一个全局动作锁。
- 机器人姿态符合动作要求。
- 周围空间、地面和遥控器急停已经由人确认。
- 自定义/示教动作:调用
G1ArmActionClient.StopCustomAction()。 - 速度运动:在
finally中持续减速并调用SetVelocity(0, 0, 0, ...)。 - 数值 ID 手臂动作:根据动作属性发送
release_arm(ID 99)。 - 下蹲/起立转换:没有通用软件急停可以替代遥控器急停。
- 捕获
KeyboardInterrupt、超时和 RPC 异常,但不能声称软件异常处理等同于硬件安全保障。
这些动作通过 G1ArmActionClient.ExecuteAction(action_id) 执行。动作 ID 必须从 GetActionList() 的当前固件响应中按名称解析,不能只依赖代码中的旧映射。
- Tool 建议名:
g1_wave_above_head - 固件名称:
wave_above_head - 当前固件 ID:
26 - 脚本:
example/g1/high_level/g1_wave_hand_example.py - 前置姿态:稳定站立;固件动作描述允许当前 FSM。
- 完成判断:订阅
rt/arm/action/state;观察动作名称进入再离开wave_above_head。当前脚本仍提供等待时间作为兼容兜底。 - 风险:手臂上举,头部和肩部周围需要净空。
python example/g1/high_level/g1_wave_hand_example.py enP7s7- Tool 建议名:
g1_wave_under_head - 固件名称:
wave_under_head - 当前固件 ID:
25 - 脚本:
example/g1/high_level/g1_face_wave_example.py - 前置姿态:稳定站立。
- 完成判断:动作状态 Topic 或经过实机标定的超时。
- 风险:手臂经过脸部前方,不能有人靠近机器人正面。
- Tool 建议名:
g1_clap - 固件名称:
clamp(固件使用的是clamp,不是英文clap) - 当前固件 ID:
17 - 脚本:
example/g1/high_level/g1_clap_example.py - 前置姿态:稳定站立,双臂无外接负载。
- 完成判断:动作状态 Topic 或标定等待时间。
- 风险:两手快速接近,手部附件和线缆必须避开。
- Tool 建议名:
g1_high_five - 固件名称:
high_five - 当前固件 ID:
18 - 脚本:
example/g1/high_level/g1_high_five_example.py - 前置姿态:稳定站立。
- 完成处理:动作结束后发送
release_arm(ID 99)。 - 风险:如果与人互动,不允许人拉拽或冲击机器人手臂。
- Tool 建议名:
g1_hug - 固件名称:
hug - 当前固件 ID:
19 - 脚本:
example/g1/high_level/g1_hug_example.py - 前置姿态:稳定站立,机器人正前方无障碍物。
- 完成处理:动作结束后发送
release_arm(ID 99)。 - 风险:首次测试不能让人进入双臂闭合区域。
- Tool 建议名:
g1_wave_then_clap - 脚本:
example/g1/high_level/g1_wave_then_clap_sequence.py - 顺序:
wave_above_head -> clamp - 前置姿态:稳定站立,两项动作都存在于当前固件列表。
- 完成判断:前一个动作完成后才能发送后一个动作。
- 并发规则:序列执行期间持有机器人全局动作锁。
自定义动作通过名称而不是数字 ID 执行:
code = client.ExecuteCustomAction("Waist_Drum_Dance")对应服务协议:
- 执行动作:API
7108,参数{"action_name":"动作名"}。 - 停止动作:API
7113。 - 状态 Topic:
rt/arm/action/state,消息类型为std_msgs.msg.dds_.String_,内容是 JSON。
当前固件公开的自定义动作:
| 名称 | 固件预计时长 | 说明 |
|---|---|---|
Waist_Drum_Dance |
9.5 秒 | 腰鼓舞,全身动作 |
Spin_discs |
6.9 秒 | 转盘类动作,需先单独实机验证 |
Scratch_head |
8.1 秒 | 挠头动作,需先单独实机验证 |
Throw_money |
8.1 秒 | 撒钱动作,需先单独实机验证 |
- Tool 建议名:
g1_waist_drum_dance - 固件名称:
Waist_Drum_Dance,区分大小写。 - 脚本:
example/g1/high_level/g1_dance_example.py - 前置姿态:
ai模式、稳定站立、至少 2 米净空。 - 接受判断:
ExecuteCustomAction()返回code=0。 - 开始判断:状态 Topic 出现
id=100且name="Waist_Drum_Dance"。 - 完成判断:已经观察到开始后,状态名称离开
Waist_Drum_Dance。 - 默认超时:固件时长 9.5 秒加 5 秒余量。
- 超时/中断:调用
StopCustomAction()。
只读诊断:
python example/g1/high_level/g1_dance_example.py enP7s7 --diagnose执行舞蹈:
python example/g1/high_level/g1_dance_example.py enP7s7停止舞蹈:
python example/g1/high_level/g1_dance_example.py enP7s7 --stop其他固件自定义动作也可通过同一入口调用:
python example/g1/high_level/g1_dance_example.py \
enP7s7 --action Scratch_head- Tool 建议名:
g1_squat - 独立脚本:
example/g1/high_level/g1_squat_only_example.py enP7s7 - 前置 FSM:
500/501/801/802中的稳定站立状态;当前机器人通常为802。 - 请求:
StandUp2Squat(),内部发送 FSM706。 - 接受判断:RPC
code=0。 - 完成判断:轮询
GetFsmId(),最终进入FSM 1。 - 禁止做法:固定睡眠几秒后直接认为完成。
- Tool 建议名:
g1_stand_from_squat - 独立脚本:
example/g1/high_level/g1_stand_up_example.py enP7s7 - 前置 FSM:
1。 - 正确顺序:
Damp() -> 等待 0.5 秒 -> Squat2StandUp()。 - 请求:
Squat2StandUp()内部同样发送 FSM706。 - 完成判断:FSM 进入站立集合
{500, 501, 801, 802}。 - 常见错误:在第一次
706尚未退出时再次发送706,服务可能接受请求但不重新触发动作。
- Tool 建议名:
g1_squat_cycle - 独立脚本:
example/g1/high_level/g1_squat_cycle_example.py enP7s7 - 状态链:
站立 -> 706 -> 1 -> 706 -> 站立。 - 完成判断:必须分别等待下蹲完成和起立完成。
- 超时:任何一段超时立即停止序列,不继续发送下一状态。
每种速度动作均有独立文件,通用入口为 example/g1/high_level/g1_smooth_motion_example.py。速度采用机身坐标系:
vx > 0:前进;vx < 0:后退。vy > 0:向左横移;vy < 0:向右横移。vyaw > 0:向左转;vyaw < 0:向右转。
| Tool 建议名 | 独立脚本 | 目标速度 |
|---|---|---|
g1_move_forward |
g1_move_forward_example.py |
(speed, 0, 0) |
g1_move_backward |
g1_move_backward_example.py |
(-speed, 0, 0) |
g1_move_left |
g1_move_left_example.py |
(0, speed, 0) |
g1_move_right |
g1_move_right_example.py |
(0, -speed, 0) |
g1_turn_left |
g1_turn_left_example.py |
(0, 0, yaw_speed) |
g1_turn_right |
g1_turn_right_example.py |
(0, 0, -yaw_speed) |
g1_move_curve_left |
g1_curve_left_example.py |
(speed, 0, yaw_speed) |
g1_move_curve_right |
g1_curve_right_example.py |
(speed, 0, -yaw_speed) |
每个移动 Tool 的输入至少包含:
{
"speed": 0.10,
"yaw_speed": 0.20,
"duration_seconds": 1.0
}约束与完成判断:
- 线速度首次测试不超过
0.25 m/s。 - 角速度首次测试不超过
0.5 rad/s。 - 单段首次测试不超过 5 秒。
- 以 20 Hz 平滑逼近目标速度,发送约 0.15 秒的短租约。
- 默认先调用
Start(),等待 FSM 从802等状态进入500/501后才发送非零速度。 --prepare-mode walkrun会改用 API7111进入内部WALKRUN(mode 2);两种准备方式不能在一次调用中自动互相回退。- 时间结束后平滑减速,最后发送零速度。
- Tool 只有在零速度 RPC 成功后才能返回
completed=true。
- Tool 建议名:
g1_lower_body_demo - 脚本:
example/g1/high_level/g1_lower_body_sequence.py - 顺序:下蹲、起立、小步前进、停止、原地左转、停止。
- 状态同步:蹲起使用真实 FSM;移动使用短租约和零速度结束。
- 失败策略:任一步失败,不得执行后续步骤。
- 并发规则:整个序列持有全局动作锁。
工具启动时仍应动态调用 GetActionList();下表只用于理解当前机器,不应作为永久硬编码来源。
当前数值 ID 动作包括:
release_arm(99), turn_back_wave(1), blow_kiss_with_both_hands(11),
blow_kiss_with_left_hand(12), blow_kiss_with_right_hand(13),
both_hands_up(15), clamp(17), high_five(18), hug(19),
make_heart_with_both_hands(20), make_heart_with_right_hand(21),
refuse(22), right_hand_up(23), ultraman_ray(24), wave_under_head(25),
wave_above_head(26), shake_hand(27), box_left_hand_win(28),
box_right_hand_win(29), box_both_hand_win(30), right_hand_on_heart(33),
both_hands_up_deviate_right(34), forward_push(36)
尚未单独验证的动作不要直接暴露给自治 Agent。应先完成:只读发现、单动作人工确认测试、完成状态标定、安全空间记录,然后才能加入 Tool 白名单。
不要让每个 Tool 各自初始化 DDS 和争抢机器人。建议使用一个长生命周期运行时:
G1Runtime
├── DDS ChannelFactory(只初始化一次)
├── MotionSwitcherClient
├── LocoClient
├── G1ArmActionClient
├── arm/action/state Subscriber
├── 全局动作锁
└── Tool 方法
├── wave_above_head()
├── clap()
├── waist_drum_dance()
├── squat()
├── stand_from_squat()
├── move(vx, vy, vyaw, duration)
└── stop()
Tool 层负责参数校验、权限和结构化结果;SDK 适配层负责 RPC、FSM 与 Topic;序列层只组合 Tool,不直接绕过状态检查调用 SDK。