gRPC 例程(传统控制)
本例程针对传统控制(MPC)模式,介绍如何获取 gRPC 客户端工程、配置运行环境,并通过交互式命令行(Python / C++)或程序集成方式控制机器人。MPC 客户端位于仓库的 mpc_client/ 目录,服务端口固定为 6666,包名为 adam_control。
获取客户端
完整客户端工程(含 Proto 协议、生成文件与示例脚本)将发布于 GitHub:
🔗 仓库地址:pnd_grpc
工程结构
仓库同时提供传统控制(MPC)与强化学习(RL)两套客户端,分别位于 mpc_client/ 与 rl_client/:
pnd_grpc/
├── mpc_client/ # 传统控制(MPC)客户端 ← 本例程
│ ├── proto/ # gRPC 协议定义(adam_control.proto,权威来源)
│ ├── include/ # protoc 生成的 C++ 头文件与源文件
│ ├── src/ # C++ API 封装 + 交互式命令行客户端
│ ├── python/ # Python 交互式客户端 + 生成的桩代码
│ ├── ip_config.json # 机器人服务端 IP / 端口配置
│ ├── build.sh / run.sh / clean.sh
│ └── README.md # 传统控制模式详细使用说明
│
├── rl_client/ # 强化学习(RL)模式客户端
│ ├── comm/
│ │ ├── proto/ # gRPC 协议定义(robot_control.proto)
│ │ └── grpc/ # protoc 生成的 Python 桩代码
│ ├── tools/grpc_client.py# Python 交互式客户端示例
│ └── README.md # 强化学习模式详细使用说明
│
└── README.md # 项目总览
本例程仅涉及 mpc_client/。 其中 proto/adam_control.proto 是接口的唯一权威来源,协议变更后执行 ./build.sh 重新生成 C++(include/)与 Python(python/)桩代码即可,不影响接口兼容性;强化学习(RL)客户端的使用方式见 gRPC 例程(强化学习)。
环境准备
系统要求
推荐在 Ubuntu 22.04 x86_64 下进行客户端开发与调试。客户端可在任意能访问机器人网络的计算机上运行,与控制程序分离部署。
安装依赖
仅需 grpcio 即可运行;grpcio-tools 用于 build.sh 重新生成桩代码:
网络连接
使用网线将您的计算机与机器人连接至同一网段,网络配置方式见快速开发(真机)。服务端 gRPC 端口固定为 6666。
配置服务端 IP
与 RL 客户端通过 --addr 传参不同,MPC 客户端在启动时读取 mpc_client/ip_config.json:
配置要点
- 修改 IP 后 C++ 客户端无需重新编译(运行时读取配置)。
- 服务端口固定为
6666,应与机器人端PndControl启动日志中的gRPC client connect address一致。 - 占位 IP(
xx.xx.xx.xx、0.0.0.0、空)会在启动时被拒绝并提示配置。
连接前检查清单
- 机器人端
PndControl已启动,且编译时启用 gRPC(buildrobot.sh中-Dgrpc_on=true)。 - 已执行
install.sh并systemctl restart pnd_adam_dds.service使新二进制生效。 ip_config.json中的 IP 与控制台打印的 gRPC 地址一致。- 客户端机器到机器人
6666端口网络可达(防火墙未阻断)。
编译与运行
cd mpc_client
chmod +x build.sh run.sh clean.sh
./build.sh # 生成 C++/Python 桩代码 + cmake 编译,输出 bin/adam_command_client
./run.sh # 默认启动 Python 客户端
./run.sh python # 同上
./run.sh bin # 启动 C++ 客户端(需先 build)
./clean.sh # 删除 build/、bin/、lib/,保留 include/ 与 python/ 中的桩代码
也可直接运行:
build.sh 会依据 proto/adam_control.proto 生成桩代码,并在 build/ 下用 cmake 编译。若本机 protoc 版本与仓库内生成文件不同,可重复执行 ./build.sh 覆盖本地桩代码。
交互式 CLI 例程
Python 与 C++ 客户端均提供 REPL 交互:输入 help 查看命令,exit 返回/退出。客户端会根据机器人当前 FSM 状态动态启用命令,Python 客户端额外支持 Tab 补全且命令大小写不敏感。
$ ./run.sh python
Running Python client: .../mpc_client/python/adam_command_client.py
已连接到 gRPC 服务: 192.168.31.76:6666
Adam Command Client v1.1.0
Type 'help' for usage information.
> help
Available commands:
SetMode
SetStandMotion
SetStandCarryBox
SetStandAction
SetStandDynamic
SetSpeed
AutoUnigaitCOM
SetErrorClear
GetStandList
GetRobotState
SetControlMode <0=Traditional|1=RL> -- switch control paradigm
GetControlState -- query current control mode from DDS rt/control_mode_state
clear
exit
> GetRobotState
Current Mode: Start
Current Motion:
Enable Mode List: ['Zero']
Enable Motion List: []
Enable Action List: []
Enable Carry Box List: []
Stand Pitch: 0.0
Stand Roll: 0.0
Stand Yaw: 0.0
Stand Height: 0.0
X Velocity: 0.0
Y Velocity: 0.0
Yaw Velocity: 0.0
Balance Control State: False
Control Mode: 0 (Traditional)
> SetMode
Available Modes: Zero
Enter parameter for Setmode: Zero
Success: Mode set successfully
> SetMode
Available Modes: Stand
Enter parameter for Setmode: Stand
Success: Mode set successfully
> SetStandMotion
Available Motions: Greeting, Chest Expansion, Stretching, Gentleman's Salute
Enter parameter for Setstandmotion: Greeting
Success: Motion executed successfully
> SetStandAction
Current action values (stand_pitch stand_roll stand_yaw base_height) (0.0, 0.0, 0.0, 0.0)
Please enter values within the following ranges:
- Pitch: [-0.1, 0.1]
- Roll: [-0.06, 0.06]
- Yaw: [-0.25, 0.25]
- Base Height: [-0.2, 0.0]
Action> Enter action values (stand_pitch stand_roll stand_yaw stand_height): 0.0 0.0 0.0 -0.1
Success: Action executed successfully
> GetControlState
Control State: domain_id=0 (Traditional)
> SetControlMode
Current control mode: 0 (Traditional)
Enter control mode (0/1): 1
Waiting for hardware to switch to RL (timeout=30s, poll every 0.5s)...
[ 0.0s] Current mode: 0 (Traditional)
[ 2.5s] Current mode: 1 (RL)
Success: Switched to RL successfully.
> exit
Exiting Adam Command Client.
CLI 命令对照
| 命令 | 对应 RPC | 适用模式 | 说明 |
|---|---|---|---|
SetMode |
SetMode |
依 mode_enable_list |
切换 Start/Zero/Stand/Walk/Run/Stop 等 |
SetStandMotion |
SetStandMotion |
Stand |
预定义动作(如 Greeting) |
SetStandCarryBox |
SetStandCarryBox |
Stand |
搬箱动作(1蹲下/2站立/0放下) |
SetStandAction |
SetStandAction |
Stand |
姿态 pitch/roll/yaw + 蹲起高度 |
SetStandDynamic |
SetStandDynamic |
Stand |
动态平衡开/关 |
SetSpeed |
SetSpeed |
Walk / Run |
设置 x/y/yaw 速度(注意安全) |
AutoUnigaitCOM |
AutoUnigaitCOM |
Walk / Run |
COM X 方向偏置平衡 |
SetErrorClear |
SetErrorClear |
Stop |
清除驱动错误,无需关电 |
GetStandList |
GetStandList |
任意 | 获取固定动作/模式列表 |
GetRobotState |
GetRobotState |
任意 | 获取当前状态与各 *_enable_list |
SetControlMode |
SetControlMode |
任意 | 切换控制范式 0Traditional / 1RL |
GetControlState |
GetControlState |
任意 | 查询当前控制范式 |
先查状态再下发
下发模式/动作类指令前应先 GetRobotState,仅当目标模式/动作出现在对应 *_enable_list 中时才可执行;列表外的指令会被客户端或服务端拒绝。
典型控制流程
Start → Zero → Stand ┬─ SetStandMotion / SetStandAction / SetStandCarryBox / SetStandDynamic
└─ Walk / Run → SetSpeed / AutoUnigaitCOM
(异常)Stop → SetErrorClear
操作步骤:
GetRobotState— 确认当前 FSM 与mode_enable_listSetMode→Zero— 零位校准SetMode→Stand— 进入站立- 在
Stand下执行动作,例如SetStandMotion(Greeting)或SetStandAction(姿态/蹲起高度) - 如需行走:
SetMode→Walk/Run,再用SetSpeed设置速度 - 若驱动报错:
SetMode→Stop,再SetErrorClear清错
安全提示
SetSpeed存在安全风险,生产环境建议使用手柄键控,客户端示例仅作接口演示。SetStandAction的 pitch/roll/yaw 与蹲起高度需在允许范围内(见下),超出会被拒绝。- 操作前请确保机器人处于安全悬挂或开阔场地,并遵循操作指南中的安全规范。
SetStandAction 姿态参数范围
| 参数 | 范围 |
|---|---|
| Pitch | [-0.1, 0.1] |
| Roll | [-0.06, 0.06] |
| Yaw | [-0.25, 0.25] |
| Base Height | [-0.2, 0.0] |
程序集成例程
交互式 CLI 适合手动调试。若需在自己的程序中集成,可参考以下封装。
Python
直接使用 Stub:
import grpc
import adam_control_pb2 as pb2
import adam_control_pb2_grpc as pb2_grpc
channel = grpc.insecure_channel("192.168.1.100:6666")
stub = pb2_grpc.RobotControlStub(channel)
# 切换模式
r = stub.SetMode(pb2.SetModeRequest(mode="Stand"))
print(r.success, r.message)
# 查询状态与 enable_list
s = stub.GetRobotState(pb2.GetRobotStateRequest(get_state_flag=True))
print(s.fsm_name, list(s.mode_enable_list))
# Stand 下执行动作
stub.SetStandMotion(pb2.SetStandMotionRequest(motion="Greeting"))
stub.SetStandAction(pb2.SetActionRequest(
stand_pitch=0.0, stand_roll=0.0, stand_yaw=0.0, stand_height=-0.1))
# 切换控制范式并读取确认
stub.SetControlMode(pb2.SetControlModeRequest(domain_id=0))
ctrl = stub.GetControlState(pb2.GetControlStateRequest())
print(ctrl.domain_id) # 0=Traditional, 1=RL
或复用示例客户端 adam_command_client.py 中 AdamCommand 的封装方法:
ok, msg = client.set_mode("Stand")
ok, msg = client.set_stand_motion("Greeting")
ok, msg = client.set_stand_action(0.0, 0.0, 0.0, -0.1)
ok, cur_mode, msg = client.set_control_mode(0) # 下发切换指令
ok, final_mode, msg = client.wait_for_control_mode(0, timeout_sec=30) # 轮询确认
client.get_control_state()
C++
#include "adam_command.h"
adam_control::AdamCommand client("192.168.1.100:6666");
std::string message;
bool ok = client.SetMode("Stand", message);
// 切换控制范式并轮询硬件确认(默认 30s 超时)
int final_mode = -1;
ok = client.SetControlModeAndWait(0, final_mode, message);
int domain_id = -1;
ok = client.GetControlState(domain_id, message);
可将 src/adam_command.cpp 编译为 libadam_command 链接到自有工程(见 src/CMakeLists.txt)。adam_command.h 另提供异步 API(如 SetModeAsync),适用于非阻塞集成场景。
代码解析
mpc_client/python/adam_command_client.py 的核心逻辑如下:
- 读取配置:从
../ip_config.json读取ip/port拼接服务端地址;占位 IP 会被拒绝并提示。 - 连接检查:连接前用
grpc.channel_ready_future做 5s 超时检查,失败时打印排查提示(PndControl 是否启动、端口是否可达等)。 - 状态感知:每次命令前调用
GetRobotState刷新fsm_name与各*_enable_list,据此动态启用命令与 Tab 补全;Stand才开放动作类命令,Walk/Run才开放速度类命令,Stop才开放SetErrorClear。 - 状态机输入:命令进入参数输入态(
WAIT_PARAMETER/WAIT_SPEED_INPUT/WAIT_ACTION_INPUT),对枚举参数与数值范围做校验。 - 控制范式切换:
SetControlMode下发 DDSrt/control_mode_cmd后,轮询GetControlState(默认 30s)确认硬件切换,与 C++ 客户端行为一致。
常见问题
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
failed to connect to all addresses |
IP/端口错误或 gRPC 未启用 | 检查 ip_config.json、PndControl 日志、防火墙、6666 端口可达性 |
this command can only be executed when mode is 'Stand' |
未先切到对应模式 | 先 SetMode 切到 Stand(或 Walk/Run) |
Invalid parameter / enable_list 外指令 |
当前状态不允许该模式/动作 | 先 GetRobotState 查看 *_enable_list |
SetControlMode 超时 |
硬件切换较慢 | 用 GetControlState 继续确认;检查 DDS 服务 |
ModuleNotFoundError: grpc |
未安装 Python 依赖 | pip install -r mpc_client/python/requirements.txt |
C++ 编译找不到 nlohmann_json |
未安装 dev 包 | sudo apt install nlohmann-json3-dev |
相关文档
| 文档 | 说明 |
|---|---|
| 传统控制 gRPC 接口说明 | 传统控制(MPC)模式 gRPC 接口定义与参数说明 |
| gRPC 例程(强化学习) | 强化学习(RL)模式客户端获取与交互示例 |
| 手臂控制例程 | DDS 实时上肢控制 |
| 灵巧手控制说明 | DDS 手指控制 |