GDK Robot Interface Documentation (C++)¶
Overview¶
The Robot module provides a unified robot control interface for the G02 robot, integrating capabilities such as robot body state retrieval, motion control, joint control, and end-effector control. Through the C++ interface, developers can conveniently implement comprehensive control of the robot, suitable for scenarios such as robot control, state monitoring, action execution, and path planning.
Interface Description¶
Robot Class¶
This class encapsulates the robot's main control interfaces, integrating the HAL (Hardware Abstraction Layer) and motion control functionality.
1. GetJointStates()¶
- Note: Use motor_position and motor_velocity to get the motor position and velocity; position and velocity are fields reserved for low-speed motors and are not relevant in the current version
- Function: Retrieves the robot's joint state information
- Parameters:
| Parameter | Type | Description |
|---|---|---|
joint_states |
JointStates& |
Output parameter, joint state information object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success, and thejoint_statesparameter contains the joint state information
JointStates Object Details¶
The JointStates struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
nums |
size_t |
Number of joints | None |
states |
std::vector<JointState> |
List of joint states | List of joint states |
timestamp |
uint64_t |
Timestamp | Nanoseconds |
struct JointStates {
size_t nums{}; ///< number of joint states
std::vector<JointState> states{}; ///< joint states
uint64_t timestamp{}; ///< joint states timestamp(ns)
};
JointState struct:
| Member | Type | Description | Unit |
|---|---|---|---|
name |
std::string |
Joint name | String |
mode |
uint32_t |
Joint mode | None |
position |
double |
Joint position | Radians |
velocity |
double |
Joint velocity | Radians/second |
effort |
double |
Joint torque | N·m |
motor_position |
double |
Motor position | Radians |
motor_velocity |
double |
Motor velocity | Radians/second |
motor_current |
double |
Motor current | A |
error_code |
uint32_t |
Error code, 0 indicates normal | None |
struct JointState {
std::string name{};
uint32_t mode{};
double position{};
double velocity{};
double effort{};
double motor_position{};
double motor_velocity{};
double motor_current{};
uint32_t error_code{};
};
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::JointStates joint_states;
if (robot.GetJointStates(joint_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
} else {
std::cout << "Number of joints: " << joint_states.nums << std::endl;
std::cout << "Timestamp: " << joint_states.timestamp << std::endl;
for (const auto& joint_state : joint_states.states) {
std::cout << "Joint: " << joint_state.name
<< ", position: " << joint_state.position
<< ", velocity: " << joint_state.velocity
<< ", torque: " << joint_state.effort
<< ", error code: " << joint_state.error_code << std::endl;
}
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
2. GetEndState()¶
- Function: Retrieves end-effector state information
- Parameters:
| Parameter | Type | Description |
|---|---|---|
end_state |
DualEndState& |
Output parameter, dual end-effector state information object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success, and theend_stateparameter contains the end-effector state information
DualEndState Object Details¶
The DualEndState struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
left_end_state |
EndState |
Left end-effector state | End-effector state |
right_end_state |
EndState |
Right end-effector state | End-effector state |
EndState struct:
| Member | Type | Description | Unit |
|---|---|---|---|
controlled |
bool |
Whether it is under control | Boolean |
type |
uint32_t |
End-effector type | None |
names |
std::vector<std::string> |
List of joint names | List of strings |
end_states |
std::vector<MotorState> |
List of motor states | List of motor states |
struct EndState {
bool controlled{};
uint32_t type{};
std::vector<std::string> names{};
std::vector<MotorState> end_states{};
};
MotorState struct:
| Member | Type | Description | Unit |
|---|---|---|---|
id |
uint32_t |
Motor ID | None |
enable |
bool |
Whether enabled | Boolean |
position |
double |
Motor position | Radians |
velocity |
double |
Motor velocity | Radians/second |
effort |
double |
Motor torque | N·m |
current |
float |
Motor current | A |
voltage |
float |
Motor voltage | V |
temperature |
float |
Motor temperature | °C |
status |
uint32_t |
Motor status | None |
err_code |
uint32_t |
Error code | None |
struct MotorState {
uint32_t id = 0;
bool enable = false;
double position = 0.0;
double velocity = 0.0;
double effort = 0.0;
float current = 0.0f;
float voltage = 0.0f;
float temperature = 0.0f;
uint32_t status = 0;
uint32_t err_code = 0;
};
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::DualEndState end_state;
if (robot.GetEndState(end_state) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to get end state" << std::endl;
} else {
std::cout << "Left end-effector state:" << std::endl;
std::cout << " Control state: " << (end_state.left_end_state.controlled ? "Yes" : "No") << std::endl;
std::cout << " Type: " << end_state.left_end_state.type << std::endl;
for (const auto& motor_state : end_state.left_end_state.end_states) {
std::cout << " Motor ID: " << motor_state.id
<< ", position: " << motor_state.position
<< ", current: " << motor_state.current
<< ", temperature: " << motor_state.temperature << std::endl;
}
std::cout << "Right end-effector state:" << std::endl;
std::cout << " Control state: " << (end_state.right_end_state.controlled ? "Yes" : "No") << std::endl;
std::cout << " Type: " << end_state.right_end_state.type << std::endl;
for (const auto& motor_state : end_state.right_end_state.end_states) {
std::cout << " Motor ID: " << motor_state.id
<< ", position: " << motor_state.position
<< ", current: " << motor_state.current
<< ", temperature: " << motor_state.temperature << std::endl;
}
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
3. GetWholeBodyStatus()¶
- Function: Retrieves the robot's whole-body state information
- Parameters:
| Parameter | Type | Description |
|---|---|---|
whole_body_status |
WholeBodyStatus& |
Output parameter, whole-body state information object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success, and thewhole_body_statusparameter contains the whole-body state information
WholeBodyStatus Object Details¶
The WholeBodyStatus struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
right_arm_error |
uint32_t |
Right arm error code | None |
left_arm_error |
uint32_t |
Left arm error code | None |
right_arm_control |
bool |
Right arm control state | Boolean |
left_arm_control |
bool |
Left arm control state | Boolean |
right_arm_estop |
bool |
Right arm emergency-stop state | Boolean |
left_arm_estop |
bool |
Left arm emergency-stop state | Boolean |
right_end_error |
uint32_t |
Right end-effector error code | None |
left_end_error |
uint32_t |
Left end-effector error code | None |
right_end_model |
std::string |
Right end-effector model | String |
left_end_model |
std::string |
Left end-effector model | String |
waist_error |
uint32_t |
Waist error code | None |
lift_error |
uint32_t |
Lift error code | None |
neck_error |
uint32_t |
Neck error code | None |
chassis_error |
uint32_t |
Chassis error code | None |
timestamp |
uint64_t |
Timestamp | Nanoseconds |
struct WholeBodyStatus {
uint32_t right_arm_error{0};
uint32_t left_arm_error{0};
bool right_arm_control{false};
bool left_arm_control{false};
bool right_arm_estop{false};
bool left_arm_estop{false};
uint32_t right_end_error{0};
uint32_t left_end_error{0};
std::string right_end_model{};
std::string left_end_model{};
uint32_t waist_error{0};
uint32_t lift_error{0};
uint32_t neck_error{0};
uint32_t chassis_error{0};
uint64_t timestamp{};
};
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::WholeBodyStatus whole_body_status;
if (robot.GetWholeBodyStatus(whole_body_status) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to get whole body status" << std::endl;
} else {
std::cout << "Whole-body state information:" << std::endl;
std::cout << "Right arm error code: " << whole_body_status.right_arm_error << std::endl;
std::cout << "Left arm error code: " << whole_body_status.left_arm_error << std::endl;
std::cout << "Right arm control state: " << (whole_body_status.right_arm_control ? "Yes" : "No") << std::endl;
std::cout << "Left arm control state: " << (whole_body_status.left_arm_control ? "Yes" : "No") << std::endl;
std::cout << "Right arm emergency-stop state: " << (whole_body_status.right_arm_estop ? "Yes" : "No") << std::endl;
std::cout << "Left arm emergency-stop state: " << (whole_body_status.left_arm_estop ? "Yes" : "No") << std::endl;
std::cout << "Right end-effector model: " << whole_body_status.right_end_model << std::endl;
std::cout << "Left end-effector model: " << whole_body_status.left_end_model << std::endl;
std::cout << "Waist error code: " << whole_body_status.waist_error << std::endl;
std::cout << "Lift error code: " << whole_body_status.lift_error << std::endl;
std::cout << "Neck error code: " << whole_body_status.neck_error << std::endl;
std::cout << "Chassis error code: " << whole_body_status.chassis_error << std::endl;
std::cout << "Timestamp: " << whole_body_status.timestamp << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
4. GetMotionControlStatus()¶
- Function: Retrieves the end-effector control status information
- Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
MotionControlStatus& |
Output parameter, end-effector control status object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success, and thestatusparameter contains the motion control status information
MotionControlStatus Object Details¶
The MotionControlStatus struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
frame_names |
std::vector<std::string> |
List of end-effector joint names | List of strings |
frame_poses |
std::vector<Pose> |
List of end-effector joint poses | List of poses |
collision_pairs_1 |
std::vector<std::string> |
Collision pair list 1 | List of strings |
collision_pairs_2 |
std::vector<std::string> |
Collision pair list 2 | List of strings |
mode |
uint8_t |
Motion mode | None |
error_code |
uint8_t |
Error code, 0 indicates normal | None |
error_msg |
std::string |
Error message | String |
twists |
std::vector<Twist> |
List of velocity information | List of velocities |
wrenches |
std::vector<Wrench> |
List of force/torque information | List of forces/torques |
Description of mode values:
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::MotionControlStatus status;
if (robot.GetMotionControlStatus(status) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to get motion control status" << std::endl;
} else {
std::cout << "End-effector control status:" << std::endl;
std::cout << "Mode: " << status.mode << std::endl;
std::cout << "Error code: " << status.error_code << std::endl;
std::cout << "Error message: " << status.error_msg << std::endl;
std::cout << "Number of joints: " << status.frame_names.size() << std::endl;
for (size_t i = 0; i < status.frame_names.size(); i++) {
std::cout << "Joint: " << status.frame_names[i]
<< ", position: x=" << status.frame_poses[i].position.x
<< ", y=" << status.frame_poses[i].position.y
<< ", z=" << status.frame_poses[i].position.z << std::endl;
}
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
5. GetChassisPowerState()¶
- Function: Retrieves the chassis power state
- Parameters:
| Parameter | Type | Description |
|---|---|---|
chassis_power_state |
ChassisPowerState& |
Chassis power state object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success
ChassisPowerState Object Details¶
The ChassisPowerState struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
battery_main_power_switch_state |
uint8_t |
Battery main power switch state | None |
emergency_stop_pedal_state |
uint8_t |
Emergency stop pedal state | None |
battery_main_power_switch_fault_state |
uint8_t |
Battery main power switch fault state | None |
emergency_stop_pedal_fault_state |
uint8_t |
Emergency stop pedal fault state | None |
chassis_power_board_state |
uint8_t |
Chassis power board state | None |
chassis_left_traction_motor_power_state |
uint8_t |
Chassis left traction motor power state | None |
chassis_right_traction_motor_power_state |
uint8_t |
Chassis right traction motor power state | None |
chassis_left_steering_motor_power_state |
uint8_t |
Chassis left steering motor power state | None |
chassis_right_steering_motor_power_state |
uint8_t |
Chassis right steering motor power state | None |
chassis_lidar1_power_state |
uint8_t |
Chassis lidar 1 power state | None |
chassis_lidar2_power_state |
uint8_t |
Chassis lidar 2 power state | None |
chassis_ultrasonic_radar_power_state |
uint8_t |
Chassis ultrasonic radar power state | None |
chassis_tof_camera_power_state |
uint8_t |
Chassis ToF camera power state | None |
chassis_ethernet_switch_power_state |
uint8_t |
Chassis Ethernet switch power state | None |
chassis_external_power_output_state |
uint8_t |
Chassis external power output state | None |
battery_main_power_output_switch_state |
uint8_t |
Battery main power output switch state | None |
battery_states |
std::vector<BatteryState> |
List of battery states | List of battery states |
charge_plug_insert_state |
uint8_t |
Charging plug insertion state | None |
charge_plug_input_voltage |
float |
Charging plug input voltage | V |
charge_plug_input_current |
float |
Charging plug input current | A |
charge_plug_input_short_circuit_fault_state |
uint8_t |
Charging plug input short-circuit fault state | None |
charge_plug_input_open_circuit_fault_state |
uint8_t |
Charging plug input open-circuit fault state | None |
chassis_led_strip_power_state |
uint8_t |
Chassis LED strip power state | None |
chassis_power_board_temperature |
float |
Chassis power board temperature | °C |
power_48v_bus_power_on_fault_state |
uint8_t |
48V bus power-on fault state | None |
power_poe_bus_power_on_fault_state |
uint8_t |
PoE bus power-on fault state | None |
chassis_board_12v_output_fault_state |
uint8_t |
Chassis board 12V output fault state | None |
chassis_board_5v_output_fault_state |
uint8_t |
Chassis board 5V output fault state | None |
chassis_power_board_fault_state |
uint32_t |
Chassis power board fault state | None |
timestamp |
uint64_t |
Timestamp | Nanoseconds |
struct ChassisPowerState {
uint8_t battery_main_power_switch_state{0};
uint8_t emergency_stop_pedal_state{0};
uint8_t battery_main_power_switch_fault_state{0};
uint8_t emergency_stop_pedal_fault_state{0};
uint8_t chassis_power_board_state{0};
uint8_t chassis_left_traction_motor_power_state{0};
uint8_t chassis_right_traction_motor_power_state{0};
uint8_t chassis_left_steering_motor_power_state{0};
uint8_t chassis_right_steering_motor_power_state{0};
uint8_t chassis_lidar1_power_state{0};
uint8_t chassis_lidar2_power_state{0};
uint8_t chassis_ultrasonic_radar_power_state{0};
uint8_t chassis_tof_camera_power_state{0};
uint8_t chassis_ethernet_switch_power_state{0};
uint8_t chassis_external_power_output_state{0};
uint8_t battery_main_power_output_switch_state{0};
std::vector<BatteryState> battery_states{};
uint8_t charge_plug_insert_state{0};
float charge_plug_input_voltage{0.0};
float charge_plug_input_current{0.0};
uint8_t charge_plug_input_short_circuit_fault_state{0};
uint8_t charge_plug_input_open_circuit_fault_state{0};
uint8_t chassis_led_strip_power_state{0};
float chassis_power_board_temperature{0.0};
uint8_t power_48v_bus_power_on_fault_state{0};
uint8_t power_poe_bus_power_on_fault_state{0};
uint8_t chassis_board_12v_output_fault_state{0};
uint8_t chassis_board_5v_output_fault_state{0};
uint32_t chassis_power_board_fault_state{0};
uint64_t timestamp{0};
};
BatteryState struct:
| Member | Type | Description | Unit |
|---|---|---|---|
battery_charging_status |
uint8_t |
Battery charging status | None |
battery_output_voltage |
float |
Battery output voltage | V |
battery_output_current |
float |
Battery output current | A |
battery_charging_current |
float |
Battery charging current | A |
battery_temperature |
float |
Battery temperature | °C |
battery_soc |
float |
Battery charge percentage (State of Charge) | % |
battery_soh |
uint8_t |
Battery health (State of Health) | % |
battery_short_circuit_fault_state |
uint8_t |
Battery short-circuit fault state | None |
battery_open_circuit_fault_state |
uint8_t |
Battery open-circuit fault state | None |
battery_other_fault_state |
uint8_t |
Battery other fault state | None |
battery_outside_output_voltage |
float |
Battery external output voltage | V |
battery_outside_connection |
uint8_t |
Battery external connection state | None |
battery_outside_open_circuit_fault_state |
uint8_t |
Battery external open-circuit fault state | None |
battery_switch_state |
uint8_t |
Battery switch state | None |
battery_unlock_state |
uint8_t |
Battery unlock state | None |
battery_input_fault_state |
uint8_t |
Battery input fault state | None |
battery_charging_mos_switch_state |
uint8_t |
Battery charging MOS switch state | None |
struct BatteryState {
uint8_t battery_charging_status{0};
float battery_output_voltage{0.0};
float battery_output_current{0.0};
float battery_charging_current{0.0};
float battery_temperature{0.0};
float battery_soc{0.0};
uint8_t battery_soh{0};
uint8_t battery_short_circuit_fault_state{0};
uint8_t battery_open_circuit_fault_state{0};
uint8_t battery_other_fault_state{0};
float battery_outside_output_voltage{0.0};
uint8_t battery_outside_connection{0};
uint8_t battery_outside_open_circuit_fault_state{0};
uint8_t battery_switch_state{0};
uint8_t battery_unlock_state{0};
uint8_t battery_input_fault_state{0};
uint8_t battery_charging_mos_switch_state{0};
};
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::ChassisPowerState chassis_power_state;
if (robot.GetChassisPowerState(chassis_power_state) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to get chassis power state" << std::endl;
} else {
std::cout << "Chassis power state information:" << std::endl;
std::cout << " Battery main power switch: " << (int)chassis_power_state.battery_main_power_switch_state << std::endl;
std::cout << " Emergency stop pedal state: " << (int)chassis_power_state.emergency_stop_pedal_state << std::endl;
std::cout << " Chassis power board state: " << (int)chassis_power_state.chassis_power_board_state << std::endl;
std::cout << " Chassis power board temperature: " << chassis_power_state.chassis_power_board_temperature << "°C" << std::endl;
std::cout << " Charging plug input voltage: " << chassis_power_state.charge_plug_input_voltage << "V" << std::endl;
std::cout << " Charging plug input current: " << chassis_power_state.charge_plug_input_current << "A" << std::endl;
std::cout << " Number of batteries: " << chassis_power_state.battery_states.size() << std::endl;
for (size_t i = 0; i < chassis_power_state.battery_states.size(); i++) {
const auto& battery = chassis_power_state.battery_states[i];
std::cout << " Battery " << i << ":" << std::endl;
std::cout << " Charge: " << battery.battery_soc << "%" << std::endl;
std::cout << " Health: " << (int)battery.battery_soh << "%" << std::endl;
std::cout << " Voltage: " << battery.battery_output_voltage << "V" << std::endl;
std::cout << " Current: " << battery.battery_output_current << "A" << std::endl;
std::cout << " Temperature: " << battery.battery_temperature << "°C" << std::endl;
}
std::cout << " Timestamp: " << chassis_power_state.timestamp << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
6. GetChestPowerState()¶
- Function: Retrieves the chest power state
- Parameters:
| Parameter | Type | Description |
|---|---|---|
chest_power_state |
ChestPowerState& |
Output parameter, chest power state object |
- Return value:
GDKRes, the operation result status code.
ChestPowerState Object Details¶
The ChestPowerState struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
power_onoff_req |
uint8_t |
Power on/off request | None |
emergency_stop_button_req |
uint8_t |
Emergency stop button request | None |
power_switch_fault_state |
uint8_t |
Power switch fault state | None |
emergency_stop_button_fault_state |
uint8_t |
Emergency stop button fault state | None |
power_full_low_req |
uint8_t |
Power full/low request | None |
chest_power_board_power_state |
uint8_t |
Chest power board power state | None |
domain_controller_power_state |
uint8_t |
Domain controller power state | None |
head_interactive_board_power_state |
uint8_t |
Head interactive board power state | None |
curved_screen_power_state |
uint8_t |
Curved screen power state | None |
head_yaw_motor_power_state |
uint8_t |
Head yaw motor power state | None |
head_pitch_motor_power_state |
uint8_t |
Head pitch motor power state | None |
head_roll_motor_power_state |
uint8_t |
Head roll motor power state | None |
waist_yaw_motor_power_state |
uint8_t |
Waist yaw motor power state | None |
head_motor_short_circuit_fault_state |
uint8_t |
Head motor short-circuit fault state | None |
waist_pitch_motor_power_state |
uint8_t |
Waist pitch motor power state | None |
leg_bending1_motor_power_state |
uint8_t |
Leg bending 1 motor power state | None |
leg_bending2_motor_power_state |
uint8_t |
Leg bending 2 motor power state | None |
leg_bending3_motor_power_state |
uint8_t |
Leg bending 3 motor power state | None |
waist_motor_short_circuit_fault_state |
uint8_t |
Waist motor short-circuit fault state | None |
left_arm_power_state |
uint8_t |
Left arm power state | None |
left_arm_motor_short_circuit_fault_state |
uint8_t |
Left arm motor short-circuit fault state | None |
left_arm_brake_enable_state |
uint8_t |
Left arm brake enable state | None |
right_arm_power_state |
uint8_t |
Right arm power state | None |
right_arm_motor_short_circuit_fault_state |
uint8_t |
Right arm motor short-circuit fault state | None |
right_arm_brake_enable_state |
uint8_t |
Right arm brake enable state | None |
fan_power_state |
uint8_t |
Fan power state | None |
chest_power_board_fan_fault_state |
uint8_t |
Chest power board fan fault state | None |
body_fan1_fault_state |
uint8_t |
Body fan 1 fault state | None |
body_fan2_fault_state |
uint8_t |
Body fan 2 fault state | None |
body_fan3_fault_state |
uint8_t |
Body fan 3 fault state | None |
body_fan4_fault_state |
uint8_t |
Body fan 4 fault state | None |
upper_body_led_strip_power_state |
uint8_t |
Upper body LED strip power state | None |
poe_power_state |
uint8_t |
PoE power state | None |
ipad_power_state |
uint8_t |
iPad power state | None |
chest_reserved_lidar_power_state |
uint8_t |
Chest reserved lidar power state | None |
chest_power_board_temperature |
float |
Chest power board temperature | °C |
chest_power_board_fault_state |
uint32_t |
Chest power board fault state | None |
timestamp |
uint64_t |
Timestamp | Nanoseconds |
struct ChestPowerState {
uint8_t power_onoff_req{0};
uint8_t emergency_stop_button_req{0};
uint8_t power_switch_fault_state{0};
uint8_t emergency_stop_button_fault_state{0};
uint8_t power_full_low_req{0};
uint8_t chest_power_board_power_state{0};
uint8_t domain_controller_power_state{0};
uint8_t head_interactive_board_power_state{0};
uint8_t curved_screen_power_state{0};
uint8_t head_yaw_motor_power_state{0};
uint8_t head_pitch_motor_power_state{0};
uint8_t head_roll_motor_power_state{0};
uint8_t waist_yaw_motor_power_state{0};
uint8_t head_motor_short_circuit_fault_state{0};
uint8_t waist_pitch_motor_power_state{0};
uint8_t leg_bending1_motor_power_state{0};
uint8_t leg_bending2_motor_power_state{0};
uint8_t leg_bending3_motor_power_state{0};
uint8_t waist_motor_short_circuit_fault_state{0};
uint8_t left_arm_power_state{0};
uint8_t left_arm_motor_short_circuit_fault_state{0};
uint8_t left_arm_brake_enable_state{0};
uint8_t right_arm_power_state{0};
uint8_t right_arm_motor_short_circuit_fault_state{0};
uint8_t right_arm_brake_enable_state{0};
uint8_t fan_power_state{0};
uint8_t chest_power_board_fan_fault_state{0};
uint8_t body_fan1_fault_state{0};
uint8_t body_fan2_fault_state{0};
uint8_t body_fan3_fault_state{0};
uint8_t body_fan4_fault_state{0};
uint8_t upper_body_led_strip_power_state{0};
uint8_t poe_power_state{0};
uint8_t ipad_power_state{0};
uint8_t chest_reserved_lidar_power_state{0};
float chest_power_board_temperature{0.0};
uint32_t chest_power_board_fault_state{0};
uint64_t timestamp{0};
};
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::ChestPowerState chest_state;
if (robot.GetChestPowerState(chest_state) == agibot::gdk::GDKRes::kSuccess) {
std::cout << "Chest power state information:" << std::endl;
std::cout << " Power on/off request: " << (int)chest_state.power_onoff_req << std::endl;
std::cout << " Emergency stop button request: " << (int)chest_state.emergency_stop_button_req << std::endl;
std::cout << " Chest power board state: " << (int)chest_state.chest_power_board_power_state << std::endl;
std::cout << " Chest power board temperature: " << chest_state.chest_power_board_temperature << "°C" << std::endl;
std::cout << " Domain controller power: " << (int)chest_state.domain_controller_power_state << std::endl;
std::cout << " Left arm power: " << (int)chest_state.left_arm_power_state << std::endl;
std::cout << " Right arm power: " << (int)chest_state.right_arm_power_state << std::endl;
std::cout << " Left arm brake enable: " << (int)chest_state.left_arm_brake_enable_state << std::endl;
std::cout << " Right arm brake enable: " << (int)chest_state.right_arm_brake_enable_state << std::endl;
std::cout << " Head yaw motor power: " << (int)chest_state.head_yaw_motor_power_state << std::endl;
std::cout << " Head pitch motor power: " << (int)chest_state.head_pitch_motor_power_state << std::endl;
std::cout << " Head roll motor power: " << (int)chest_state.head_roll_motor_power_state << std::endl;
std::cout << " Fan power: " << (int)chest_state.fan_power_state << std::endl;
std::cout << " Timestamp: " << chest_state.timestamp << std::endl;
} else {
std::cout << "Failed to get chest power state" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
7. JointControl()¶
- Function: Joint control interface (path-planning control); the interface returns after the target position is reached.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
joint_control_req |
const JointControlReq& |
Joint control request object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success
JointControlReq Object Details¶
The JointControlReq struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
uuid |
std::string |
Unique request identifier | String |
life_time |
double |
Request lifetime | Seconds |
joint_names |
std::vector<std::string> |
List of joint names | List of strings |
joint_positions |
std::vector<double> |
List of joint positions | Radians |
joint_velocities |
std::vector<double> |
List of joint velocities | Radians/second |
detail |
std::string |
Detailed information | String |
struct JointControlReq {
double life_time{0.0};
std::vector<std::string> joint_names{};
std::vector<double> joint_positions{};
std::vector<double> joint_velocities{};
std::string uuid{};
std::string detail{};
};
Joint Limit Values¶
The limit values for each joint (in radians) are as follows:
| Joint Name | Minimum | Maximum |
|---|---|---|
idx01_body_joint1 |
-1.082104 | 0.000174 |
idx02_body_joint2 |
-0.000174 | 2.652900 |
idx03_body_joint3 |
-1.919862 | 1.570970 |
idx04_body_joint4 |
-0.436332 | 0.436332 |
idx05_body_joint5 |
-3.045599 | 3.045599 |
idx11_head_joint1 |
-1.570970 | 1.570970 |
idx12_head_joint2 |
-0.349240 | 0.349240 |
idx13_head_joint3 |
-0.534773 | 0.534773 |
idx21_arm_l_joint1 |
-3.071796 | 3.071796 |
idx22_arm_l_joint2 |
-2.059505 | 2.059505 |
idx23_arm_l_joint3 |
-3.071796 | 3.071796 |
idx24_arm_l_joint4 |
-2.495838 | 1.012308 |
idx25_arm_l_joint5 |
-3.071796 | 3.071796 |
idx26_arm_l_joint6 |
-1.012308 | 1.012308 |
idx27_arm_l_joint7 |
-1.535907 | 1.535907 |
idx61_arm_r_joint1 |
-3.071796 | 3.071796 |
idx62_arm_r_joint2 |
-2.059505 | 2.059505 |
idx63_arm_r_joint3 |
-3.071796 | 3.071796 |
idx64_arm_r_joint4 |
-2.495838 | 1.012308 |
idx65_arm_r_joint5 |
-3.071796 | 3.071796 |
idx66_arm_r_joint6 |
-1.012308 | 1.012308 |
idx67_arm_r_joint7 |
-1.535907 | 1.535907 |
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <random>
#include <sstream>
std::string generate_uuid() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint32_t> dis(0, 0xFFFFFFFF);
std::stringstream ss;
ss << std::hex << dis(gen) << "-" << dis(gen) << "-" << dis(gen) << "-" << dis(gen);
return ss.str();
}
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
agibot::gdk::JointControlReq joint_control;
joint_control.life_time = 5.0;
joint_control.joint_names = {"idx21_arm_l_joint1","idx22_arm_l_joint2","idx23_arm_l_joint3"};
joint_control.joint_positions = {0.0, 0.0, 0.0};
joint_control.joint_velocities = {0.0, 0.0, 0.0};
joint_control.detail = "Left arm joint control";
if (robot.JointControl(joint_control) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to control joints" << std::endl;
} else {
std::cout << "Joint control command sent successfully" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
8. MoveHeadJoint()¶
- Function: Head joint position planning control interface; the interface returns after the target position is reached.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
std::vector<double>& |
List of head joint positions; fill in the target joint angles in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3" |
velocities |
const std::vector<double>& |
List of head joint velocities; fill in the target joint velocities in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3" |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::vector<double> head_positions = {0.0, 0.0, 0.0}; // Head joint positions
std::vector<double> head_velocities = {0.3, 0.3, 0.3}; // Head joint velocities
if (robot.MoveHeadJoint(head_positions, head_velocities) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move head position" << std::endl;
} else {
std::cout << "Head position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
9. MoveWaistJoint()¶
- Function: Waist joint position planning control interface; the interface returns after the target position is reached.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
std::vector<double>& |
List of waist joint positions; fill in the target joint angles in the order "idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5" |
velocities |
const std::vector<double>& |
List of waist joint velocities; fill in the target joint velocities in the order "idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5" |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::vector<double> waist_positions = {0.0, 0.0, 0.0, 0.0, 0.0}; // Waist joint positions
std::vector<double> waist_velocities = {0.3, 0.3, 0.3, 0.3, 0.3}; // Waist joint velocities
if (robot.MoveWaistJoint(waist_positions, waist_velocities) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move waist position" << std::endl;
} else {
std::cout << "Waist position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
10. MoveArmJoint()¶
- Function: Arm joint position planning control interface; the interface returns after the target position is reached.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
std::vector<double>& |
List of arm joint positions; fill in the target joint angles in the order "idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3", |
| "idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6", | ||
| "idx27_arm_l_joint7", "idx61_arm_r_joint1", "idx62_arm_r_joint2", | ||
| "idx63_arm_r_joint3", "idx64_arm_r_joint4", "idx65_arm_r_joint5", | ||
| "idx66_arm_r_joint6", "idx67_arm_r_joint7" | ||
velocities |
const std::vector<double>& |
List of arm joint velocities; fill in the target joint velocities in the order "idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3", |
| "idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6", | ||
| "idx27_arm_l_joint7", "idx61_arm_r_joint1", "idx62_arm_r_joint2", | ||
| "idx63_arm_r_joint3", "idx64_arm_r_joint4", "idx65_arm_r_joint5", | ||
| "idx66_arm_r_joint6", "idx67_arm_r_joint7" | ||
control_group |
const int |
Control group: 0 controls the left arm, 1 controls the right arm, 2 controls both arms |
- Return value: GDKRes, the operation result status code. Returns GDKRes::kSuccess on success |
- Example:
#include "gdk/gdk.h"
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::vector<double> arm_positions = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // Arm joint positions
std::vector<double> arm_velocities = {0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3}; // Arm joint velocities
if (robot.MoveArmJoint(arm_positions, arm_velocities, 2) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move arm position" << std::endl;
} else {
std::cout << "Arm position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
11. JointServoControl()¶
- Function: Joint position servo control interface. It must be controlled at a 100 Hz control frequency and supports normal mode and low-latency mode; normal mode is used by default.
- Note: Low-latency mode has no collision protection; use it with caution for safety. To simultaneously control the end-effector, use this interface to issue control commands — see the example below for details.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
joint_servo_control_req |
const JointServoControlReq& |
Joint position servo request object |
enable_low_latency |
bool |
Whether to enable low-latency mode; defaults to false |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success
JointServoControlReq Object Details¶
The JointServoControlReq struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
control_period |
double |
Control period | Seconds |
joint_names |
std::vector<std::string> |
List of joint names | List of strings |
joint_positions |
std::vector<double> |
List of joint positions | Radians |
joint_velocities |
std::vector<double> |
List of joint velocities | Radians/second |
struct JointServoControlReq {
double control_period{0.0};
std::vector<std::string> joint_names{};
std::vector<double> joint_positions{};
std::vector<double> joint_velocities{};
};
Parameter description:
- control_period indicates the control period, in seconds; it is recommended to set it slightly larger than the current control frequency
- The three lists joint_names, joint_positions, and joint_velocities must have the same length
- The values in joint_positions must be within the corresponding joint's limit range (see the joint limit values below); otherwise, ErrorCode::kInvalidInput is returned
- joint_names, joint_positions, and joint_velocities cannot be empty; otherwise, ErrorCode::kInvalidInput is returned
- joint_velocities is a reserved parameter that is currently unused and may be left empty
Joint Limit Values¶
The limit values for each joint (in radians) are as follows:
| Joint Name | Minimum | Maximum |
|---|---|---|
idx01_body_joint1 |
-1.082104 | 0.000174 |
idx02_body_joint2 |
-0.000174 | 2.652900 |
idx03_body_joint3 |
-1.919862 | 1.570970 |
idx04_body_joint4 |
-0.436332 | 0.436332 |
idx05_body_joint5 |
-3.045599 | 3.045599 |
idx11_head_joint1 |
-1.570970 | 1.570970 |
idx12_head_joint2 |
-0.349240 | 0.349240 |
idx13_head_joint3 |
-0.534773 | 0.534773 |
idx21_arm_l_joint1 |
-3.071796 | 3.071796 |
idx22_arm_l_joint2 |
-2.059505 | 2.059505 |
idx23_arm_l_joint3 |
-3.071796 | 3.071796 |
idx24_arm_l_joint4 |
-2.495838 | 1.012308 |
idx25_arm_l_joint5 |
-3.071796 | 3.071796 |
idx26_arm_l_joint6 |
-1.012308 | 1.012308 |
idx27_arm_l_joint7 |
-1.535907 | 1.535907 |
idx61_arm_r_joint1 |
-3.071796 | 3.071796 |
idx62_arm_r_joint2 |
-2.059505 | 2.059505 |
idx63_arm_r_joint3 |
-3.071796 | 3.071796 |
idx64_arm_r_joint4 |
-2.495838 | 1.012308 |
idx65_arm_r_joint5 |
-3.071796 | 3.071796 |
idx66_arm_r_joint6 |
-1.012308 | 1.012308 |
idx67_arm_r_joint7 |
-1.535907 | 1.535907 |
| End-effector (omnipicker) | ||
idx31_gripper_l_inner_joint1 |
-0.785 | 0 |
idx71_gripper_r_inner_joint1 |
-0.785 | 0 |
| End-effector (dahuan) | ||
idx31_gripper_l_inner_joint1 |
0 | 0.025 |
idx71_gripper_r_inner_joint1 |
0 | 0.025 |
| End-effector (ctek90d) | ||
idx31_gripper_l_inner_joint1 |
-0.91 | 0 |
idx71_gripper_r_inner_joint1 |
-0.91 | 0 |
| End-effector (o10_t2 dexterous hand, left) | ||
idx31_hand_l_thumb_roll_joint |
-1.1213740444063567 | 0.029670597283903602 |
idx32_hand_l_thumb_abad_joint |
-0.04537856055185257 | 1.642354826126664 |
idx33_hand_l_thumb_mcp_joint |
-0.8415977653116657 | 0.0 |
idx36_hand_l_index_abad_joint |
0.0 | 0.16406094968746698 |
idx37_hand_l_index_pip_joint |
0.0 | 1.4835298641951802 |
idx39_hand_l_middle_pip_joint |
0.0 | 1.4835298641951802 |
idx41_hand_l_ring_abad_joint |
-0.16929693744344995 | 0.0 |
idx42_hand_l_ring_pip_joint |
0.0 | 1.4835298641951802 |
idx44_hand_l_pinky_abad_joint |
-0.1850049007113989 | 0.0 |
idx45_hand_l_pinky_pip_joint |
0.0 | 1.4835298641951802 |
| End-effector (o10_t2 dexterous hand, right) | ||
idx71_hand_r_thumb_roll_joint |
-0.029670597283903602 | 1.1213740444063567 |
idx72_hand_r_thumb_abad_joint |
-1.642354826126664 | 0.04537856055185257 |
idx73_hand_r_thumb_mcp_joint |
0.0 | 0.8415977653116657 |
idx76_hand_r_index_abad_joint |
-0.16406094968746698 | 0.0 |
idx77_hand_r_index_pip_joint |
0.0 | 1.4835298641951802 |
idx79_hand_r_middle_pip_joint |
0.0 | 1.4835298641951802 |
idx81_hand_r_ring_abad_joint |
0.0 | 0.16929693744344995 |
idx82_hand_r_ring_pip_joint |
0.0 | 1.4835298641951802 |
idx84_hand_r_pinky_abad_joint |
0.0 | 0.1850049007113989 |
idx85_hand_r_pinky_pip_joint |
0.0 | 1.4835298641951802 |
| End-effector (o12_t2 dexterous hand, left) | ||
idx31_hand_l_thumb_roll_joint |
-0.9425 | 0.0 |
idx32_hand_l_thumb_abad_joint |
0.0 | 1.3875 |
idx33_hand_l_thumb_mcp_joint |
-0.8273 | 0.0 |
idx34_hand_l_thumb_pip_joint |
-1.2915 | 0.0 |
idx36_hand_l_index_abad_joint |
-0.2618 | 0.2618 |
idx37_hand_l_index_mcp_joint |
0.0 | 1.3526 |
idx38_hand_l_index_pip_joint |
0.0 | 1.5307 |
idx40_hand_l_middle_abad_joint |
-0.2618 | 0.2618 |
idx41_hand_l_middle_mcp_joint |
0.0 | 1.3579 |
idx42_hand_l_middle_pip_joint |
0.0 | 1.8151 |
idx44_hand_l_ring_mcp_joint |
0.0 | 1.5359 |
idx47_hand_l_pinky_mcp_joint |
0.0 | 1.5359 |
| End-effector (o12_t2 dexterous hand, right) | ||
idx71_hand_r_thumb_roll_joint |
0.0 | 0.9425 |
idx72_hand_r_thumb_abad_joint |
-1.3875 | 0.0 |
idx73_hand_r_thumb_mcp_joint |
-0.8273 | 0.0 |
idx74_hand_r_thumb_pip_joint |
-1.2915 | 0.0 |
idx76_hand_r_index_abad_joint |
-0.2618 | 0.2618 |
idx77_hand_r_index_mcp_joint |
0.0 | 1.3526 |
idx78_hand_r_index_pip_joint |
0.0 | 1.5307 |
idx80_hand_r_middle_abad_joint |
-0.2618 | 0.2618 |
idx81_hand_r_middle_mcp_joint |
0.0 | 1.3579 |
idx82_hand_r_middle_pip_joint |
0.0 | 1.8151 |
idx84_hand_r_ring_mcp_joint |
0.0 | 1.5359 |
idx87_hand_r_pinky_mcp_joint |
0.0 | 1.5359 |
- Error handling:
- If
joint_namesorjoint_positionsis empty,ErrorCode::kInvalidInputis returned - If the values in
joint_positionsexceed the corresponding joint's limit range,ErrorCode::kInvalidInputis returned - If retrieving the configuration parser fails,
ErrorCode::kRuntimeErroris returned -
For other error conditions, the corresponding error code is returned
-
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <algorithm>
using namespace agibot::gdk;
// Control parameters
const double CONTROL_PERIOD = 0.01; // Control period (seconds)
const double RATE_HZ = 100.0; // Send frequency (Hz)
const double DURATION = 5.0; // Control duration (seconds)
class JointServoControlController {
private:
Robot robot_;
double getJointPositionByName(const JointStates& joint_states, const std::string& joint_name) {
for (const auto& state : joint_states.states) {
if (state.name == joint_name) {
return state.motor_position;
}
}
throw std::runtime_error("Joint name " + joint_name + " not found");
}
double interpolatePosition(double start_pos, double target_pos, double t) {
return start_pos + t * (target_pos - start_pos);
}
public:
void executeJointServoControl(const std::vector<std::string>& target_joint_names,
const std::vector<double>& target_positions) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait 1 second
// Get current joint states
JointStates current_joint_states;
if (robot_.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
return;
}
std::cout << "Current number of joints: " << current_joint_states.nums << std::endl;
// Get the starting position
std::vector<double> start_positions;
for (const auto& joint_name : target_joint_names) {
try {
double pos = getJointPositionByName(current_joint_states, joint_name);
start_positions.push_back(pos);
std::cout << "Joint " << joint_name << " current position: " << pos << " rad" << std::endl;
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
return;
}
}
// Calculate number of steps
int n_steps = static_cast<int>(DURATION * RATE_HZ);
std::cout << "Total steps: " << n_steps << ", duration: " << DURATION << " s" << std::endl;
// Execute trajectory
double dt = 1.0 / RATE_HZ;
auto start_time = std::chrono::steady_clock::now();
for (int i = 0; i < n_steps; i++) {
double t = static_cast<double>(i) / (n_steps - 1);
// Create joint position servo request
JointServoControlReq joint_position_servo_req;
joint_position_servo_req.control_period = CONTROL_PERIOD;
// Compute current target position (linear interpolation)
std::vector<double> current_positions;
for (size_t j = 0; j < target_joint_names.size(); j++) {
double interp_pos = interpolatePosition(
start_positions[j], target_positions[j], t
);
current_positions.push_back(interp_pos);
}
joint_position_servo_req.joint_names = target_joint_names;
joint_position_servo_req.joint_positions = current_positions;
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.JointServoControl(joint_position_servo_req);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.JointServoControl(joint_position_servo_req, true);
if (res != GDKRes::kSuccess) {
std::cout << "Failed to send control command, step: " << i << std::endl;
return;
}
// Control the send rate
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_time = std::chrono::milliseconds(static_cast<int>((i + 1) * dt * 1000));
auto sleep_time = expected_time - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
std::cout << "Joint position servo control complete" << std::endl;
// Hold the final position
std::cout << "Entering final position hold (Ctrl+C to stop)..." << std::endl;
try {
while (true) {
JointServoControlReq joint_position_servo_req;
joint_position_servo_req.control_period = CONTROL_PERIOD;
joint_position_servo_req.joint_names = target_joint_names;
joint_position_servo_req.joint_positions = target_positions;
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.JointServoControl(joint_position_servo_req);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.JointServoControl(joint_position_servo_req, true);
if (res != GDKRes::kSuccess) {
std::cout << "Failed to hold position" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
} catch (const std::exception& e) {
std::cout << "Hold interrupted: " << e.what() << std::endl;
}
}
};
int main() {
// Initialize the GDK system
if (GDKInit() != GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
// Get current joint states
JointStates current_joint_states;
if (robot.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
GDKRelease();
return -1;
}
std::cout << "Current number of joints: " << current_joint_states.nums << std::endl;
// Define the joints to control (example: the first 3 joints of the left arm)
std::vector<std::string> target_joint_names = {
"idx21_arm_l_joint1",
"idx22_arm_l_joint2",
"idx23_arm_l_joint3"
};
// Get the current position as the starting position (for interpolation)
std::vector<double> start_positions;
for (const auto& joint_name : target_joint_names) {
bool found = false;
for (const auto& state : current_joint_states.states) {
if (state.name == joint_name) {
start_positions.push_back(state.motor_position);
std::cout << "Joint " << joint_name << " current position: " << state.motor_position << " rad" << std::endl;
found = true;
break;
}
}
if (!found) {
std::cout << "Error: joint " << joint_name << " not found" << std::endl;
GDKRelease();
return -1;
}
}
// Set target angles (directly specify the target angle values, in radians)
std::vector<double> target_positions = {
0.0, // idx21_arm_l_joint1: target angle 0.0 rad
0.0, // idx22_arm_l_joint2: target angle 0.0 rad
0.0 // idx23_arm_l_joint3: target angle 0.0 rad
};
std::cout << "\nTarget angles:" << std::endl;
for (size_t i = 0; i < target_joint_names.size(); i++) {
std::cout << " " << target_joint_names[i] << ": " << target_positions[i] << " rad" << std::endl;
}
// Execute joint position servo control
JointServoControlController controller;
controller.executeJointServoControl(
target_joint_names, target_positions);
// Release GDK system resources
if (GDKRelease() != GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
- Example of simultaneously controlling the arm and the end-effector:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
using namespace agibot::gdk;
const double CONTROL_PERIOD = 0.01;
const double RATE_HZ = 100.0;
const double DURATION = 3.0;
const double HOLD_DURATION = 0.5; // Time to hold at -0.785 or 0 (seconds)
const int NUM_CYCLES = 3; // Number of back-and-forth cycles
static const std::vector<std::string> ARM_L_JOINT_NAMES = {
"idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3",
"idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6",
"idx27_arm_l_joint7",
};
// Extract the position list by joint name from the GetJointStates return value
std::vector<double> getArmPositionsByName(const JointStates& joint_states,
const std::vector<std::string>& joint_names) {
std::vector<double> positions;
for (const auto& name : joint_names) {
for (const auto& state : joint_states.states) {
if (state.name == name) {
positions.push_back(state.motor_position);
break;
}
}
}
return positions;
}
// Extract the joint name list and position list for the specified end-effector side from the GetEndState return value
// If use_left is true, take left_end_state; if false, take right_end_state
void getEENamesAndPositions(const DualEndState& end_state,
bool use_left,
std::vector<std::string>& names,
std::vector<double>& positions) {
const EndState& state = use_left ? end_state.left_end_state : end_state.right_end_state;
names = state.names;
positions.clear();
for (const auto& motor : state.end_states) {
positions.push_back(motor.position);
}
}
int main() {
if (GDKInit() != GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
Robot robot;
std::this_thread::sleep_for(std::chrono::seconds(2));
JointStates joint_states;
if (robot.GetJointStates(joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
GDKRelease();
return -1;
}
DualEndState end_state;
if (robot.GetEndState(end_state) != GDKRes::kSuccess) {
std::cout << "Failed to get end-effector state" << std::endl;
GDKRelease();
return -1;
}
std::vector<std::string> ee_names;
std::vector<double> ee_positions;
getEENamesAndPositions(end_state, true, ee_names, ee_positions); // Left end-effector
std::vector<std::string> all_names = ARM_L_JOINT_NAMES;
all_names.insert(all_names.end(), ee_names.begin(), ee_names.end());
std::vector<double> arm_positions = getArmPositionsByName(joint_states, ARM_L_JOINT_NAMES);
if (arm_positions.size() != ARM_L_JOINT_NAMES.size()) {
std::cout << "Left arm joint count mismatch" << std::endl;
GDKRelease();
return -1;
}
// The arm performs small back-and-forth joint-space motion as before, while the end-effector joint moves back and forth between -0.785 and 0
std::vector<double> arm_start = arm_positions; // Arm initial pose
std::vector<double> arm_target = arm_positions; // Arm target pose (small offset)
for (auto& v : arm_target) v += 0.05;
const double ee_low = -0.785; // End-effector lower limit
const double ee_high = 0.0; // End-effector upper limit
std::cout << "Number of controlled joints: arm " << ARM_L_JOINT_NAMES.size()
<< " + end-effector " << ee_names.size() << " = " << all_names.size() << std::endl;
std::cout << "The arm will move in joint space between arm_start and arm_target, and the end-effector joint will move back and forth between "
<< ee_low << " and " << ee_high << " for " << NUM_CYCLES << " cycles" << std::endl;
int n_steps = static_cast<int>(DURATION * RATE_HZ); // Number of steps for a single move
int hold_steps = static_cast<int>(HOLD_DURATION * RATE_HZ); // Number of steps for the hold phase
double dt = 1.0 / RATE_HZ;
// Helper function: send control command
auto sendControlCommand = [&](const std::vector<double>& arm_vals, const std::vector<double>& ee_vals) -> bool {
std::vector<double> current = arm_vals;
current.insert(current.end(), ee_vals.begin(), ee_vals.end());
JointServoControlReq req;
req.control_period = CONTROL_PERIOD;
req.joint_names = all_names;
req.joint_positions = current;
req.joint_velocities = std::vector<double>(current.size(), 0.0);
return robot.JointServoControl(req) == GDKRes::kSuccess;
};
for (int cycle = 0; cycle < NUM_CYCLES; cycle++) {
std::cout << "\n=== Cycle " << (cycle + 1) << "/" << NUM_CYCLES
<< ": arm arm_start -> arm_target, end-effector " << ee_low << " -> " << ee_high << " ===" << std::endl;
auto start_time = std::chrono::steady_clock::now();
// Segment 1: arm arm_start -> arm_target, end-effector ee_low -> ee_high
for (int i = 0; i < n_steps; i++) {
double t = (n_steps > 1) ? static_cast<double>(i) / (n_steps - 1) : 1.0;
std::vector<double> current_arm;
for (size_t j = 0; j < arm_start.size(); j++) {
current_arm.push_back(arm_start[j] + t * (arm_target[j] - arm_start[j]));
}
std::vector<double> current_ee(ee_names.size(), ee_low + t * (ee_high - ee_low));
if (!sendControlCommand(current_arm, current_ee)) {
std::cout << "Send failed, cycle=" << (cycle + 1) << ", phase=0->1, step=" << i << std::endl;
GDKRelease();
return -1;
}
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_ms = static_cast<int>((i + 1) * dt * 1000);
auto sleep_time = std::chrono::milliseconds(expected_ms) - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
// Segment 2: hold at arm_target / ee_high
std::cout << "=== Cycle " << (cycle + 1) << "/" << NUM_CYCLES
<< ": holding at arm_target / " << ee_high << " for " << HOLD_DURATION << " s ===" << std::endl;
start_time = std::chrono::steady_clock::now();
std::vector<double> current_arm = arm_target;
std::vector<double> current_ee(ee_names.size(), ee_high);
for (int i = 0; i < hold_steps; i++) {
if (!sendControlCommand(current_arm, current_ee)) {
std::cout << "Send failed, cycle=" << (cycle + 1) << ", phase=hold@1, step=" << i << std::endl;
GDKRelease();
return -1;
}
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_ms = static_cast<int>((i + 1) * dt * 1000);
auto sleep_time = std::chrono::milliseconds(expected_ms) - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
// Segment 3: arm arm_target -> arm_start, end-effector ee_high -> ee_low
std::cout << "=== Cycle " << (cycle + 1) << "/" << NUM_CYCLES
<< ": arm arm_target -> arm_start, end-effector " << ee_high << " -> " << ee_low << " ===" << std::endl;
start_time = std::chrono::steady_clock::now();
for (int i = 0; i < n_steps; i++) {
double t = (n_steps > 1) ? static_cast<double>(i) / (n_steps - 1) : 1.0;
std::vector<double> current_arm;
for (size_t j = 0; j < arm_target.size(); j++) {
current_arm.push_back(arm_target[j] + t * (arm_start[j] - arm_target[j]));
}
std::vector<double> current_ee(ee_names.size(), ee_high + t * (ee_low - ee_high));
if (!sendControlCommand(current_arm, current_ee)) {
std::cout << "Send failed, cycle=" << (cycle + 1) << ", phase=1->0, step=" << i << std::endl;
GDKRelease();
return -1;
}
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_ms = static_cast<int>((i + 1) * dt * 1000);
auto sleep_time = std::chrono::milliseconds(expected_ms) - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
// Segment 4: hold at arm_start / ee_low
std::cout << "=== Cycle " << (cycle + 1) << "/" << NUM_CYCLES
<< ": holding at arm_start / " << ee_low << " for " << HOLD_DURATION << " s ===" << std::endl;
start_time = std::chrono::steady_clock::now();
current_arm = arm_start;
current_ee = std::vector<double>(ee_names.size(), ee_low);
for (int i = 0; i < hold_steps; i++) {
if (!sendControlCommand(current_arm, current_ee)) {
std::cout << "Send failed, cycle=" << (cycle + 1) << ", phase=hold@0, step=" << i << std::endl;
GDKRelease();
return -1;
}
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_ms = static_cast<int>((i + 1) * dt * 1000);
auto sleep_time = std::chrono::milliseconds(expected_ms) - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
}
std::cout << "\nArm arm_start<->arm_target, end-effector " << ee_low << "<->" << ee_high << " back-and-forth control finished" << std::endl;
if (GDKRelease() != GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
12. MoveHeadJointServo()¶
- Function: Head joint position servo control interface. It must be controlled at a 100 Hz control frequency and supports normal mode and low-latency mode; normal mode is used by default.
- Note: Low-latency mode has no collision protection; use it with caution for safety.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
const std::vector<double>& |
List of head joint positions (radians), in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3" |
control_period |
const double |
Control period (seconds); recommended to be slightly larger than the control frequency |
enable_low_latency |
const bool |
Whether to enable low-latency mode; defaults to false |
Parameter description:
- positions must have a length of 3
- The values in positions must be within the corresponding joint's limit range (see the joint limit values below); otherwise, ErrorCode::kInvalidInput is returned
- control_period indicates the control period, in seconds; recommended to be slightly larger than the control frequency
- enable_low_latency is used to select the control channel; low-latency mode is suitable for scenarios with higher real-time requirements
Joint Limit Values¶
The limit values for the head joints (in radians) are as follows:
| Joint Name | Minimum | Maximum |
|---|---|---|
idx11_head_joint1 |
-1.570970 | 1.570970 |
idx12_head_joint2 |
-0.349240 | 0.349240 |
idx13_head_joint3 |
-0.534773 | 0.534773 |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Error handling:
- If the length of
positionsis not 3,ErrorCode::kInvalidInputis returned - If the values in
positionsexceed the corresponding joint's limit range,ErrorCode::kInvalidInputis returned -
For other error conditions, the corresponding error code is returned
-
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <algorithm>
using namespace agibot::gdk;
// Control parameters
const double CONTROL_PERIOD = 0.01; // Control period (seconds)
const double RATE_HZ = 100.0; // Send frequency (Hz)
const double DURATION = 5.0; // Control duration (seconds)
class HeadJointServoController {
private:
Robot robot_;
double getJointPositionByName(const JointStates& joint_states, const std::string& joint_name) {
for (const auto& state : joint_states.states) {
if (state.name == joint_name) {
return state.motor_position;
}
}
throw std::runtime_error("Joint name " + joint_name + " not found");
}
double interpolatePosition(double start_pos, double target_pos, double t) {
return start_pos + t * (target_pos - start_pos);
}
public:
void executeHeadJointServoControl(const std::vector<double>& target_positions) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait 1 second
// Get current joint states
JointStates current_joint_states;
if (robot_.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
return;
}
// Get the starting position
std::vector<std::string> head_joint_names = {
"idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"
};
std::vector<double> start_positions;
for (const auto& joint_name : head_joint_names) {
try {
double pos = getJointPositionByName(current_joint_states, joint_name);
start_positions.push_back(pos);
std::cout << "Joint " << joint_name << " current position: " << pos << " rad" << std::endl;
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
return;
}
}
// Calculate number of steps
int n_steps = static_cast<int>(DURATION * RATE_HZ);
std::cout << "Total steps: " << n_steps << ", duration: " << DURATION << " s" << std::endl;
// Execute trajectory
double dt = 1.0 / RATE_HZ;
auto start_time = std::chrono::steady_clock::now();
for (int i = 0; i < n_steps; i++) {
double t = static_cast<double>(i) / (n_steps - 1);
// Compute current target position (linear interpolation)
std::vector<double> current_positions;
for (size_t j = 0; j < 3; j++) {
double interp_pos = interpolatePosition(
start_positions[j], target_positions[j], t
);
current_positions.push_back(interp_pos);
}
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveHeadJointServo(
current_positions, CONTROL_PERIOD);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveHeadJointServo(
// current_positions, target_velocities, CONTROL_PERIOD, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to send control command, step: " << i << std::endl;
return;
}
// Control the send rate
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_time = std::chrono::milliseconds(static_cast<int>((i + 1) * dt * 1000));
auto sleep_time = expected_time - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
std::cout << "Head joint position servo control complete" << std::endl;
// Hold the final position
std::cout << "Entering final position hold (Ctrl+C to stop)..." << std::endl;
try {
while (true) {
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveHeadJointServo(
target_positions, CONTROL_PERIOD);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveHeadJointServo(
// target_positions, target_velocities, CONTROL_PERIOD, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to hold position" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
} catch (const std::exception& e) {
std::cout << "Hold interrupted: " << e.what() << std::endl;
}
}
};
int main() {
// Initialize the GDK system
if (GDKInit() != GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
// Get current joint states
JointStates current_joint_states;
if (robot.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
GDKRelease();
return -1;
}
// Define target positions (example: head joints)
std::vector<double> target_positions = {
0.0, // idx11_head_joint1: target angle 0.0 rad
0.0, // idx12_head_joint2: target angle 0.0 rad
0.0 // idx13_head_joint3: target angle 0.0 rad
};
std::cout << "\nTarget angles:" << std::endl;
std::vector<std::string> head_joint_names = {
"idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"
};
for (size_t i = 0; i < head_joint_names.size(); i++) {
std::cout << " " << head_joint_names[i] << ": " << target_positions[i] << " rad" << std::endl;
}
// Execute head joint position servo control
HeadJointServoController controller;
controller.executeHeadJointServoControl(target_positions);
// Release GDK system resources
if (GDKRelease() != GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
13. MoveWaistJointServo()¶
- Function: Waist joint position servo control interface. It must be controlled at a 100 Hz control frequency and supports normal mode and low-latency mode; normal mode is used by default.
- Note: Low-latency mode has no collision protection; use it with caution for safety.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
const std::vector<double>& |
List of waist joint positions (radians), in the order "idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5" |
control_period |
const double |
Control period (seconds); recommended to be slightly larger than the control frequency |
enable_low_latency |
const bool |
Whether to enable low-latency mode; defaults to false |
Parameter description:
- positions must have a length of 5
- The values in positions must be within the corresponding joint's limit range (see the joint limit values below); otherwise, ErrorCode::kInvalidInput is returned
- control_period indicates the control period, in seconds; recommended to be slightly larger than the control frequency
- enable_low_latency is used to select the control channel; low-latency mode is suitable for scenarios with higher real-time requirements
Joint Limit Values¶
The limit values for the waist joints (in radians) are as follows:
| Joint Name | Minimum | Maximum |
|---|---|---|
idx01_body_joint1 |
-1.082104 | 0.000174 |
idx02_body_joint2 |
-0.000174 | 2.652900 |
idx03_body_joint3 |
-1.919862 | 1.570970 |
idx04_body_joint4 |
-0.436332 | 0.436332 |
idx05_body_joint5 |
-3.045599 | 3.045599 |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Error handling:
- If the length of
positionsis not 5,ErrorCode::kInvalidInputis returned - If the values in
positionsexceed the corresponding joint's limit range,ErrorCode::kInvalidInputis returned -
For other error conditions, the corresponding error code is returned
-
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <algorithm>
using namespace agibot::gdk;
// Control parameters
const double CONTROL_PERIOD = 0.01; // Control period (seconds)
const double RATE_HZ = 100.0; // Send frequency (Hz)
const double DURATION = 5.0; // Control duration (seconds)
class WaistJointServoController {
private:
Robot robot_;
double getJointPositionByName(const JointStates& joint_states, const std::string& joint_name) {
for (const auto& state : joint_states.states) {
if (state.name == joint_name) {
return state.motor_position;
}
}
throw std::runtime_error("Joint name " + joint_name + " not found");
}
double interpolatePosition(double start_pos, double target_pos, double t) {
return start_pos + t * (target_pos - start_pos);
}
public:
void executeWaistJointServoControl(const std::vector<double>& target_positions) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait 1 second
// Get current joint states
JointStates current_joint_states;
if (robot_.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
return;
}
// Get the starting position
std::vector<std::string> waist_joint_names = {
"idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3",
"idx04_body_joint4", "idx05_body_joint5"
};
std::vector<double> start_positions;
for (const auto& joint_name : waist_joint_names) {
try {
double pos = getJointPositionByName(current_joint_states, joint_name);
start_positions.push_back(pos);
std::cout << "Joint " << joint_name << " current position: " << pos << " rad" << std::endl;
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
return;
}
}
// Calculate number of steps
int n_steps = static_cast<int>(DURATION * RATE_HZ);
std::cout << "Total steps: " << n_steps << ", duration: " << DURATION << " s" << std::endl;
// Execute trajectory
double dt = 1.0 / RATE_HZ;
auto start_time = std::chrono::steady_clock::now();
for (int i = 0; i < n_steps; i++) {
double t = static_cast<double>(i) / (n_steps - 1);
// Compute current target position (linear interpolation)
std::vector<double> current_positions;
for (size_t j = 0; j < 5; j++) {
double interp_pos = interpolatePosition(
start_positions[j], target_positions[j], t
);
current_positions.push_back(interp_pos);
}
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveWaistJointServo(
current_positions, CONTROL_PERIOD);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveWaistJointServo(
// current_positions, target_velocities, CONTROL_PERIOD, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to send control command, step: " << i << std::endl;
return;
}
// Control the send rate
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_time = std::chrono::milliseconds(static_cast<int>((i + 1) * dt * 1000));
auto sleep_time = expected_time - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
std::cout << "Waist joint position servo control complete" << std::endl;
// Hold the final position
std::cout << "Entering final position hold (Ctrl+C to stop)..." << std::endl;
try {
while (true) {
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveWaistJointServo(
target_positions, CONTROL_PERIOD);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveWaistJointServo(
// target_positions, target_velocities, CONTROL_PERIOD, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to hold position" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
} catch (const std::exception& e) {
std::cout << "Hold interrupted: " << e.what() << std::endl;
}
}
};
int main() {
// Initialize the GDK system
if (GDKInit() != GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
// Get current joint states
JointStates current_joint_states;
if (robot.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
GDKRelease();
return -1;
}
// Define target positions (example: waist joints)
std::vector<double> target_positions = {
0.0, // idx01_body_joint1: target angle 0.0 rad
0.0, // idx02_body_joint2: target angle 0.0 rad
0.0, // idx03_body_joint3: target angle 0.0 rad
0.0, // idx04_body_joint4: target angle 0.0 rad
0.0 // idx05_body_joint5: target angle 0.0 rad
};
std::cout << "\nTarget angles:" << std::endl;
std::vector<std::string> waist_joint_names = {
"idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3",
"idx04_body_joint4", "idx05_body_joint5"
};
for (size_t i = 0; i < waist_joint_names.size(); i++) {
std::cout << " " << waist_joint_names[i] << ": " << target_positions[i] << " rad" << std::endl;
}
// Execute waist joint position servo control
WaistJointServoController controller;
controller.executeWaistJointServoControl(target_positions);
// Release GDK system resources
if (GDKRelease() != GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
14. MoveArmJointServo()¶
- Function: Arm joint position servo control interface. It must be controlled at a 100 Hz control frequency and supports normal mode and low-latency mode; normal mode is used by default.
- Note: Low-latency mode has no collision protection; use it with caution for safety.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
positions |
const std::vector<double>& |
List of arm joint positions (radians), in the order "idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3", "idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6", "idx27_arm_l_joint7", "idx61_arm_r_joint1", "idx62_arm_r_joint2", "idx63_arm_r_joint3", "idx64_arm_r_joint4", "idx65_arm_r_joint5", "idx66_arm_r_joint6", "idx67_arm_r_joint7" |
control_period |
const double |
Control period (seconds); recommended to be slightly larger than the control frequency |
control_group |
const int |
Control group: 0 controls the left arm, 1 controls the right arm, 2 controls both arms |
enable_low_latency |
const bool |
Whether to enable low-latency mode; defaults to false |
Parameter description:
- positions has a length of 7 (single arm) or 14 (both arms)
- The values in positions must be within the corresponding joint's limit range (see the joint limit values below); otherwise, ErrorCode::kInvalidInput is returned
- control_period indicates the control period, in seconds; recommended to be slightly larger than the control frequency
- control_group indicates the control group: 0 controls the left arm, 1 controls the right arm, 2 controls both arms
- enable_low_latency is used to select the control channel; low-latency mode is suitable for scenarios with higher real-time requirements
Joint Limit Values¶
The limit values for the arm joints (in radians) are as follows:
| Joint Name | Minimum | Maximum |
|---|---|---|
idx21_arm_l_joint1 |
-3.071796 | 3.071796 |
idx22_arm_l_joint2 |
-2.059505 | 2.059505 |
idx23_arm_l_joint3 |
-3.071796 | 3.071796 |
idx24_arm_l_joint4 |
-2.495838 | 1.012308 |
idx25_arm_l_joint5 |
-3.071796 | 3.071796 |
idx26_arm_l_joint6 |
-1.012308 | 1.012308 |
idx27_arm_l_joint7 |
-1.535907 | 1.535907 |
idx61_arm_r_joint1 |
-3.071796 | 3.071796 |
idx62_arm_r_joint2 |
-2.059505 | 2.059505 |
idx63_arm_r_joint3 |
-3.071796 | 3.071796 |
idx64_arm_r_joint4 |
-2.495838 | 1.012308 |
idx65_arm_r_joint5 |
-3.071796 | 3.071796 |
idx66_arm_r_joint6 |
-1.012308 | 1.012308 |
idx67_arm_r_joint7 |
-1.535907 | 1.535907 |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Error handling:
- If the length of
positionsis not 7 (single arm) or 14 (both arms),ErrorCode::kInvalidInputis returned - If the values in
positionsexceed the corresponding joint's limit range,ErrorCode::kInvalidInputis returned -
For other error conditions, the corresponding error code is returned
-
Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <algorithm>
using namespace agibot::gdk;
// Control parameters
const double CONTROL_PERIOD = 0.01; // Control period (seconds)
const double RATE_HZ = 100.0; // Send frequency (Hz)
const double DURATION = 5.0; // Control duration (seconds)
class ArmJointServoController {
private:
Robot robot_;
double getJointPositionByName(const JointStates& joint_states, const std::string& joint_name) {
for (const auto& state : joint_states.states) {
if (state.name == joint_name) {
return state.motor_position;
}
}
throw std::runtime_error("Joint name " + joint_name + " not found");
}
double interpolatePosition(double start_pos, double target_pos, double t) {
return start_pos + t * (target_pos - start_pos);
}
public:
void executeArmJointServoControl(const std::vector<double>& target_positions, const int control_group) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // Wait 1 second
// Get current joint states
JointStates current_joint_states;
if (robot_.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
return;
}
// Get the starting position
std::vector<std::string> arm_joint_names = {
"idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3",
"idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6",
"idx27_arm_l_joint7", // 7 joints of the left arm
"idx61_arm_r_joint1", "idx62_arm_r_joint2", "idx63_arm_r_joint3",
"idx64_arm_r_joint4", "idx65_arm_r_joint5", "idx66_arm_r_joint6",
"idx67_arm_r_joint7" // 7 joints of the right arm
};
std::vector<double> start_positions;
for (const auto& joint_name : arm_joint_names) {
try {
double pos = getJointPositionByName(current_joint_states, joint_name);
start_positions.push_back(pos);
std::cout << "Joint " << joint_name << " current position: " << pos << " rad" << std::endl;
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
return;
}
}
// Calculate number of steps
int n_steps = static_cast<int>(DURATION * RATE_HZ);
std::cout << "Total steps: " << n_steps << ", duration: " << DURATION << " s" << std::endl;
// Execute trajectory
double dt = 1.0 / RATE_HZ;
auto start_time = std::chrono::steady_clock::now();
for (int i = 0; i < n_steps; i++) {
double t = static_cast<double>(i) / (n_steps - 1);
// Compute current target position (linear interpolation)
std::vector<double> current_positions;
for (size_t j = 0; j < 14; j++) {
double interp_pos = interpolatePosition(
start_positions[j], target_positions[j], t
);
current_positions.push_back(interp_pos);
}
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveArmJointServo(
current_positions, CONTROL_PERIOD, control_group
);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveArmJointServo(
// current_positions, CONTROL_PERIOD, control_group, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to send control command, step: " << i << std::endl;
return;
}
// Control the send rate
auto elapsed = std::chrono::steady_clock::now() - start_time;
auto expected_time = std::chrono::milliseconds(static_cast<int>((i + 1) * dt * 1000));
auto sleep_time = expected_time - elapsed;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
std::cout << "Arm joint position servo control complete" << std::endl;
// Hold the final position
std::cout << "Entering final position hold (Ctrl+C to stop)..." << std::endl;
try {
while (true) {
// Use normal mode (enable_low_latency=false, the default)
auto res = robot_.MoveArmJointServo(
target_positions, CONTROL_PERIOD, control_group
);
// To use low-latency mode, pass enable_low_latency=true:
// auto res = robot_.MoveArmJointServo(
// target_positions, CONTROL_PERIOD, control_group, true
// );
if (res != GDKRes::kSuccess) {
std::cout << "Failed to hold position" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
} catch (const std::exception& e) {
std::cout << "Hold interrupted: " << e.what() << std::endl;
}
}
};
int main() {
// Initialize the GDK system
if (GDKInit() != GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
// Get current joint states
JointStates current_joint_states;
if (robot.GetJointStates(current_joint_states) != GDKRes::kSuccess) {
std::cout << "Failed to get joint states" << std::endl;
GDKRelease();
return -1;
}
// Define target positions (example: arm joints)
std::vector<double> target_positions = {
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, // 7 joints of the left arm
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 // 7 joints of the right arm
};
std::cout << "\nTarget angles:" << std::endl;
std::vector<std::string> arm_joint_names = {
"idx21_arm_l_joint1", "idx22_arm_l_joint2", "idx23_arm_l_joint3",
"idx24_arm_l_joint4", "idx25_arm_l_joint5", "idx26_arm_l_joint6",
"idx27_arm_l_joint7", // 7 joints of the left arm
"idx61_arm_r_joint1", "idx62_arm_r_joint2", "idx63_arm_r_joint3",
"idx64_arm_r_joint4", "idx65_arm_r_joint5", "idx66_arm_r_joint6",
"idx67_arm_r_joint7" // 7 joints of the right arm
};
for (size_t i = 0; i < arm_joint_names.size(); i++) {
std::cout << " " << arm_joint_names[i] << ": " << target_positions[i] << " rad" << std::endl;
}
// Execute arm joint position servo control
ArmJointServoController controller;
controller.executeArmJointServoControl(target_positions, 2);
// Release GDK system resources
if (GDKRelease() != GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
15. EndEffectorPoseControl()¶
- Function: End-effector pose control interface
- Note: This interface requires the sender to publish control commands at a 50 Hz frequency; step signals are not allowed. This interface has no collision detection, so be mindful of the environment when using it.
- Parameters:
| Parameter | Type | Description |
|---|---|---|
end_pose |
const EndEffectorPose& |
End-effector pose control object |
- Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success
EndEffectorPose Object Details¶
The EndEffectorPose struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
life_time |
double |
Control lifetime | Seconds |
group |
int32_t |
Control group: 0: unknown, 4: left arm, 8: right arm, 12: both arms | None |
left_end_effector_pose |
Pose |
Left end-effector pose (in the base_link frame) | Pose |
right_end_effector_pose |
Pose |
Right end-effector pose (in the base_link frame) | Pose |
struct EndEffectorPose {
double life_time{0.0};
int32_t group{0};
Pose left_end_effector_pose{};
Pose right_end_effector_pose{};
};
Pose struct:
| Member | Type | Description | Unit |
|---|---|---|---|
position |
Position |
Position information | Meters |
orientation |
Orientation |
Orientation information | Quaternion |
Position struct:
| Member | Type | Description | Unit |
|---|---|---|---|
x |
double |
X coordinate | Meters |
y |
double |
Y coordinate | Meters |
z |
double |
Z coordinate | Meters |
Orientation struct:
| Member | Type | Description | Unit |
|---|---|---|---|
x |
double |
Quaternion X component | None |
y |
double |
Quaternion Y component | None |
z |
double |
Quaternion Z component | None |
w |
double |
Quaternion W component | None |
- Example:
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace agibot::gdk;
const std::string LEFT_NAME = "arm_l_end_link";
const std::string RIGHT_NAME = "arm_r_end_link";
const int32_t CONTROL_GROUP = 12; // kBothArms
const Pose TARGET_LEFT = {
{0.516, 0.433, 1.081}, // position
{0.382, -0.146, 0.663, 0.626} // orientation
};
const Pose TARGET_RIGHT = {
{0.579, -0.306, 1.158}, // position
{0.320, 0.655, 0.651, 0.206} // orientation
};
const double MAX_STEP_CM = 0.1; // Maximum step size (centimeters)
const double LIFETIME = 0.02; // Lifetime (seconds)
const double RATE_HZ = 50.0; // Send frequency (Hz)
const bool HOLD_FINAL = true; // Whether to hold the final pose
class EndEffectorController {
private:
Robot robot_;
void slerp(const double q0[4], const double q1[4], double t, double result[4]) {
double dot = q0[0]*q1[0] + q0[1]*q1[1] + q0[2]*q1[2] + q0[3]*q1[3];
// If the dot product is negative, negate q1 to ensure the shortest path
if (dot < 0.0) {
dot = -dot;
for (int i = 0; i < 4; i++) {
result[i] = q0[i] + t * (-q1[i] - q0[i]);
}
} else {
for (int i = 0; i < 4; i++) {
result[i] = q0[i] + t * (q1[i] - q0[i]);
}
}
// Clamp the dot product range
dot = std::clamp(dot, -1.0, 1.0);
if (dot > 0.9995) {
// Linear interpolation
double norm = 0.0;
for (int i = 0; i < 4; i++) {
norm += result[i] * result[i];
}
norm = std::sqrt(norm);
if (norm > 0.0) {
for (int i = 0; i < 4; i++) {
result[i] /= norm;
}
}
} else {
// Spherical linear interpolation
double theta_0 = std::acos(dot);
double sin_theta_0 = std::sin(theta_0);
double theta = theta_0 * t;
double sin_theta = std::sin(theta);
double s0 = std::cos(theta) - dot * sin_theta / sin_theta_0;
double s1 = sin_theta / sin_theta_0;
for (int i = 0; i < 4; i++) {
result[i] = s0 * q0[i] + s1 * q1[i];
}
}
}
double distanceBetweenPoints(const Vector3& p1, const Vector3& p2) {
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double dz = p2.z - p1.z;
return std::sqrt(dx*dx + dy*dy + dz*dz);
}
int calculateNSteps(const Vector3& start, const Vector3& goal, double max_step_cm) {
double dist_cm = distanceBetweenPoints(start, goal) * 100.0;
return std::max(static_cast<int>(std::ceil(dist_cm / max_step_cm)), 1);
}
std::vector<Pose> planTrajectory(const Pose& start, const Pose& goal, int n_steps) {
std::vector<Pose> trajectory;
for (int i = 0; i < n_steps; i++) {
double t = static_cast<double>(i) / (n_steps - 1);
Pose pose;
// Linear interpolation of position
pose.position.x = start.position.x + t * (goal.position.x - start.position.x);
pose.position.y = start.position.y + t * (goal.position.y - start.position.y);
pose.position.z = start.position.z + t * (goal.position.z - start.position.z);
// Quaternion SLERP interpolation
double q0[4] = {start.orientation.x, start.orientation.y, start.orientation.z, start.orientation.w};
double q1[4] = {goal.orientation.x, goal.orientation.y, goal.orientation.z, goal.orientation.w};
double result[4];
slerp(q0, q1, t, result);
pose.orientation.x = result[0];
pose.orientation.y = result[1];
pose.orientation.z = result[2];
pose.orientation.w = result[3];
trajectory.push_back(pose);
}
return trajectory;
}
Pose findPoseByName(const std::vector<std::string>& frame_names,
const std::vector<Pose>& frame_poses,
const std::string& target_name) {
for (size_t i = 0; i < frame_names.size(); i++) {
if (frame_names[i] == target_name) {
return frame_poses[i];
}
}
throw std::runtime_error("Frame name " + target_name + " not found");
}
public:
void executeEndPoseControl() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Wait 1 second
// Get the current state
MotionControlStatus status;
GDKRes result = robot_.GetMotionControlStatus(status);
if (result != GDKRes::kSuccess) {
std::cout << "Failed to get motion control status" << std::endl;
return;
}
// Get the starting pose
Pose start_left_pose = findPoseByName(status.frame_names, status.frame_poses, LEFT_NAME);
Pose start_right_pose = findPoseByName(status.frame_names, status.frame_poses, RIGHT_NAME);
// Calculate number of steps
int n_left = calculateNSteps(start_left_pose.position, TARGET_LEFT.position, MAX_STEP_CM);
int n_right = calculateNSteps(start_right_pose.position, TARGET_RIGHT.position, MAX_STEP_CM);
int n_steps = std::max(n_left, n_right);
std::cout << "Left arm steps: " << n_left << ", right arm steps: " << n_right << ", total steps: " << n_steps << std::endl;
// Plan trajectory
std::vector<Pose> traj_left = planTrajectory(start_left_pose, TARGET_LEFT, n_steps);
std::vector<Pose> traj_right = planTrajectory(start_right_pose, TARGET_RIGHT, n_steps);
// Execute trajectory
double dt = 1.0 / RATE_HZ;
for (int i = 0; i < n_steps; i++) {
EndEffectorPose end_pose;
end_pose.life_time = LIFETIME;
end_pose.group = CONTROL_GROUP;
end_pose.left_end_effector_pose = traj_left[i];
end_pose.right_end_effector_pose = traj_right[i];
result = robot_.EndEffectorPoseControl(end_pose);
if (result != GDKRes::kSuccess) {
std::cout << "Failed to send control command, step: " << i << std::endl;
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
// Hold the final pose (corresponds to the Python version)
if (HOLD_FINAL) {
std::cout << "Entering end-effector pose hold (Ctrl+C to stop)..." << std::endl;
try {
while (true) {
EndEffectorPose end_pose;
end_pose.life_time = LIFETIME;
end_pose.group = CONTROL_GROUP;
end_pose.left_end_effector_pose = traj_left.back();
end_pose.right_end_effector_pose = traj_right.back();
result = robot_.EndEffectorPoseControl(end_pose);
if (result != GDKRes::kSuccess) {
std::cout << "Failed to hold pose" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));
}
} catch (const std::exception& e) {
std::cout << "Hold interrupted: " << e.what() << std::endl;
}
}
}
};
int main() {
EndEffectorController controller;
controller.executeEndPoseControl();
return 0;
}
16. MoveEEPos()¶
- Function: Controls the end-effector position
- Parameters:
| Parameter | Type | Description |
|---|---|---|
joint_states |
const JointStates& |
Joint state control parameter |
JointStates Object Details (for MoveEEPos)¶
The JointStates struct contains the following members:
| Member | Type | Description | Unit |
|---|---|---|---|
nums |
size_t |
Number of joints; should equal states.size() |
None |
group |
std::string |
Control group; must be "left_tool", "right_tool", or "dual_tool" | String |
target_type |
std::string |
Target type; see the table below for supported values | String |
states |
std::vector<JointState> |
List of joint states (required) | List of joint states |
Supported values of target_type and the corresponding joint-count requirements:
target_type Value |
Required Joint Count | Description |
|---|---|---|
"omnipicker" |
1 | Omnidirectional gripper, requires 1 joint |
"dahuan" |
1 | Dahuan end-effector, requires 1 joint |
"ctek90d" |
1 | CTEK90D end-effector, requires 1 joint |
"o10_t2" |
10 | O10 dexterous-hand end-effector, requires 10 joints |
"o12_t2" |
12 | O12 dexterous-hand end-effector, requires 12 joints |
Joint position value ranges for each end-effector type:
- Note: The joint value ranges are tied to the version; be mindful of the current version's value ranges when using them. For the current version, the ranges given in this document take precedence.
- omnipicker:
positionranges over[-0.785,0], where-0.785means open and0means closed - dahuan:
positionranges over[0,0.025], where0means open and0.025means closed - ctek90d:
positionranges over[-0.91, 0], where-0.91means open and0means closed - o10_t2: The joint position value ranges are as follows (in radians)
Left-hand joint limit values:
| Joint Index | Joint Name | Minimum | Maximum |
|---|---|---|---|
| 0 | idx31_hand_l_thumb_roll_joint |
-1.1213740444063567 | 0.029670597283903602 |
| 1 | idx32_hand_l_thumb_abad_joint |
-0.04537856055185257 | 1.642354826126664 |
| 2 | idx33_hand_l_thumb_mcp_joint |
-0.8415977653116657 | 0.0 |
| 3 | idx36_hand_l_index_abad_joint |
0.0 | 0.16406094968746698 |
| 4 | idx37_hand_l_index_pip_joint |
0.0 | 1.4835298641951802 |
| 5 | idx39_hand_l_middle_pip_joint |
0.0 | 1.4835298641951802 |
| 6 | idx41_hand_l_ring_abad_joint |
-0.16929693744344995 | 0.0 |
| 7 | idx42_hand_l_ring_pip_joint |
0.0 | 1.4835298641951802 |
| 8 | idx44_hand_l_pinky_abad_joint |
-0.1850049007113989 | 0.0 |
| 9 | idx45_hand_l_pinky_pip_joint |
0.0 | 1.4835298641951802 |
Right-hand joint limit values:
| Joint Index | Joint Name | Minimum | Maximum |
|---|---|---|---|
| 0 | idx71_hand_r_thumb_roll_joint |
-0.029670597283903602 | 1.1213740444063567 |
| 1 | idx72_hand_r_thumb_abad_joint |
-1.642354826126664 | 0.04537856055185257 |
| 2 | idx73_hand_r_thumb_mcp_joint |
0.0 | 0.8415977653116657 |
| 3 | idx76_hand_r_index_abad_joint |
-0.16406094968746698 | 0.0 |
| 4 | idx77_hand_r_index_pip_joint |
0.0 | 1.4835298641951802 |
| 5 | idx79_hand_r_middle_pip_joint |
0.0 | 1.4835298641951802 |
| 6 | idx81_hand_r_ring_abad_joint |
0.0 | 0.16929693744344995 |
| 7 | idx82_hand_r_ring_pip_joint |
0.0 | 1.4835298641951802 |
| 8 | idx84_hand_r_pinky_abad_joint |
0.0 | 0.1850049007113989 |
| 9 | idx85_hand_r_pinky_pip_joint |
0.0 | 1.4835298641951802 |
Typical state values:
- Left hand open: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- Left hand grip: [-0.2, 1.45, -0.75, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0]
- Right hand open: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- Right hand grip: [0.2, -1.45, 0.75, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0]
- o12_t2: The joint position value ranges are as follows (in radians)
Left-hand joint limit values:
| Joint Index | Joint Name | Minimum | Maximum |
|---|---|---|---|
| 0 | idx31_hand_l_thumb_roll_joint |
-0.9425 | 0.0 |
| 1 | idx32_hand_l_thumb_abad_joint |
0.0 | 1.3875 |
| 2 | idx33_hand_l_thumb_mcp_joint |
-0.8273 | 0.0 |
| 3 | idx34_hand_l_thumb_pip_joint |
-1.2915 | 0.0 |
| 4 | idx36_hand_l_index_abad_joint |
-0.2618 | 0.2618 |
| 5 | idx37_hand_l_index_mcp_joint |
0.0 | 1.3526 |
| 6 | idx38_hand_l_index_pip_joint |
0.0 | 1.5307 |
| 7 | idx40_hand_l_middle_abad_joint |
-0.2618 | 0.2618 |
| 8 | idx41_hand_l_middle_mcp_joint |
0.0 | 1.3579 |
| 9 | idx42_hand_l_middle_pip_joint |
0.0 | 1.8151 |
| 10 | idx44_hand_l_ring_mcp_joint |
0.0 | 1.5359 |
| 11 | idx47_hand_l_pinky_mcp_joint |
0.0 | 1.5359 |
Right-hand joint limit values:
| Joint Index | Joint Name | Minimum | Maximum |
|---|---|---|---|
| 0 | idx71_hand_r_thumb_roll_joint |
0.0 | 0.9425 |
| 1 | idx72_hand_r_thumb_abad_joint |
-1.3875 | 0.0 |
| 2 | idx73_hand_r_thumb_mcp_joint |
-0.8273 | 0.0 |
| 3 | idx74_hand_r_thumb_pip_joint |
-1.2915 | 0.0 |
| 4 | idx76_hand_r_index_abad_joint |
-0.2618 | 0.2618 |
| 5 | idx77_hand_r_index_mcp_joint |
0.0 | 1.3526 |
| 6 | idx78_hand_r_index_pip_joint |
0.0 | 1.5307 |
| 7 | idx80_hand_r_middle_abad_joint |
-0.2618 | 0.2618 |
| 8 | idx81_hand_r_middle_mcp_joint |
0.0 | 1.3579 |
| 9 | idx82_hand_r_middle_pip_joint |
0.0 | 1.8151 |
| 10 | idx84_hand_r_ring_mcp_joint |
0.0 | 1.5359 |
| 11 | idx87_hand_r_pinky_mcp_joint |
0.0 | 1.5359 |
Typical state values:
- Left hand open: [-0.53, 0.42, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- Left hand grip: [-0.77, 0.5, -0.4, -0.36, -0.12, 0.69, 0.46, 0.0, 0.72, 0.5, 0.63, 0.63]
- Right hand open: [0.53, -0.42, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
- Right hand grip: [0.77, -0.5, -0.4, -0.36, 0.12, 0.69, 0.46, 0.0, 0.72, 0.5, 0.63, 0.63]
Parameter description:
- group must be "left_tool" (left end-effector), "right_tool" (right end-effector), or "dual_tool" (both end-effectors); any other value returns ErrorCode::kInvalidInput
- When group is "left_tool" or "right_tool", states.size() must exactly match the joint-count requirement corresponding to target_type
- When group is "dual_tool", states.size() must be 2x the joint-count requirement corresponding to target_type (the first half is used for the left end-effector, the second half for the right end-effector)
- target_type must be one of the supported values listed above; any other value returns ErrorCode::kInvalidInput
- nums must equal the size of the states vector
- states cannot be empty; states.size() must be greater than 0, otherwise ErrorCode::kInvalidInput is returned
JointState struct:
| Member | Type | Description | Unit |
|---|---|---|---|
position |
double |
Joint position (required) | Opening degree |
-
Return value:
GDKRes, the operation result status code. ReturnsGDKRes::kSuccesson success -
Error handling:
- If
joint_states.states.size() <= 0,ErrorCode::kInvalidInputis returned - If
target_typeis not one of the supported values ("omnipicker", "dahuan", "ctek90d", "o10_t2", "o12_t2"),ErrorCode::kInvalidInputis returned - If
joint_states.states.size()does not match the joint-count requirement corresponding totarget_type(for "dual_tool", it must be 2x),ErrorCode::kInvalidInputis returned - If
groupis not "left_tool", "right_tool", or "dual_tool",ErrorCode::kInvalidInputis returned - If a joint position value exceeds the value range for the corresponding end-effector type,
ErrorCode::kInvalidInputis returned -
For other error conditions, the corresponding error code is returned
-
Example:
Example 1: Controlling the left gripper (omnipicker type, requires 1 joint)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control the left gripper (omnipicker type, requires 1 joint)
agibot::gdk::JointStates left_joint_states;
left_joint_states.group = "left_tool";
left_joint_states.target_type = "omnipicker";
left_joint_states.states.resize(1);
left_joint_states.states[0].position = 0; // Value range [-0.785, 0]
left_joint_states.nums = left_joint_states.states.size();
if (robot.MoveEEPos(left_joint_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move left end effector position" << std::endl;
} else {
std::cout << "Left end-effector position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Example 2: Controlling the right gripper (dahuan type, requires 1 joint)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control the right gripper (dahuan type, requires 1 joint)
agibot::gdk::JointStates right_joint_states;
right_joint_states.group = "right_tool";
right_joint_states.target_type = "dahuan";
right_joint_states.states.resize(1);
right_joint_states.states[0].position = 0; // Value range [0, 0.025]
right_joint_states.nums = right_joint_states.states.size();
if (robot.MoveEEPos(right_joint_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move right end effector position" << std::endl;
} else {
std::cout << "Right end-effector position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Example 3: Controlling the left gripper (ctek90d type, requires 1 joint)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control the left gripper (ctek90d type, requires 1 joint)
agibot::gdk::JointStates left_joint_states;
left_joint_states.group = "left_tool";
left_joint_states.target_type = "ctek90d";
left_joint_states.states.resize(1);
left_joint_states.states[0].position = 0; // Value range [-0.91, 0]
left_joint_states.nums = left_joint_states.states.size();
if (robot.MoveEEPos(left_joint_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move left end effector position" << std::endl;
} else {
std::cout << "Left end-effector position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Example 4: Controlling the left end-effector (o10_t2 type, requires 10 joints)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control the left end-effector (o10_t2 type, requires 10 joints)
agibot::gdk::JointStates left_o10_states;
left_o10_states.group = "left_tool";
left_o10_states.target_type = "o10_t2";
left_o10_states.states.resize(10);
for (size_t i = 0; i < 10; ++i) {
left_o10_states.states[i].position = 0.0;
}
left_o10_states.nums = left_o10_states.states.size();
if (robot.MoveEEPos(left_o10_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move left end effector (o10_t2)" << std::endl;
} else {
std::cout << "Left end-effector (o10_t2) position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Example 5: Controlling the right end-effector (o12_t2 type, requires 12 joints)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control the right end-effector (o12_t2 type, requires 12 joints)
agibot::gdk::JointStates right_o12_states;
right_o12_states.group = "right_tool";
right_o12_states.target_type = "o12_t2";
right_o12_states.states.resize(12);
for (size_t i = 0; i < 12; ++i) {
right_o12_states.states[i].position = 0.0;
}
right_o12_states.nums = right_o12_states.states.size();
if (robot.MoveEEPos(right_o12_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move right end effector (o12_t2)" << std::endl;
} else {
std::cout << "Right end-effector (o12_t2) position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Example 6: Controlling both end-effectors (dual_tool, requires 2x the joint count)
#include "gdk/gdk.h"
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
// Initialize the GDK system
if (agibot::gdk::GDKInit() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK initialization failed" << std::endl;
return -1;
}
std::cout << "GDK initialized successfully" << std::endl;
agibot::gdk::Robot robot;
std::cout << "Robot init" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// Control both end-effectors (dual_tool, requires 2x the joint count)
// For example: using the omnipicker type requires 2 joints (1 left + 1 right)
agibot::gdk::JointStates dual_states;
dual_states.group = "dual_tool";
dual_states.target_type = "omnipicker";
dual_states.states.resize(2);
// The first half is used for the left end-effector
dual_states.states[0].position = 0.0;
// The second half is used for the right end-effector
dual_states.states[1].position = 0.0;
dual_states.nums = dual_states.states.size();
if (robot.MoveEEPos(dual_states) != agibot::gdk::GDKRes::kSuccess) {
std::cout << "Failed to move dual end effector" << std::endl;
} else {
std::cout << "Dual end-effector position control succeeded" << std::endl;
}
// Release GDK system resources
if (agibot::gdk::GDKRelease() != agibot::gdk::GDKRes::kSuccess) {
std::cout << "GDK release failed" << std::endl;
return -1;
}
std::cout << "GDK released successfully" << std::endl;
return 0;
}
Usage Notes¶
- GDK initialization: Before using Robot functionality, you must first call
agibot::gdk::GDKInit()to initialize the GDK system - GDK release: Before the program exits, you must call
agibot::gdk::GDKRelease()to release GDK system resources - Initialization wait: After creating the Robot object, it is recommended to wait 1 second to ensure the DDS connection is established
- Joint names: Confirm the correctness of joint names before use; they can be obtained via
GetJointStates() - Position range: Joint positions should be within a safe range to avoid exceeding mechanical limits
- Velocity limit: Set reasonable joint velocities to avoid hazards from excessively fast motion
- Lifetime: Set the request lifetime appropriately to avoid command expiration
- Error handling: Check return values promptly and handle possible error conditions
- Control group selection: Select the appropriate control group (left arm/right arm/both arms) when controlling the end-effector
- Pose setting: Pay attention to the correctness of the coordinate frame when setting the end-effector pose
- State monitoring: Periodically check error codes to ensure the robot operates safely
- Temperature monitoring: Monitor motor temperature to avoid damage from overheating
- Emergency stop state: Check the emergency stop state to ensure the robot can be controlled normally
- Data synchronization: Synchronize multi-sensor data based on timestamps
- Error handling: Always check the GDKRes return value to ensure the operation succeeded
Application Scenarios¶
- Robot control: Implements comprehensive motion control of the robot
- State monitoring: Monitors the state of the robot's components in real time
- Action execution: Executes complex robot action sequences
- Path planning: Performs path planning based on state information
- Safety detection: Monitors abnormal robot states to ensure safe operation
- End-effector control: Precisely controls the pose of the end-effector
- Dual-arm coordination: Implements coordinated control of a dual-arm robot
- Joint control: Implements high-precision joint position control
- Fault diagnosis: Performs fault diagnosis and handling via error codes
- Data fusion: Combines multi-sensor data for robot control