gRPC Example (MPC)
This guide targets traditional-control (MPC) mode. It explains how to obtain the gRPC client project, set up the environment, and control the robot via the interactive CLI (Python / C++) or programmatic integration. The MPC client lives in the repository's mpc_client/ directory; the service port is fixed at 6666 and the package name is adam_control.
Obtaining the Client
The full client project (Proto definitions, generated bindings, and sample scripts) will be published on GitHub:
đ Repository: pnd_grpc
Project Layout
The repository ships both the traditional-control (MPC) and reinforcement-learning (RL) clients, located in mpc_client/ and rl_client/ respectively:
pnd_grpc/
âââ mpc_client/ # Traditional-control (MPC) client â this guide
â âââ proto/ # gRPC protocol definition (adam_control.proto, source of truth)
â âââ include/ # protoc-generated C++ headers and sources
â âââ src/ # C++ API wrapper + interactive CLI client
â âââ python/ # Python interactive client + generated stubs
â âââ ip_config.json # Robot server IP / port configuration
â âââ build.sh / run.sh / clean.sh
â âââ README.md # Detailed MPC mode usage
â
âââ rl_client/ # Reinforcement-learning (RL) mode client
â âââ comm/
â â âââ proto/ # gRPC protocol definition (robot_control.proto)
â â âââ grpc/ # protoc-generated Python stubs
â âââ tools/grpc_client.py# Interactive Python CLI sample
â âââ README.md # Detailed RL mode usage
â
âââ README.md # Project overview
This guide covers only mpc_client/. Its proto/adam_control.proto is the single source of truth for the interface; after any protocol change, run ./build.sh to regenerate the C++ (include/) and Python (python/) stubs without breaking compatibility. For the reinforcement-learning (RL) client, see gRPC Example (RL).
Environment Setup
System Requirements
We recommend Ubuntu 22.04 x86_64 for client development. The client can run on any machine that can reach the robot over the network, separately from the control program.
Install Dependencies
Only grpcio is required at runtime; grpcio-tools is used by build.sh to regenerate stubs:
Network
Connect your computer and the robot on the same subnet. See Quick Development (Real) for network configuration. The service gRPC port is fixed at 6666.
Configuring the Server IP
Unlike the RL client (which takes --addr), the MPC client reads mpc_client/ip_config.json at startup:
{
"server": {
"ip": "192.168.x.x",
"port": 6666,
"comment": "ip = robot NIC IP; port defaults to 6666 and rarely needs changing"
}
}
Configuration notes
- After changing the IP, the C++ client does not need to be recompiled (the config is read at runtime).
- The service port is fixed at
6666and should match thegRPC client connect addressprinted in the robot'sPndControlstartup log. - Placeholder IPs (
xx.xx.xx.xx,0.0.0.0, empty) are rejected at startup with a prompt to configure.
Pre-Connection Checklist
- The robot's
PndControlis running and was built with gRPC enabled (-Dgrpc_on=trueinbuildrobot.sh). install.shhas been run andsystemctl restart pnd_adam_dds.serviceapplied so the new binary takes effect.- The IP in
ip_config.jsonmatches the gRPC address printed in the console. - The client machine can reach port
6666on the robot (not blocked by a firewall).
Build and Run
cd mpc_client
chmod +x build.sh run.sh clean.sh
./build.sh # Generate C++/Python stubs + cmake build â bin/adam_command_client
./run.sh # Start the Python client by default
./run.sh python # Same as above
./run.sh bin # Start the C++ client (build first)
./clean.sh # Remove build/, bin/, lib/; keep stubs in include/ and python/
Or run directly:
build.sh generates stubs from proto/adam_control.proto and builds with cmake under build/. If your local protoc differs from the bundled generated files, rerun ./build.sh to overwrite the local stubs.
Interactive CLI Example
Both the Python and C++ clients provide a REPL: type help for commands and exit to go back / quit. The client enables commands dynamically based on the robot's current FSM state; the Python client additionally supports Tab completion and is case-insensitive.
$ ./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 Command Reference
| Command | RPC | Mode | Description |
|---|---|---|---|
SetMode |
SetMode |
per mode_enable_list |
Switch Start/Zero/Stand/Walk/Run/Stop, etc. |
SetStandMotion |
SetStandMotion |
Stand |
Predefined motion (e.g. Greeting) |
SetStandCarryBox |
SetStandCarryBox |
Stand |
Box-carrying action (1 squat / 2 stand / 0 place) |
SetStandAction |
SetStandAction |
Stand |
Posture pitch/roll/yaw + squat height |
SetStandDynamic |
SetStandDynamic |
Stand |
Toggle dynamic balance |
SetSpeed |
SetSpeed |
Walk / Run |
Set x/y/yaw speed (mind safety) |
AutoUnigaitCOM |
AutoUnigaitCOM |
Walk / Run |
COM X-direction offset balance |
SetErrorClear |
SetErrorClear |
Stop |
Clear driver errors without power cycling |
GetStandList |
GetStandList |
any | Get fixed motion/mode lists |
GetRobotState |
GetRobotState |
any | Get current state and the *_enable_lists |
SetControlMode |
SetControlMode |
any | Switch paradigm 0=Traditional / 1=RL |
GetControlState |
GetControlState |
any | Query the current control paradigm |
Query state before commanding
Run GetRobotState before issuing mode/action commands; a target mode/action can only be executed when it appears in the corresponding *_enable_list. Commands outside the list are rejected by the client or server.
Typical Control Flow
Start â Zero â Stand âŦâ SetStandMotion / SetStandAction / SetStandCarryBox / SetStandDynamic
ââ Walk / Run â SetSpeed / AutoUnigaitCOM
(on error) Stop â SetErrorClear
Steps:
GetRobotStateâ confirm the current FSM andmode_enable_listSetModeâZeroâ homingSetModeâStandâ enter standing- In
Stand, execute actions, e.g.SetStandMotion(Greeting) orSetStandAction(posture / squat height) - To walk:
SetModeâWalk/Run, then set speed withSetSpeed - If a driver error occurs:
SetModeâStop, thenSetErrorClear
Safety
SetSpeedcarries safety risk; in production prefer gamepad teleoperation â the sample client is for interface demonstration only.SetStandActionpitch/roll/yaw and squat height must be within the allowed ranges (below); out-of-range values are rejected.- Ensure the robot is safely suspended or in a clear area before operating, and follow the Operations Guide.
SetStandAction Posture Ranges
| Parameter | Range |
|---|---|
| Pitch | [-0.1, 0.1] |
| Roll | [-0.06, 0.06] |
| Yaw | [-0.25, 0.25] |
| Base Height | [-0.2, 0.0] |
Programmatic Integration
The interactive CLI is for manual debugging. To integrate into your own program, use the wrappers below.
Python
Use the stub directly:
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)
# Switch mode
r = stub.SetMode(pb2.SetModeRequest(mode="Stand"))
print(r.success, r.message)
# Query state and enable lists
s = stub.GetRobotState(pb2.GetRobotStateRequest(get_state_flag=True))
print(s.fsm_name, list(s.mode_enable_list))
# Execute actions in 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))
# Switch control paradigm and read back
stub.SetControlMode(pb2.SetControlModeRequest(domain_id=0))
ctrl = stub.GetControlState(pb2.GetControlStateRequest())
print(ctrl.domain_id) # 0=Traditional, 1=RL
Or reuse the AdamCommand wrapper methods from the sample client adam_command_client.py:
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) # queue the switch
ok, final_mode, msg = client.wait_for_control_mode(0, timeout_sec=30) # poll to confirm
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);
// Switch the control paradigm and poll hardware to confirm (30s timeout by default)
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 can be built as libadam_command and linked into your own project (see src/CMakeLists.txt). adam_command.h also provides async APIs (e.g. SetModeAsync) for non-blocking integration.
Code Walkthrough
Core logic in mpc_client/python/adam_command_client.py:
- Config loading: Reads
ip/portfrom../ip_config.jsonto build the server address; placeholder IPs are rejected with a prompt. - Connection check: Before connecting, uses
grpc.channel_ready_futurewith a 5s timeout and prints troubleshooting hints on failure (PndControl running? port reachable?). - State awareness: Calls
GetRobotStatebefore each command to refreshfsm_nameand the*_enable_lists, enabling commands and Tab completion accordingly â action commands only inStand, speed commands only inWalk/Run,SetErrorClearonly inStop. - State-machine input: Commands enter a parameter-input state (
WAIT_PARAMETER/WAIT_SPEED_INPUT/WAIT_ACTION_INPUT) with enum and numeric-range validation. - Control-paradigm switch: After
SetControlModepublishes the DDSrt/control_mode_cmd, it pollsGetControlState(30s by default) to confirm the hardware switch, matching the C++ client.
FAQ
| Symptom | Likely cause | Suggestion |
|---|---|---|
failed to connect to all addresses |
Wrong IP/port or gRPC not enabled | Check ip_config.json, PndControl log, firewall, port 6666 reachability |
this command can only be executed when mode is 'Stand' |
Not switched to the required mode first | SetMode to Stand (or Walk/Run) first |
Invalid parameter / command outside enable_list |
Current state does not allow that mode/action | Run GetRobotState to view the *_enable_lists |
SetControlMode timeout |
Hardware switch is slow | Keep confirming with GetControlState; check the DDS service |
ModuleNotFoundError: grpc |
Python dependency missing | pip install -r mpc_client/python/requirements.txt |
C++ build cannot find nlohmann_json |
dev package missing | sudo apt install nlohmann-json3-dev |
Related Documents
| Document | Description |
|---|---|
| MPC gRPC Interface | Traditional-control (MPC) gRPC API definitions and parameters |
| gRPC Example (RL) | RL-mode client acquisition and interactive example |
| Arm Control Example | DDS real-time upper-limb control |
| Dexterous Hand Control | DDS finger control |