A comprehensive robotics software development kit for AgiBot and Unitree robot platforms, built on ROS 2. It provides hardware abstraction, motion control, sensor integration, and interaction capabilities — along with a reinforcement learning control example.
| Platform | Models |
|---|---|
| AgiBot X2 | pm01, se01, sa01 |
| Unitree | unitree_sdk2 compatible |
| EngineAI | interface_protocol compatible |
robot_sdk/
├── agibot/
│ ├── aimdk_msgs/ # ROS 2 message & service definitions
│ └── aimdk_examples/ # High-level robot API and usage examples
├── engineai/
│ ├── interface_protocol/ # Low-level hardware interface definitions
│ └── interface_example/ # Joint control & RL policy examples
└── unitree/
├── unitree_sdk2/ # Unitree SDK (git submodule)
└── unitree_sdk2_ament/ # ROS 2 ament wrapper for Unitree SDK
- ROS 2 Humble or Foxy
- CMake 3.8+
- C++17 compatible compiler
- Third-party libraries installed to
/opt/engineai_robotics_third_party/:- Eigen3, yaml-cpp, OpenCV, ruckig, libcurl, ncurses, MNN
Option A — Clone and initialize submodules in one step:
git clone --recurse-submodules https://github.com/ZemsRepo/robot_sdk.git
cd robot_sdkOption B — Already cloned but submodules not yet initialized:
git clone https://github.com/ZemsRepo/robot_sdk.git
cd robot_sdk
git submodule update --init --recursiveUpdate submodules to their latest remote version:
git submodule update --remote --recursivesource /opt/ros/humble/setup.bash# Build all packages
colcon build
# Build specific packages only
colcon build --packages-select aimdk_msgs aimdk_examples
# Build with keyboard input support (requires ncurses)
ENABLE_KEYBOARD=1 colcon build --packages-select aimdk_examples
# Build interface packages
colcon build --packages-select interface_protocol interface_examplesource install/setup.bashThe aimdk::Robot class provides a simple interface for controlling AgiBot robots:
#include "robot.h"
int main(int argc, char *argv[]) {
rclcpp::init(argc, argv);
auto robot = std::make_shared<aimdk::Robot>();
robot->OnInit();
robot->OnStart();
// Register as an input source
robot->RegisterInputSource();
// Show expression and speak
robot->ShowExpression(90, 1, 10);
robot->Speak("Hello, I am AgiBot X2!");
// Switch to walk mode and move forward
robot->SetAction(300 /*ACTION_WALK*/);
robot->Move(/*forward*/ 0.3, /*lateral*/ 0.0, /*angular*/ 0.0);
// Control hands
robot->SetHandPositions(/*left*/ 0.5f, /*right*/ 0.5f);
robot->OnShutdown();
rclcpp::shutdown();
}Launch the complete demo:
export PRODUCT=pm01
export LD_LIBRARY_PATH=/opt/engineai_robotics_third_party/lib:$LD_LIBRARY_PATH
ros2 launch aimdk_examples example.launch.pyHold all joints at their current position at 500 Hz:
ros2 run interface_example hold_joint_statusRun a single-joint motion test:
ros2 run interface_example joint_test_exampleRun the reinforcement learning locomotion policy:
ros2 launch interface_example rl_basic_example.launch.py| Executable | Description |
|---|---|
robot (main) |
Full workflow: walk, speak, gesture |
set_mc_action |
Set motion control action |
set_mc_input_source |
Register input source |
preset_motion_client |
Trigger preset motion |
mc_locomotion_velocity |
Publish locomotion velocity |
set_mc_locomotion_gait |
Set locomotion gait |
get_mc_locomotion_gait |
Query current gait |
hand_control |
Dexterous hand control |
omnihand_control |
OmniHand control |
motocontrol |
Direct motor control |
send_joint_command |
Send joint commands |
echo_camera_head_rear |
Head/rear camera feedback |
echo_camera_stereo |
Stereo camera feedback |
echo_camera_rgbd |
RGBD camera feedback |
echo_imu_data |
IMU data stream |
echo_lidar_data |
LiDAR data stream |
echo_hds_diagnostics |
System diagnostics |
play_tts |
Text-to-speech |
play_emoji |
Display expression |
play_video |
Play video on face display |
play_media |
Media playback |
mic_receiver |
Microphone audio input |
| Executable | Description |
|---|---|
hold_joint_status |
Subscribe joint state → publish hold command at 500 Hz |
joint_test_example |
Test individual joint movement with YAML config |
rl_basic_example |
RL policy inference loop using MNN model |
Hardware topics and services exposed by the robot:
| Topic / Service | Direction | Rate | Type | Description |
|---|---|---|---|---|
/hardware/joint_state |
Publish | ≥500 Hz | JointState |
Joint position, velocity, torque |
/hardware/joint_command |
Subscribe | 0–500 Hz | JointCommand |
Joint position/torque commands |
/hardware/imu_info |
Publish | ≥500 Hz | ImuInfo |
IMU sensor data |
/hardware/gamepad_keys |
Publish | ≥500 Hz | GamepadKeys |
Gamepad input |
/hardware/motor_debug |
Publish | ≥50 Hz | MotorDebug |
Temperature, torque feedback |
/motion/motion_state |
Publish | ≥5 Hz | MotionState |
Current motion task state |
/motion/body_vel_cmd |
Publish | ≥5 Hz | BodyVelCmd |
Body velocity (x: ±0.5 m/s, y: ±0.2 m/s, yaw: ±0.5 rad/s) |
RL and motor parameters are loaded from YAML files under:
engineai/interface_example/config/<PRODUCT>/
├── motor.yaml # Motor sign conventions and offsets
├── joint_test.yaml # Joint test parameters
├── pd_joint_test.yaml # PD control gains
└── rl_basic/basic/rl_basic_param.yaml # RL controller config
Key rl_basic_param.yaml fields:
policy_file: "/path/to/policy.mnn" # MNN model path
obs_dim: 48 # Observation dimension
action_dim: 12 # Action dimension
dt: 0.02 # Control period (s)
active_joints: [0, 1, 2, ...] # Joint indices used by policySet the robot model before launching:
export PRODUCT=pm01 # or se01, sa01// Lifecycle
bool OnInit();
bool OnStart();
void OnShutdown();
// Motion control
bool SetAction(int action_value, Ms timeout = Ms(0));
bool PresetMotion(int area_id, int motion_id, Ms timeout = Ms(0));
bool RegisterInputSource(int priority = 40, const std::string& source = "node",
int timeout_ms = 1000, Ms timeout = Ms(0));
bool Move(double forward_velocity, double lateral_velocity, double angular_velocity);
// Hand control
bool SetHandPositions(float left_position, float right_position, ...);
// Interaction
bool Speak(const std::string& text, ...);
bool ShowExpression(uint8_t emoji, uint8_t mode = 0, uint8_t priority = 0, Ms timeout = Ms(0));
bool PlayVideo(const std::string& video_path, uint8_t mode = 1, uint8_t priority = 5, Ms timeout = Ms(0));This project is licensed under the MIT License.