GDK Robot Control Interface Documentation (Python)¶
Overview¶
The robot control module provides the G02 robot with capabilities such as retrieving joint states, controlling robot motion, and retrieving whole-body status. Through the Python interface, developers can conveniently implement fine-grained control of robot motion, suitable for a variety of scenarios such as basic control, status detection, and motion recording/playback.
Interface Description¶
Robot Class¶
This class encapsulates the main functional interfaces for robot control.
1. get_joint_states()¶
- Notes: Use
motor_positionandmotor_velocityto obtain the motor position and velocity.positionandvelocityare fields reserved for low-speed motors and do not need to be used in the current version. - Function: Retrieves joint state information
- Parameters: None
- Returns:
dict, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
timestamp |
int |
Timestamp | nanoseconds |
nums |
int |
Number of joints | integer |
states |
list[dict] |
List of joint states | list of dicts |
Structure of each joint state in states:
| Attribute | Type | Description | Unit |
|---|---|---|---|
name |
str |
Joint name | string |
mode |
int |
Joint mode | integer |
position |
float |
Joint position | radians |
velocity |
float |
Joint velocity | radians/second |
effort |
float |
Joint torque | Newton-meters |
motor_position |
float |
Motor position | radians |
motor_velocity |
float |
Motor velocity | radians/second |
motor_current |
float |
Motor current | amperes |
error_code |
int |
Error code | integer |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get joint states
joint_states = robot.get_joint_states()
print(f"Joint count: {joint_states['nums']}")
print(f"Timestamp: {joint_states['timestamp']}")
for state in joint_states['states']:
print(f"Joint: {state['name']}")
print(f" Position: {state['position']:.3f} rad")
print(f" Velocity: {state['velocity']:.3f} rad/s")
print(f" Torque: {state['effort']:.3f} N·m")
print(f" Motor position: {state['motor_position']:.3f} rad")
print(f" Motor current: {state['motor_current']:.3f} A")
print(f" Error code: {state['error_code']}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
2. get_whole_body_status()¶
- Function: Retrieves whole-body status information
- Parameters: None
- Returns:
dict, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
timestamp |
int |
Timestamp | nanoseconds |
right_arm_error |
int |
Right arm error code | integer |
left_arm_error |
int |
Left arm error code | integer |
right_arm_control |
bool |
Right arm control state | boolean |
left_arm_control |
bool |
Left arm control state | boolean |
right_arm_estop |
bool |
Right arm e-stop state | boolean |
left_arm_estop |
bool |
Left arm e-stop state | boolean |
right_end_error |
int |
Right end effector error code | integer |
left_end_error |
int |
Left end effector error code | integer |
right_end_model |
str |
Right end effector model | string |
left_end_model |
str |
Left end effector model | string |
waist_error |
int |
Waist error code | integer |
lift_error |
int |
Lift error code | integer |
neck_error |
int |
Head error code | integer |
chassis_error |
int |
Chassis error code | integer |
Meaning of mode values:
| Value | Meaning |
|---|---|
| 0 | Stopped |
| 1 | G1 servo |
| 2 | Path planning |
| 5 | G2 servo |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get whole-body status
status = robot.get_whole_body_status()
# Print basic information
print(f"Timestamp: {status['timestamp']}")
print(f"Right end effector model: {status['right_end_model']}")
print(f"Left end effector model: {status['left_end_model']}")
# Check error status
print("\n=== Error status check ===")
if status['right_arm_error'] == 0:
print("✅ Right arm OK")
else:
print(f"❌ Right arm error code: {status['right_arm_error']}")
if status['left_arm_error'] == 0:
print("✅ Left arm OK")
else:
print(f"❌ Left arm error code: {status['left_arm_error']}")
if status['waist_error'] == 0:
print("✅ Waist OK")
else:
print(f"❌ Waist error code: {status['waist_error']}")
if status['neck_error'] == 0:
print("✅ Head OK")
else:
print(f"❌ Head error code: {status['neck_error']}")
if status['chassis_error'] == 0:
print("✅ Chassis OK")
else:
print(f"❌ Chassis error code: {status['chassis_error']}")
# Check control status
print("\n=== Control status ===")
print(f"Right arm control: {'Yes' if status['right_arm_control'] else 'No'}")
print(f"Left arm control: {'Yes' if status['left_arm_control'] else 'No'}")
print(f"Right arm e-stop: {'Yes' if status['right_arm_estop'] else 'No'}")
print(f"Left arm e-stop: {'Yes' if status['left_arm_estop'] else 'No'}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
3. get_motion_control_status()¶
- Function: Retrieves end-effector motion control status
- Parameters: None
- Returns: A
MotionControlStatusobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
frame_names |
list[str] |
List of end-effector joint names | list of strings |
frame_poses |
list[Pose] |
List of end-effector joint poses | list of poses |
collision_pairs_1 |
list[str] |
Collision pair list 1 | list of strings |
collision_pairs_2 |
list[str] |
Collision pair list 2 | list of strings |
mode |
int |
Motion mode | integer |
error_code |
int |
Error code | integer |
error_msg |
str |
Error message | string |
twists |
list[Twist] |
List of velocities | list of velocities |
wrenches |
list[Wrench] |
List of forces/torques | list of forces/torques |
Meaning of mode values:
| Value | Meaning |
|---|---|
| 0 | Stopped |
| 1 | G1 servo |
| 2 | Path planning |
| 5 | G2 servo |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get motion control status
status = robot.get_motion_control_status()
print(f"Motion mode: {status.mode}")
print(f"Error code: {status.error_code}")
print(f"Error message: {status.error_msg}")
print(f"Joint count: {len(status.frame_names)}")
print(f"Collision pair count: {len(status.collision_pairs_1)}")
# Print all joint names
for i, frame_name in enumerate(status.frame_names):
print(f"Joint {i}: {frame_name}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
4. get_end_state()¶
- Function: Retrieves end-effector state information
- Parameters: None
- Returns:
dict, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
left_end_state |
dict |
Left end effector state information | dict |
right_end_state |
dict |
Right end effector state information | dict |
Structure of left_end_state/right_end_state:
| Attribute | Type | Description | Unit |
|---|---|---|---|
controlled |
bool |
Whether it is being controlled | boolean |
type |
int |
End effector type | integer |
names |
list[str] |
List of joint names | list of strings |
end_states |
list[dict] |
List of joint states | list of dicts |
Structure of each joint state in end_states:
| Attribute | Type | Description | Unit |
|---|---|---|---|
id |
int |
Joint ID | integer |
enable |
bool |
Whether it is enabled | boolean |
position |
float |
Joint position | radians |
velocity |
float |
Joint velocity | radians/second |
effort |
float |
Joint torque | Newton-meters |
current |
float |
Motor current | amperes |
voltage |
float |
Motor voltage | volts |
temperature |
float |
Motor temperature | Celsius |
status |
int |
Status code | integer |
err_code |
int |
Error code | integer |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get end effector state
end_state = robot.get_end_state()
# Print left end effector state
left_state = end_state['left_end_state']
print(f"Left end effector control status: {left_state['controlled']}")
print(f"Left end effector type: {left_state['type']}")
print(f"Left end effector joints: {left_state['names']}")
# Print left end effector joint details
for i, joint_state in enumerate(left_state['end_states']):
print(f"\nLeft end effector joint {i+1}:")
print(f" Joint ID: {joint_state['id']}")
print(f" Enabled: {joint_state['enable']}")
print(f" Position: {joint_state['position']:.3f} stroke value")
print(f" Velocity: {joint_state['velocity']:.3f} stroke value/s")
print(f" Torque: {joint_state['effort']:.3f} N·m")
print(f" Current: {joint_state['current']:.3f} A")
print(f" Voltage: {joint_state['voltage']:.3f} V")
print(f" Temperature: {joint_state['temperature']:.1f} °C")
print(f" Status code: {joint_state['status']}")
print(f" Error code: {joint_state['err_code']}")
# Print right end effector state
right_state = end_state['right_end_state']
print(f"\nRight end effector control status: {right_state['controlled']}")
print(f"Right end effector type: {right_state['type']}")
print(f"Right end effector joints: {right_state['names']}")
# Check end effector status
print("\n=== End effector status check ===")
for side in ['left', 'right']:
state = end_state[f'{side}_end_state']
if state['controlled']:
print(f"✅ {side} end effector is being controlled")
else:
print(f"❌ {side} end effector is not controlled")
for joint_state in state['end_states']:
if joint_state['err_code'] == 0:
print(f"✅ {side} end effector joint {joint_state['id']} OK")
else:
print(f"❌ {side} end effector joint {joint_state['id']} error code: {joint_state['err_code']}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
5. get_chassis_power_state()¶
- Function: Retrieves the chassis power state
- Returns: A
ChassisPowerStateobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
battery_main_power_switch_state |
uint8_t |
Battery main power switch state | unitless |
emergency_stop_pedal_state |
uint8_t |
Emergency stop pedal state | unitless |
battery_main_power_switch_fault_state |
uint8_t |
Battery main power switch fault state | unitless |
emergency_stop_pedal_fault_state |
uint8_t |
Emergency stop pedal fault state | unitless |
chassis_power_board_state |
uint8_t |
Chassis power board state | unitless |
chassis_left_traction_motor_power_state |
uint8_t |
Chassis left traction motor power state | unitless |
chassis_right_traction_motor_power_state |
uint8_t |
Chassis right traction motor power state | unitless |
chassis_left_steering_motor_power_state |
uint8_t |
Chassis left steering motor power state | unitless |
chassis_right_steering_motor_power_state |
uint8_t |
Chassis right steering motor power state | unitless |
chassis_lidar1_power_state |
uint8_t |
Chassis LiDAR 1 power state | unitless |
chassis_lidar2_power_state |
uint8_t |
Chassis LiDAR 2 power state | unitless |
chassis_ultrasonic_radar_power_state |
uint8_t |
Chassis ultrasonic radar power state | unitless |
chassis_tof_camera_power_state |
uint8_t |
Chassis ToF camera power state | unitless |
chassis_ethernet_switch_power_state |
uint8_t |
Chassis Ethernet switch power state | unitless |
chassis_external_power_output_state |
uint8_t |
Chassis external power output state | unitless |
battery_main_power_output_switch_state |
uint8_t |
Battery main power output switch state | unitless |
battery_states |
list[BatteryState] |
List of battery states | list of battery states |
charge_plug_insert_state |
uint8_t |
Charging plug insertion state | unitless |
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 | unitless |
charge_plug_input_open_circuit_fault_state |
uint8_t |
Charging plug input open-circuit fault state | unitless |
chassis_led_strip_power_state |
uint8_t |
Chassis LED strip power state | unitless |
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 | unitless |
power_poe_bus_power_on_fault_state |
uint8_t |
PoE bus power-on fault state | unitless |
chassis_board_12v_output_fault_state |
uint8_t |
Chassis board 12V output fault state | unitless |
chassis_board_5v_output_fault_state |
uint8_t |
Chassis board 5V output fault state | unitless |
chassis_power_board_fault_state |
uint32_t |
Chassis power board fault state | unitless |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get chassis power state
chassis_power_state = robot.get_chassis_power_state()
print(chassis_power_state)
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
6. get_chest_power_state()¶
- Function: Retrieves the chest power state
- Returns: A
ChestPowerStateobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
power_onoff_req |
uint8_t |
Power on/off request | unitless |
emergency_stop_button_req |
uint8_t |
Emergency stop button request | unitless |
power_switch_fault_state |
uint8_t |
Power switch fault state | unitless |
emergency_stop_button_fault_state |
uint8_t |
Emergency stop button fault state | unitless |
power_full_low_req |
uint8_t |
Power full/low request | unitless |
chest_power_board_power_state |
uint8_t |
Chest power board state | unitless |
domain_controller_power_state |
uint8_t |
Domain controller power state | unitless |
head_interactive_board_power_state |
uint8_t |
Head interactive board power state | unitless |
curved_screen_power_state |
uint8_t |
Curved screen power state | unitless |
head_yaw_motor_power_state |
uint8_t |
Head yaw motor power state | unitless |
head_pitch_motor_power_state |
uint8_t |
Head pitch motor power state | unitless |
head_roll_motor_power_state |
uint8_t |
Head roll motor power state | unitless |
fan_power_state |
uint8_t |
Fan power state | unitless |
chest_power_board_fan_fault_state |
uint8_t |
Chest power board fan fault state | unitless |
body_fan1_fault_state |
uint8_t |
Body fan 1 fault state | unitless |
body_fan2_fault_state |
uint8_t |
Body fan 2 fault state | unitless |
body_fan3_fault_state |
uint8_t |
Body fan 3 fault state | unitless |
body_fan4_fault_state |
uint8_t |
Body fan 4 fault state | unitless |
upper_body_led_strip_power_state |
uint8_t |
Upper body LED strip power state | unitless |
poe_power_state |
uint8_t |
PoE power state | unitless |
ipad_power_state |
uint8_t |
iPad power state | unitless |
chest_reserved_lidar_power_state |
uint8_t |
Chest reserved LiDAR power state | unitless |
chest_power_board_temperature |
float |
Chest power board temperature | °C |
chest_power_board_fault_state |
uint32_t |
Chest power board fault state | unitless |
- Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get chest power state
chest_power_state = robot.get_chest_power_state()
print(chest_power_state)
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
7. joint_control_request()¶
- Function: Joint position planning control interface; the call returns after the target position has been reached.
- Parameters: A
JointControlReqobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
life_time |
float |
Lifetime | seconds |
joint_names |
list[str] |
List of joint names | list of strings |
joint_positions |
list[float] |
List of joint positions | radians |
joint_velocities |
list[float] |
List of joint velocities | radians/second |
detail |
str |
Details | string |
- Returns:
int, 0 indicates success; an exception is raised on failure
Joint limit values¶
The limit values (in radians) for each joint 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:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Create joint control request
joint_control_req = agibot_gdk.JointControlReq()
joint_control_req.joint_names = ["idx01_body_joint1", "idx02_body_joint2"]
joint_control_req.joint_positions = [0.0, 0.0]
joint_control_req.joint_velocities = [0.1, 0.1]
joint_control_req.life_time = 5.0
joint_control_req.detail = "Test joint control"
try:
result = robot.joint_control_request(joint_control_req)
print("Joint control request succeeded")
except Exception as e:
print(f"Joint control request failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
8. move_head_joint()¶
- Function: Head joint position planning control interface; the call returns after the target position has been reached.
- Parameters:
positions:list[float], list of head joint positions, in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"velocities:list[float], list of head joint velocities (radians/second), in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"-
Returns:
int, 0 indicates success; an exception is raised on failure -
Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control head position (in joint order: idx11_head_joint1, idx12_head_joint2, idx13_head_joint3)
head_positions = [0.0, 0.0, 0.0] # List of head joint positions
head_velocities = [0.3, 0.3, 0.3] # List of head joint velocities
try:
result = robot.move_head_joint(head_positions, head_velocities)
print("Head control succeeded")
except Exception as e:
print(f"Head control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
9. move_waist_joint()¶
- Function: Waist joint position planning control interface; the call returns after the target position has been reached.
- Parameters:
positions:list[float], list of waist joint positions, in the order "idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5"velocities:list[float], list of waist joint velocities (radians/second), in the order "idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5"-
Returns:
int, 0 indicates success; an exception is raised on failure -
Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control waist position (in joint order: idx01_body_joint1, idx02_body_joint2, idx03_body_joint3, idx04_body_joint4, idx05_body_joint5)
waist_positions = [0.0, 0.0, 0.0, 0.0, 0.0] # List of waist joint positions
waist_velocities = [0.3, 0.3, 0.3, 0.3, 0.3] # List of waist joint velocities
try:
result = robot.move_waist_joint(waist_positions, waist_velocities)
print("Waist control succeeded")
except Exception as e:
print(f"Waist control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
10. move_arm_joint()¶
- Function: Arm joint position planning control interface; the call returns after the target position has been reached.
- Parameters:
positions:list[float], list of arm joint positions, 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:list[float], list of arm joint velocities (radians/second), 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:int, control group; 0 controls the left arm, 1 controls the right arm, 2 controls both arms-
Returns:
int, 0 indicates success; an exception is raised on failure -
Example:
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control arm positions (in joint order: 7 left-arm joints + 7 right-arm joints)
arm_positions = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, # 7 left-arm joints
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # 7 right-arm joints
arm_velocities = [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, # 7 left-arm joint velocities
0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3] # 7 right-arm joint velocities
try:
result = robot.move_arm_joint(arm_positions, arm_velocities, 2)
print("Arm control succeeded")
except Exception as e:
print(f"Arm control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
11. joint_servo_control()¶
- Function: Joint position servo control interface. Requires a control frequency of 100 Hz, and supports both normal mode and low-latency mode, with normal mode used by default.
- Note: Low-latency mode has no collision protection — take care to ensure safety when using it. If you also need to control the end effector at the same time, use this interface to send the control command; see the example below for details.
- Parameters:
joint_servo_control_req: aJointServoControlReqobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
control_period |
float |
Control period | seconds |
joint_names |
list[str] |
List of joint names | list of strings |
joint_positions |
list[float] |
List of joint positions | radians |
joint_velocities |
list[float] |
List of joint velocities | radians/second |
enable_low_latency:bool, optional parameter, defaults toFalse.
Parameter notes:
- control_period denotes the control period, in seconds; it is recommended to make it slightly larger than the control interval
- The joint_names and joint_positions lists must be the same length
- Values in joint_positions must be within the limit range of the corresponding joint (see the joint limit values below), otherwise an exception is raised
- joint_names and joint_positions must not be empty, otherwise an exception is raised
- joint_velocities is a reserved parameter, currently unused, and may be left empty
- enable_low_latency selects the control channel; low-latency mode is suited to scenarios with higher real-time requirements
Joint limit values¶
The limit values (in radians) for each joint 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 (dexterous hand o10_t2, left hand) | ||
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 (dexterous hand o10_t2, right hand) | ||
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 (dexterous hand o12_t2, left hand) | ||
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 (dexterous hand o12_t2, right hand) | ||
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 |
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Exceptions:
- If
joint_namesorjoint_positionsis empty, the underlying layer returnsErrorCode::kInvalidInput, and Python raisesstd::runtime_error("JointServoControlRequest failed") - If a value in
joint_positionsexceeds the limit range of the corresponding joint, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
If retrieving the configuration parser fails, the underlying layer returns
ErrorCode::kRuntimeError, and Python raises an exception -
Example:
import agibot_gdk
import time
import math
# Control parameters
CONTROL_PERIOD = 0.01 # Control period (seconds)
RATE_HZ = 100.0 # Send frequency (Hz)
DURATION = 5.0 # Control duration (seconds)
MAX_POSITION_DELTA = 0.1 # Maximum position change (radians)
class JointServoControlController:
def __init__(self, robot):
self.robot = robot
def get_joint_position_by_name(self, joint_states, joint_name):
"""Get a joint's position by joint name"""
for state in joint_states['states']:
if state['name'] == joint_name:
return state['motor_position']
raise RuntimeError(f"Joint name {joint_name} not found")
def interpolate_position(self, start_pos, target_pos, t):
"""Compute an intermediate position via linear interpolation"""
return start_pos + t * (target_pos - start_pos)
def execute_joint_servo_control(self, target_joint_names, target_positions):
"""Execute joint position servo control"""
time.sleep(1.0) # Wait 1 second
# Get current joint states
current_joint_states = self.robot.get_joint_states()
print(f"Current joint count: {current_joint_states['nums']}")
# Get the starting positions
start_positions = []
for joint_name in target_joint_names:
try:
pos = self.get_joint_position_by_name(current_joint_states, joint_name)
start_positions.append(pos)
print(f"Joint {joint_name} current position: {pos:.3f} rad")
except RuntimeError as e:
print(f"Error: {e}")
return
# Compute the number of steps
n_steps = int(DURATION * RATE_HZ)
print(f"Total steps: {n_steps}, duration: {DURATION} s")
# Execute the trajectory
dt = 1.0 / RATE_HZ
start_time = time.time()
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 0.0
# Create a joint position servo request
joint_servo_control_req = agibot_gdk.JointServoControlReq()
joint_servo_control_req.control_period = CONTROL_PERIOD
# Compute the current target position (linear interpolation)
current_positions = []
for j, joint_name in enumerate(target_joint_names):
interp_pos = self.interpolate_position(
start_positions[j], target_positions[j], t
)
current_positions.append(interp_pos)
joint_servo_control_req.joint_names = target_joint_names
joint_servo_control_req.joint_positions = current_positions
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.joint_servo_control(joint_servo_control_req)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.joint_servo_control(joint_servo_control_req, enable_low_latency=True)
if result != 0:
print(f"Failed to send control command, step: {i}")
return
except Exception as e:
print(f"Exception sending control command, step: {i}, error: {e}")
return
# Control the send frequency
elapsed = time.time() - start_time
expected_time = (i + 1) * dt
sleep_time = expected_time - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
print("Joint position servo control complete")
# Hold the final position
print("Entering final position hold (Ctrl+C to stop)...")
try:
while True:
joint_servo_control_req = agibot_gdk.JointServoControlReq()
joint_servo_control_req.control_period = CONTROL_PERIOD
joint_servo_control_req.joint_names = target_joint_names
joint_servo_control_req.joint_positions = target_positions
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.joint_servo_control(joint_servo_control_req)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.joint_servo_control(joint_servo_control_req, enable_low_latency=True)
if result != 0:
print("Failed to hold position")
break
except Exception as e:
print(f"Exception while holding position: {e}")
break
time.sleep(dt)
except KeyboardInterrupt:
print("\nHold interrupted")
def main():
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get current joint states
current_joint_states = robot.get_joint_states()
print(f"Current joint count: {current_joint_states['nums']}")
# Define the joints to control (example: the first 3 joints of the left arm)
target_joint_names = [
"idx21_arm_l_joint1",
"idx22_arm_l_joint2",
"idx23_arm_l_joint3"
]
# Get the current positions to use as the starting positions (for interpolation)
controller = JointServoControlController(robot)
start_positions = []
for joint_name in target_joint_names:
pos = controller.get_joint_position_by_name(current_joint_states, joint_name)
start_positions.append(pos)
print(f"Joint {joint_name} current position: {pos:.3f} rad")
# Set target angles (directly specify the target angle values, in radians)
target_positions = [
0.0, # idx21_arm_l_joint1: target angle 0.0 radians
0.0, # idx22_arm_l_joint2: target angle 0.0 radians
0.0 # idx23_arm_l_joint3: target angle 0.0 radians
]
print(f"\nTarget angles:")
for i, joint_name in enumerate(target_joint_names):
print(f" {joint_name}: {target_positions[i]:.3f} rad")
# Execute joint position servo control
controller.execute_joint_servo_control(
target_joint_names, target_positions)
except Exception as e:
print(f"Error occurred during execution: {e}")
finally:
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
- Example — simultaneously controlling the arm and the end effector:
import agibot_gdk
import time
# Control parameters
CONTROL_PERIOD = 0.01 # Control period (seconds)
RATE_HZ = 100.0 # Send frequency (Hz)
DURATION = 3.0 # Duration of a single move (seconds)
HOLD_DURATION = 0.5 # Time to hold at 0 or 1 (seconds)
NUM_CYCLES = 3 # Number of back-and-forth cycles
# Names of the left arm's 7 joints (consistent with get_joint_states)
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",
]
def get_arm_positions_by_name(joint_states, joint_names):
"""Extract the list of positions by joint name from the return value of get_joint_states"""
name_to_pos = {s["name"]: s["motor_position"] for s in joint_states["states"]}
return [name_to_pos[name] for name in joint_names]
def get_ee_names_and_positions(end_state, side="left"):
"""Extract the joint name list and position list for the given side's end effector from the return value of get_end_state"""
key = f"{side}_end_state"
if key not in end_state:
raise RuntimeError(f"{key} not found in get_end_state")
state = end_state[key]
names = state.get("names", [])
positions = [s["position"] for s in state.get("end_states", [])]
if len(names) != len(positions):
raise RuntimeError(f"Length mismatch between names and end_states in {key}")
return names, positions
def main():
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2)
# 1) Get the whole-body joints (including the arm) from get_joint_states
joint_states = robot.get_joint_states()
# 2) Get the end-effector joint names and current positions (e.g. left gripper/left hand) from get_end_state
end_state = robot.get_end_state()
ee_names, ee_positions = get_ee_names_and_positions(end_state, "left")
# Merge: arm joints + end-effector joints
all_names = ARM_L_JOINT_NAMES + ee_names
arm_positions = get_arm_positions_by_name(joint_states, ARM_L_JOINT_NAMES)
# The arm moves slightly, while the end-effector joint moves back and forth between -0.785 and 0 (omnipicker)
arm_start = arm_positions[:] # Initial arm pose
arm_target = [p + 0.05 for p in arm_positions] # Target arm pose (small offset)
ee_low = -0.785 # End-effector lower bound
ee_high = 0.0 # End-effector upper bound
print(f"Controlled joint count: arm {len(ARM_L_JOINT_NAMES)} + end effector {len(ee_names)} = {len(all_names)}")
print(f"The arm will move in joint space between arm_start ↔ arm_target, and the end-effector joint will cycle between {ee_low} and {ee_high} {NUM_CYCLES} times")
n_steps = int(DURATION * RATE_HZ) # Number of steps for a single move
hold_steps = int(HOLD_DURATION * RATE_HZ) # Number of steps for the hold phase
dt = 1.0 / RATE_HZ
def send_control_command(arm_target_values, ee_target_values):
"""Helper function for sending the control command"""
current = arm_target_values + ee_target_values
req = agibot_gdk.JointServoControlReq()
req.control_period = CONTROL_PERIOD
req.joint_names = all_names
req.joint_positions = current
return robot.joint_servo_control(req)
for cycle in range(NUM_CYCLES):
print(f"\n=== Cycle {cycle+1}/{NUM_CYCLES}: arm arm_start -> arm_target, end effector {ee_low} -> {ee_high} ===")
start_time = time.time()
# Segment 1: arm arm_start -> arm_target, end effector ee_low -> ee_high
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 1.0
current_arm = [
arm_start[j] + t * (arm_target[j] - arm_start[j])
for j in range(len(ARM_L_JOINT_NAMES))
]
current_ee = [ee_low + t * (ee_high - ee_low) for _ in ee_names]
result = send_control_command(current_arm, current_ee)
if result != 0:
print(f"Send failed, cycle={cycle+1}, phase=0->1, step={i}")
raise RuntimeError("joint_servo_control failed")
elapsed = time.time() - start_time
sleep_time = (i + 1) * dt - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
# Segment 2: hold at arm_target / ee_high
print(f"=== Cycle {cycle+1}/{NUM_CYCLES}: holding at arm_target / {ee_high} for {HOLD_DURATION} s ===")
start_time = time.time()
current_arm = arm_target[:]
current_ee = [ee_high for _ in ee_names]
for i in range(hold_steps):
result = send_control_command(current_arm, current_ee)
if result != 0:
print(f"Send failed, cycle={cycle+1}, phase=hold@1, step={i}")
raise RuntimeError("joint_servo_control failed")
elapsed = time.time() - start_time
sleep_time = (i + 1) * dt - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
# Segment 3: arm arm_target -> arm_start, end effector ee_high -> ee_low
print(f"=== Cycle {cycle+1}/{NUM_CYCLES}: arm arm_target -> arm_start, end effector {ee_high} -> {ee_low} ===")
start_time = time.time()
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 1.0
current_arm = [
arm_target[j] + t * (arm_start[j] - arm_target[j])
for j in range(len(ARM_L_JOINT_NAMES))
]
current_ee = [ee_high + t * (ee_low - ee_high) for _ in ee_names]
result = send_control_command(current_arm, current_ee)
if result != 0:
print(f"Send failed, cycle={cycle+1}, phase=1->0, step={i}")
raise RuntimeError("joint_servo_control failed")
elapsed = time.time() - start_time
sleep_time = (i + 1) * dt - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
# Segment 4: hold at arm_start / ee_low
print(f"=== Cycle {cycle+1}/{NUM_CYCLES}: holding at arm_start / {ee_low} for {HOLD_DURATION} s ===")
start_time = time.time()
current_arm = arm_start[:]
current_ee = [ee_low for _ in ee_names]
for i in range(hold_steps):
result = send_control_command(current_arm, current_ee)
if result != 0:
print(f"Send failed, cycle={cycle+1}, phase=hold@0, step={i}")
raise RuntimeError("joint_servo_control failed")
elapsed = time.time() - start_time
sleep_time = (i + 1) * dt - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
print(f"\nArm arm_start↔arm_target and end-effector {ee_low}↔{ee_high} back-and-forth control finished")
except Exception as e:
print(f"Execution error: {e}")
finally:
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
12. move_head_joint_servo()¶
- Function: Head joint position servo control interface. Requires a control frequency of 100 Hz, and supports both normal mode and low-latency mode, with normal mode used by default.
- Note: Low-latency mode has no collision protection — take care to ensure safety when using it.
- Parameters:
positions:list[float], list of head joint positions (radians), in the order "idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"control_period:float, control period (seconds); it is recommended to make it slightly larger than the control intervalenable_low_latency:bool, optional parameter, defaults toFalse, used to select the control channel
Parameter notes:
- positions must have a length of 3
- Values in positions must be within the limit range of the corresponding joint (see the joint limit values below), otherwise an exception is raised
- control_period denotes the control period, in seconds; it is recommended to make it slightly larger than the control interval
- enable_low_latency selects the control channel; low-latency mode is suited to scenarios with higher real-time requirements
Joint limit values¶
The head joint limit values (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 |
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Exceptions:
- If the length of
positionsis not 3, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
If a value in
positionsexceeds the limit range of the corresponding joint, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
Example:
import agibot_gdk
import time
import math
# Control parameters
CONTROL_PERIOD = 0.01 # Control period (seconds)
RATE_HZ = 100.0 # Send frequency (Hz)
DURATION = 5.0 # Control duration (seconds)
class HeadJointServoController:
def __init__(self, robot):
self.robot = robot
def get_joint_position_by_name(self, joint_states, joint_name):
"""Get a joint's position by joint name"""
for state in joint_states['states']:
if state['name'] == joint_name:
return state['motor_position']
raise RuntimeError(f"Joint name {joint_name} not found")
def interpolate_position(self, start_pos, target_pos, t):
"""Compute an intermediate position via linear interpolation"""
return start_pos + t * (target_pos - start_pos)
def execute_head_joint_servo_control(self, target_positions):
"""Execute head joint position servo control"""
time.sleep(1.0) # Wait 1 second
# Get current joint states
current_joint_states = self.robot.get_joint_states()
# Get the starting positions
head_joint_names = ["idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"]
start_positions = []
for joint_name in head_joint_names:
try:
pos = self.get_joint_position_by_name(current_joint_states, joint_name)
start_positions.append(pos)
print(f"Joint {joint_name} current position: {pos:.3f} rad")
except RuntimeError as e:
print(f"Error: {e}")
return
# Compute the number of steps
n_steps = int(DURATION * RATE_HZ)
print(f"Total steps: {n_steps}, duration: {DURATION} s")
# Execute the trajectory
dt = 1.0 / RATE_HZ
start_time = time.time()
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 0.0
# Compute the current target position (linear interpolation)
current_positions = []
for j in range(3):
interp_pos = self.interpolate_position(
start_positions[j], target_positions[j], t
)
current_positions.append(interp_pos)
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_head_joint_servo(
current_positions, CONTROL_PERIOD)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_head_joint_servo(
# current_positions, CONTROL_PERIOD, enable_low_latency=True
# )
if result != 0:
print(f"Failed to send control command, step: {i}")
return
except Exception as e:
print(f"Exception sending control command, step: {i}, error: {e}")
return
# Control the send frequency
elapsed = time.time() - start_time
expected_time = (i + 1) * dt
sleep_time = expected_time - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
print("Head joint position servo control complete")
# Hold the final position
print("Entering final position hold (Ctrl+C to stop)...")
try:
while True:
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_head_joint_servo(
target_positions, CONTROL_PERIOD
)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_head_joint_servo(
# target_positions, CONTROL_PERIOD, enable_low_latency=True
# )
if result != 0:
print("Failed to hold position")
break
except Exception as e:
print(f"Exception while holding position: {e}")
break
time.sleep(dt)
except KeyboardInterrupt:
print("\nHold interrupted")
def main():
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get current joint states
current_joint_states = robot.get_joint_states()
# Define the target positions (example: head joints)
target_positions = [
0.0, # idx11_head_joint1: target angle 0.0 radians
0.0, # idx12_head_joint2: target angle 0.0 radians
0.0 # idx13_head_joint3: target angle 0.0 radians
]
print(f"\nTarget angles:")
head_joint_names = ["idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3"]
for i, joint_name in enumerate(head_joint_names):
print(f" {joint_name}: {target_positions[i]:.3f} rad")
# Execute head joint position servo control
controller = HeadJointServoController(robot)
controller.execute_head_joint_servo_control(target_positions)
except Exception as e:
print(f"Error occurred during execution: {e}")
finally:
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
13. move_waist_joint_servo()¶
- Function: Waist joint position servo control interface. Requires a control frequency of 100 Hz, and supports both normal mode and low-latency mode, with normal mode used by default.
- Note: Low-latency mode has no collision protection — take care to ensure safety when using it.
- Parameters:
positions:list[float], 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:float, control period (seconds); it is recommended to make it slightly larger than the control intervalenable_low_latency:bool, optional parameter, defaults toFalse, used to select the control channel
Parameter notes:
- positions must have a length of 5
- Values in positions must be within the limit range of the corresponding joint (see the joint limit values below), otherwise an exception is raised
- control_period denotes the control period, in seconds; it is recommended to make it slightly larger than the control interval
- enable_low_latency selects the control channel; low-latency mode is suited to scenarios with higher real-time requirements
Joint limit values¶
The waist joint limit values (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 |
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Exceptions:
- If the length of
positionsis not 5, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
If a value in
positionsexceeds the limit range of the corresponding joint, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
Example:
import agibot_gdk
import time
import math
# Control parameters
CONTROL_PERIOD = 0.01 # Control period (seconds)
RATE_HZ = 100.0 # Send frequency (Hz)
DURATION = 5.0 # Control duration (seconds)
class WaistJointServoController:
def __init__(self, robot):
self.robot = robot
def get_joint_position_by_name(self, joint_states, joint_name):
"""Get a joint's position by joint name"""
for state in joint_states['states']:
if state['name'] == joint_name:
return state['motor_position']
raise RuntimeError(f"Joint name {joint_name} not found")
def interpolate_position(self, start_pos, target_pos, t):
"""Compute an intermediate position via linear interpolation"""
return start_pos + t * (target_pos - start_pos)
def execute_waist_joint_servo_control(self, target_positions):
"""Execute waist joint position servo control"""
time.sleep(1.0) # Wait 1 second
# Get current joint states
current_joint_states = self.robot.get_joint_states()
# Get the starting positions
waist_joint_names = [
"idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3",
"idx04_body_joint4", "idx05_body_joint5"
]
start_positions = []
for joint_name in waist_joint_names:
try:
pos = self.get_joint_position_by_name(current_joint_states, joint_name)
start_positions.append(pos)
print(f"Joint {joint_name} current position: {pos:.3f} rad")
except RuntimeError as e:
print(f"Error: {e}")
return
# Compute the number of steps
n_steps = int(DURATION * RATE_HZ)
print(f"Total steps: {n_steps}, duration: {DURATION} s")
# Execute the trajectory
dt = 1.0 / RATE_HZ
start_time = time.time()
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 0.0
# Compute the current target position (linear interpolation)
current_positions = []
for j in range(5):
interp_pos = self.interpolate_position(
start_positions[j], target_positions[j], t
)
current_positions.append(interp_pos)
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_waist_joint_servo(
current_positions, CONTROL_PERIOD
)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_waist_joint_servo(
# current_positions, CONTROL_PERIOD, enable_low_latency=True
# )
if result != 0:
print(f"Failed to send control command, step: {i}")
return
except Exception as e:
print(f"Exception sending control command, step: {i}, error: {e}")
return
# Control the send frequency
elapsed = time.time() - start_time
expected_time = (i + 1) * dt
sleep_time = expected_time - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
print("Waist joint position servo control complete")
# Hold the final position
print("Entering final position hold (Ctrl+C to stop)...")
try:
while True:
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_waist_joint_servo(
target_positions, CONTROL_PERIOD
)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_waist_joint_servo(
# target_positions, CONTROL_PERIOD, enable_low_latency=True
# )
if result != 0:
print("Failed to hold position")
break
except Exception as e:
print(f"Exception while holding position: {e}")
break
time.sleep(dt)
except KeyboardInterrupt:
print("\nHold interrupted")
def main():
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get current joint states
current_joint_states = robot.get_joint_states()
# Define the target positions (example: waist joints)
target_positions = [
0.0, # idx01_body_joint1: target angle 0.0 radians
0.0, # idx02_body_joint2: target angle 0.0 radians
0.0, # idx03_body_joint3: target angle 0.0 radians
0.0, # idx04_body_joint4: target angle 0.0 radians
0.0 # idx05_body_joint5: target angle 0.0 radians
]
print(f"\nTarget angles:")
waist_joint_names = [
"idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3",
"idx04_body_joint4", "idx05_body_joint5"
]
for i, joint_name in enumerate(waist_joint_names):
print(f" {joint_name}: {target_positions[i]:.3f} rad")
# Execute waist joint position servo control
controller = WaistJointServoController(robot)
controller.execute_waist_joint_servo_control(target_positions)
except Exception as e:
print(f"Error occurred during execution: {e}")
finally:
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
14. move_arm_joint_servo()¶
- Function: Arm joint position servo control interface. Requires a control frequency of 100 Hz, and supports both normal mode and low-latency mode, with normal mode used by default.
- Note: Low-latency mode has no collision protection — take care to ensure safety when using it.
- Parameters:
positions:list[float], 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:float, control period (seconds); it is recommended to make it slightly larger than the control intervalcontrol_group:int, control group; 0 controls the left arm, 1 controls the right arm, 2 controls both armsenable_low_latency:bool, optional parameter, defaults toFalse, used to select the control channel
Parameter notes:
- positions must have a length of 7 (left arm or right arm) or 14 (both arms)
- Values in positions must be within the limit range of the corresponding joint (see the joint limit values below), otherwise an exception is raised
- control_period denotes the control period, in seconds; it is recommended to make it slightly larger than the control interval
- control_group denotes the control group: 0 controls the left arm, 1 controls the right arm, 2 controls both arms
- enable_low_latency selects the control channel; low-latency mode is suited to scenarios with higher real-time requirements
Joint limit values¶
The arm joint limit values (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 |
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Exceptions:
- If the length of
positionsis not 7 (left arm or right arm) or 14 (both arms), the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
If a value in
positionsexceeds the limit range of the corresponding joint, the underlying layer returnsErrorCode::kInvalidInput, and Python raises an exception -
Example:
import agibot_gdk
import time
import math
# Control parameters
CONTROL_PERIOD = 0.01 # Control period (seconds)
RATE_HZ = 100.0 # Send frequency (Hz)
DURATION = 5.0 # Control duration (seconds)
class ArmJointServoController:
def __init__(self, robot):
self.robot = robot
def get_joint_position_by_name(self, joint_states, joint_name):
"""Get a joint's position by joint name"""
for state in joint_states['states']:
if state['name'] == joint_name:
return state['motor_position']
raise RuntimeError(f"Joint name {joint_name} not found")
def interpolate_position(self, start_pos, target_pos, t):
"""Compute an intermediate position via linear interpolation"""
return start_pos + t * (target_pos - start_pos)
def execute_arm_joint_servo_control(self, target_positions, control_group):
"""Execute arm joint position servo control"""
time.sleep(1.0) # Wait 1 second
# Get current joint states
current_joint_states = self.robot.get_joint_states()
# Get the starting positions
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 left-arm joints
"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 right-arm joints
]
start_positions = []
for joint_name in arm_joint_names:
try:
pos = self.get_joint_position_by_name(current_joint_states, joint_name)
start_positions.append(pos)
print(f"Joint {joint_name} current position: {pos:.3f} rad")
except RuntimeError as e:
print(f"Error: {e}")
return
# Compute the number of steps
n_steps = int(DURATION * RATE_HZ)
print(f"Total steps: {n_steps}, duration: {DURATION} s")
# Execute the trajectory
dt = 1.0 / RATE_HZ
start_time = time.time()
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 0.0
# Compute the current target position (linear interpolation)
current_positions = []
for j in range(14):
interp_pos = self.interpolate_position(
start_positions[j], target_positions[j], t
)
current_positions.append(interp_pos)
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_arm_joint_servo(
current_positions, CONTROL_PERIOD, control_group
)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_arm_joint_servo(
# current_positions, CONTROL_PERIOD, control_group, enable_low_latency=True
# )
if result != 0:
print(f"Failed to send control command, step: {i}")
return
except Exception as e:
print(f"Exception sending control command, step: {i}, error: {e}")
return
# Control the send frequency
elapsed = time.time() - start_time
expected_time = (i + 1) * dt
sleep_time = expected_time - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
print("Arm joint position servo control complete")
# Hold the final position
print("Entering final position hold (Ctrl+C to stop)...")
try:
while True:
try:
# Use normal mode (enable_low_latency=False, the default)
result = self.robot.move_arm_joint_servo(
target_positions, CONTROL_PERIOD, control_group
)
# To use low-latency mode, pass enable_low_latency=True:
# result = self.robot.move_arm_joint_servo(
# target_positions, CONTROL_PERIOD, control_group, enable_low_latency=True
# )
if result != 0:
print("Failed to hold position")
break
except Exception as e:
print(f"Exception while holding position: {e}")
break
time.sleep(dt)
except KeyboardInterrupt:
print("\nHold interrupted")
def main():
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Get current joint states
current_joint_states = robot.get_joint_states()
# Define the target positions (example: arm joints)
target_positions = [
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, # 7 left-arm joints
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 # 7 right-arm joints
]
print(f"\nTarget angles:")
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 left-arm joints
"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 right-arm joints
]
for i, joint_name in enumerate(arm_joint_names):
print(f" {joint_name}: {target_positions[i]:.3f} rad")
# Execute arm joint position servo control
controller = ArmJointServoController(robot)
controller.execute_arm_joint_servo_control(target_positions, 2)
except Exception as e:
print(f"Error occurred during execution: {e}")
finally:
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
15. move_ee_pos()¶
- Function: Controls the end effector position (gripper opening/closing)
- Parameters: A
JointStatesobject
Structure of the JointStates object:
| Attribute | Type | Description | Unit |
|---|---|---|---|
group |
str |
Control group; must be "left_tool", "right_tool", or "dual_tool" | string |
target_type |
str |
Target type; see the table below for supported values | string |
states |
list[JointState] |
List of joint states (required) | list of JointState |
nums |
int |
Number of joints; must equal len(states) |
unitless |
Supported target_type values and the corresponding required joint counts:
target_type value |
Required joint count | Description |
|---|---|---|
"omnipicker" |
1 | Omni-directional 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: Joint value ranges are tied to the version — pay attention to the current version's value ranges when using this; the documentation reflects the ranges for the current version
- 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 value range for each joint position is as follows (unit: 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 closed (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 closed (grip): [0.2, -1.45, 0.75, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0]
- o12_t2: the value range for each joint position is as follows (unit: 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 closed (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 closed (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]
Structure of the JointState object:
| Attribute | Type | Description | Unit |
|---|---|---|---|
position |
float |
Joint position (required) | degree of opening |
Parameter notes:
- group must be "left_tool" (left end effector), "right_tool" (right end effector), or "dual_tool" (both end effectors)
- When group is "left_tool" or "right_tool", the length of the states list must exactly match the joint count required for the target_type
- When group is "dual_tool", the length of the states list must be twice the joint count required for the target_type (the first half is for the left end effector, the second half for the right end effector)
- target_type must be one of the supported values above; other values will return an error
- states is a list of JointState objects; each JointState only needs the position field set
- nums must equal len(states)
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Exceptions:
- If
target_typeis not one of the supported values ("omnipicker", "dahuan", "ctek90d", "o10_t2", "o12_t2"), the underlying layer returnsErrorCode::kInvalidInput - If the length of
statesdoes not match the joint count required bytarget_type(for "dual_tool", it must be twice that count), the underlying layer returnsErrorCode::kInvalidInput - If
groupis not "left_tool", "right_tool", or "dual_tool", the underlying layer returnsErrorCode::kInvalidInput - If
statesis empty, the underlying layer returnsErrorCode::kInvalidInput - If a joint position value exceeds the value range for the corresponding end-effector type, the underlying layer returns
ErrorCode::kInvalidInput -
If the control command fails to execute,
std::runtime_error("Failed to move end effector position")is raised -
Examples:
Example 1: Controlling the left gripper (omnipicker type, requires 1 joint)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control the left gripper (omnipicker type, requires 1 joint)
joint_states_left = agibot_gdk.JointStates()
joint_states_left.group = "left_tool"
joint_states_left.target_type = "omnipicker"
joint_state = agibot_gdk.JointState()
joint_state.position = 0 # Value range [-0.785, 0]
joint_states_left.states = [joint_state]
joint_states_left.nums = len(joint_states_left.states)
try:
result = robot.move_ee_pos(joint_states_left)
print("Left gripper control succeeded")
except Exception as e:
print(f"Left gripper control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
Example 2: Controlling the right gripper (dahuan type, requires 1 joint)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control the right gripper (dahuan type, requires 1 joint)
joint_states_right = agibot_gdk.JointStates()
joint_states_right.group = "right_tool"
joint_states_right.target_type = "dahuan"
joint_state = agibot_gdk.JointState()
joint_state.position = 0 # Right gripper position, value range [0, 0.025]
joint_states_right.states = [joint_state]
joint_states_right.nums = len(joint_states_right.states)
try:
result = robot.move_ee_pos(joint_states_right)
print("Right gripper control succeeded")
except Exception as e:
print(f"Right gripper control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
Example 3: Controlling the left gripper (ctek90d type, requires 1 joint)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control the left gripper (ctek90d type, requires 1 joint)
joint_states_left = agibot_gdk.JointStates()
joint_states_left.group = "left_tool"
joint_states_left.target_type = "ctek90d"
joint_state = agibot_gdk.JointState()
joint_state.position = 0.5 # Value range [-0.91, 0]
joint_states_left.states = [joint_state]
joint_states_left.nums = len(joint_states_left.states)
try:
result = robot.move_ee_pos(joint_states_left)
print("Left gripper (ctek90d) control succeeded")
except Exception as e:
print(f"Left gripper control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
Example 4: Controlling the left end effector (o10_t2 type, requires 10 joints)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control the left end effector (o10_t2 type, requires 10 joints)
joint_states_left_o10 = agibot_gdk.JointStates()
joint_states_left_o10.group = "left_tool"
joint_states_left_o10.target_type = "o10_t2"
# Create the list of joint states
positions = [-0.2, 1.45, -0.75, 0, 1, 1, 0, 1, 0, 1]
states_list = []
for i in range(10):
joint_state = agibot_gdk.JointState()
joint_state.position = positions[i]
states_list.append(joint_state)
# Assign the whole list directly
joint_states_left_o10.states = states_list
joint_states_left_o10.nums = len(joint_states_left_o10.states)
try:
result = robot.move_ee_pos(joint_states_left_o10)
print("Left end effector (o10_t2) control succeeded")
except Exception as e:
print(f"Left end effector control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
Example 5: Controlling the right end effector (o12_t2 type, requires 12 joints)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control the right end effector (o12_t2 type, requires 12 joints)
joint_states_right_o12 = agibot_gdk.JointStates()
joint_states_right_o12.group = "right_tool"
joint_states_right_o12.target_type = "o12_t2"
# Create the list of joint states
states_list = []
for i in range(12):
joint_state = agibot_gdk.JointState()
joint_state.position = 0
states_list.append(joint_state)
# Assign the whole list directly
joint_states_right_o12.states = states_list
joint_states_right_o12.nums = len(joint_states_right_o12.states)
try:
result = robot.move_ee_pos(joint_states_right_o12)
print("Right end effector (o12_t2) control succeeded")
except Exception as e:
print(f"Right end effector control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
Example 6: Controlling both end effectors (dual_tool, requires twice the joint count)
import agibot_gdk
import time
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
exit(1)
print("GDK initialized successfully")
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
# Control both end effectors (dual_tool, requires twice the joint count)
# For example: using the omnipicker type requires 2 joints (1 left + 1 right)
joint_states_dual = agibot_gdk.JointStates()
joint_states_dual.group = "dual_tool"
joint_states_dual.target_type = "omnipicker"
# The first half is for the left end effector
joint_state_left = agibot_gdk.JointState()
joint_state_left.position = 0
# The second half is for the right end effector
joint_state_right = agibot_gdk.JointState()
joint_state_right.position = 0
# Assign the whole list directly
joint_states_dual.states = [joint_state_left, joint_state_right]
joint_states_dual.nums = len(joint_states_dual.states)
try:
result = robot.move_ee_pos(joint_states_dual)
print("Dual end effector control succeeded")
except Exception as e:
print(f"Dual end effector control failed: {e}")
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
16. end_effector_pose_control()¶
- Function: End-effector pose control
- Note: This interface requires the sender to publish control commands at a frequency of 50 Hz, and step (discontinuous) signals are not allowed; this interface has no collision detection, so pay attention to the surrounding environment when using it.
- Parameters: An
EndEffectorPoseobject, containing the following attributes:
| Attribute | Type | Description | Unit |
|---|---|---|---|
life_time |
float |
Lifetime | seconds |
group |
int |
Control group | integer |
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 |
-
Returns:
int, 0 indicates success; an exception is raised on failure -
Example: (Note: for safety, this example first moves the robot to its initial pose (standing), and then calls end-effector pose control — please ensure the space around the robot is safe before running it)
import agibot_gdk
import time
import math
# Constant definitions
LEFT_NAME = "arm_l_end_link"
RIGHT_NAME = "arm_r_end_link"
# Target poses (position and quaternion)
TARGET_LEFT_POSITION = [0.626755,0.301127306,1.08398]
TARGET_LEFT_ORIENTATION = [0.5858436, -0.02614889,0.80973243,0.02089957]
TARGET_RIGHT_POSITION = [0.6099763,-0.3903393, 1.050190472]
TARGET_RIGHT_ORIENTATION = [0.648815,-0.001096,0.76094223696, 0.0020416]
# Control parameters
MAX_STEP_CM = 0.1 # Maximum step size (centimeters)
LIFETIME = 0.02 # Lifetime (seconds)
RATE_HZ = 50.0 # Send frequency (Hz)
HOLD_FINAL = True # Whether to hold the final pose
class EndEffectorController:
def __init__(self, robot):
self.robot = robot
def slerp(self, q0, q1, t):
"""
Spherical linear interpolation (SLERP) between quaternions
q0, q1: quaternions [x, y, z, w]
t: interpolation parameter [0, 1]
Returns: the interpolated quaternion [x, y, z, w]
"""
# Compute the dot product
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
q1_neg = [-q1[0], -q1[1], -q1[2], -q1[3]]
result = [q0[i] + t * (q1_neg[i] - q0[i]) for i in range(4)]
else:
result = [q0[i] + t * (q1[i] - q0[i]) for i in range(4)]
# Clamp the dot product range
dot = max(-1.0, min(1.0, dot))
if dot > 0.9995:
# Linear interpolation
norm = math.sqrt(sum(r*r for r in result))
if norm > 0.0:
result = [r / norm for r in result]
else:
# Spherical linear interpolation
theta_0 = math.acos(dot)
sin_theta_0 = math.sin(theta_0)
theta = theta_0 * t
sin_theta = math.sin(theta)
s0 = math.cos(theta) - dot * sin_theta / sin_theta_0
s1 = sin_theta / sin_theta_0
result = [s0 * q0[i] + s1 * q1[i] for i in range(4)]
return result
def distance_between_points(self, p1, p2):
"""Compute the distance between two points"""
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
dz = p2[2] - p1[2]
return math.sqrt(dx*dx + dy*dy + dz*dz)
def calculate_n_steps(self, start_pos, goal_pos, max_step_cm):
"""Compute the number of steps needed"""
dist_cm = self.distance_between_points(start_pos, goal_pos) * 100.0
return max(int(math.ceil(dist_cm / max_step_cm)), 1)
def plan_trajectory(self, start_pose, goal_pose, n_steps):
"""
Plan the trajectory
start_pose, goal_pose: dicts containing position and orientation
n_steps: number of steps
Returns: the list of trajectory poses
"""
trajectory = []
for i in range(n_steps):
t = float(i) / (n_steps - 1) if n_steps > 1 else 0.0
# Linear interpolation of position
pos = [
start_pose['position'][0] + t * (goal_pose['position'][0] - start_pose['position'][0]),
start_pose['position'][1] + t * (goal_pose['position'][1] - start_pose['position'][1]),
start_pose['position'][2] + t * (goal_pose['position'][2] - start_pose['position'][2])
]
# SLERP interpolation of the quaternion
q0 = start_pose['orientation']
q1 = goal_pose['orientation']
quat = self.slerp(q0, q1, t)
trajectory.append({
'position': pos,
'orientation': quat
})
return trajectory
def find_pose_by_name(self, status, target_name):
"""Look up a pose by name"""
for i, frame_name in enumerate(status.frame_names):
if frame_name == target_name:
pose = status.frame_poses[i]
# Extract the position and quaternion
position = [pose.position.x, pose.position.y, pose.position.z]
orientation = [pose.orientation.x, pose.orientation.y,
pose.orientation.z, pose.orientation.w]
return {'position': position, 'orientation': orientation}
raise RuntimeError(f"Frame name {target_name} not found")
def execute_end_pose_control(self):
"""Execute end-effector pose control"""
time.sleep(1.0) # Wait 1 second
# Get the current status
status = self.robot.get_motion_control_status()
# Get the starting poses
start_left_pose = self.find_pose_by_name(status, LEFT_NAME)
start_right_pose = self.find_pose_by_name(status, RIGHT_NAME)
# Target poses
goal_left_pose = {
'position': TARGET_LEFT_POSITION,
'orientation': TARGET_LEFT_ORIENTATION
}
goal_right_pose = {
'position': TARGET_RIGHT_POSITION,
'orientation': TARGET_RIGHT_ORIENTATION
}
# Compute the number of steps
n_left = self.calculate_n_steps(start_left_pose['position'],
goal_left_pose['position'],
MAX_STEP_CM)
n_right = self.calculate_n_steps(start_right_pose['position'],
goal_right_pose['position'],
MAX_STEP_CM)
n_steps = max(n_left, n_right)
print(f"Left arm steps: {n_left}, right arm steps: {n_right}, total steps: {n_steps}")
# Plan the trajectories
traj_left = self.plan_trajectory(start_left_pose, goal_left_pose, n_steps)
traj_right = self.plan_trajectory(start_right_pose, goal_right_pose, n_steps)
# Execute the trajectory
dt = 1.0 / RATE_HZ
for i in range(n_steps):
# Create the end-effector pose control request
end_pose = agibot_gdk.EndEffectorPose()
end_pose.life_time = LIFETIME
end_pose.group = agibot_gdk.EndEffectorControlGroup.kBothArms
# Set the left arm pose
end_pose.left_end_effector_pose.position.x = traj_left[i]['position'][0]
end_pose.left_end_effector_pose.position.y = traj_left[i]['position'][1]
end_pose.left_end_effector_pose.position.z = traj_left[i]['position'][2]
end_pose.left_end_effector_pose.orientation.x = traj_left[i]['orientation'][0]
end_pose.left_end_effector_pose.orientation.y = traj_left[i]['orientation'][1]
end_pose.left_end_effector_pose.orientation.z = traj_left[i]['orientation'][2]
end_pose.left_end_effector_pose.orientation.w = traj_left[i]['orientation'][3]
# Set the right arm pose
end_pose.right_end_effector_pose.position.x = traj_right[i]['position'][0]
end_pose.right_end_effector_pose.position.y = traj_right[i]['position'][1]
end_pose.right_end_effector_pose.position.z = traj_right[i]['position'][2]
end_pose.right_end_effector_pose.orientation.x = traj_right[i]['orientation'][0]
end_pose.right_end_effector_pose.orientation.y = traj_right[i]['orientation'][1]
end_pose.right_end_effector_pose.orientation.z = traj_right[i]['orientation'][2]
end_pose.right_end_effector_pose.orientation.w = traj_right[i]['orientation'][3]
try:
result = self.robot.end_effector_pose_control(end_pose)
if result != 0:
print(f"Failed to send control command, step: {i}")
return
print(f"Control command sent successfully, step: {i}")
except Exception as e:
print(f"Exception sending control command, step: {i}, error: {e}")
return
time.sleep(dt)
# Hold the final pose
if HOLD_FINAL:
print("Entering end-effector pose hold (Ctrl+C to stop)...")
try:
final_left = traj_left[-1]
final_right = traj_right[-1]
while True:
end_pose = agibot_gdk.EndEffectorPose()
end_pose.life_time = LIFETIME
end_pose.group = agibot_gdk.EndEffectorControlGroup.kBothArms
# Set the left arm pose
end_pose.left_end_effector_pose.position.x = final_left['position'][0]
end_pose.left_end_effector_pose.position.y = final_left['position'][1]
end_pose.left_end_effector_pose.position.z = final_left['position'][2]
end_pose.left_end_effector_pose.orientation.x = final_left['orientation'][0]
end_pose.left_end_effector_pose.orientation.y = final_left['orientation'][1]
end_pose.left_end_effector_pose.orientation.z = final_left['orientation'][2]
end_pose.left_end_effector_pose.orientation.w = final_left['orientation'][3]
# Set the right arm pose
end_pose.right_end_effector_pose.position.x = final_right['position'][0]
end_pose.right_end_effector_pose.position.y = final_right['position'][1]
end_pose.right_end_effector_pose.position.z = final_right['position'][2]
end_pose.right_end_effector_pose.orientation.x = final_right['orientation'][0]
end_pose.right_end_effector_pose.orientation.y = final_right['orientation'][1]
end_pose.right_end_effector_pose.orientation.z = final_right['orientation'][2]
end_pose.right_end_effector_pose.orientation.w = final_right['orientation'][3]
try:
result = self.robot.end_effector_pose_control(end_pose)
if result != 0:
print("Failed to hold pose")
break
except Exception as e:
print(f"Exception while holding pose: {e}")
break
time.sleep(dt)
except KeyboardInterrupt:
print("\nHold interrupted")
def main():
# Initialize the GDK system
if agibot_gdk.gdk_init() != agibot_gdk.GDKRes.kSuccess:
print("GDK initialization failed")
return
print("GDK initialized successfully")
try:
robot = agibot_gdk.Robot()
time.sleep(2) # Wait for the robot to finish initializing
print("Moving to initial pose...")
joint_control_req = agibot_gdk.JointControlReq()
joint_control_req.joint_names = [
"idx01_body_joint1", "idx02_body_joint2", "idx03_body_joint3", "idx04_body_joint4", "idx05_body_joint5",
"idx11_head_joint1", "idx12_head_joint2", "idx13_head_joint3",
"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 left-arm joints
"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 right-arm joints
]
joint_control_req.joint_positions = [-0.12526109443163597,
0.8407635483115572,
-0.971927299903638,
0,
0,
0,
0,
0.0036426282540360732,
1.7301117664332919,
-1.1500181062743811,
-1.5999388458662482,
-1.79993398793182,
-0.41992232715148303,
5.8962386534354331e-05,
3.8709046444301724e-05,
-1.7301030279359648,
-1.1500377304426637,
1.5999483134039236,
-1.6252835640650924,
0.42000178256260562,
1.3781858641160056e-05,
3.7151097206605374e-06]
joint_control_req.joint_velocities = [0.3] * 22 # Set the velocities
joint_control_req.life_time = 5.0
result = robot.joint_control_request(joint_control_req)
if result != 0:
print("Failed to move to initial pose")
return
print("Successfully moved to initial pose, waiting to settle...")
time.sleep(2)
controller = EndEffectorController(robot)
controller.execute_end_pose_control()
except Exception as e:
print(f"Error occurred during execution: {e}")
finally:
# Release GDK system resources
if agibot_gdk.gdk_release() != agibot_gdk.GDKRes.kSuccess:
print("GDK release failed")
else:
print("GDK released successfully")
if __name__ == "__main__":
main()
Usage Notes¶
- GDK initialization:
agibot_gdk.gdk_init()must be called to initialize the GDK system before using any robot control functionality - GDK release:
agibot_gdk.gdk_release()must be called to release GDK system resources before the program exits - Initialization wait: After creating a
Robotobject, it is recommended to wait 2 seconds to ensure the DDS connection is established - Joint names: Confirm that joint names are correct before use; they can be retrieved via
get_motion_control_status() - Position range: Joint positions should stay within a safe range to avoid exceeding mechanical limits
- Velocity limits: Set reasonable joint velocities to avoid dangerous, overly fast motion
- Lifetime: Set a reasonable request lifetime to avoid commands expiring
- Exception handling: All interfaces raise a
std::runtime_errorexception on failure, which must be handled appropriately - Data types: Position parameters use radians; velocity parameters use radians/second
- Timestamp precision: Timestamps are in nanoseconds, which can be used for precise time synchronization
Application Scenarios¶
- Basic control: Implementing basic motion control of the robot
- Status monitoring: Real-time monitoring of each robot joint's state
- Motion recording: Recording and replaying robot motion sequences
- Precise control: Implementing high-precision joint position control
- Safety detection: Monitoring abnormal robot states to ensure safe operation
- End-effector control: Controlling the opening/closing of grippers and other end effectors
- Multi-joint coordination: Implementing coordinated motion across multiple joints
- Pose control: Cartesian-coordinate-based end-effector pose control