The A3-Ultra robot comes preinstalled with a motion control program. Users only need to send high-level commands to directly control the robot's locomotion, without developing low-level control models for walking and similar functions.
The AgiBot motion control program is designed with an internal state machine that switches between different models under different states. The state machine is shown below:
The states are described as follows:
Action Type
Action Code
Name
Description
Available Control Interfaces
Safety Action
PASSIVE
Default Mode
The default action after motion control starts
Safety Action
DAMPING
Damping Mode
The joints can still be moved, but they have high damping and can be held in place
Position-Control Action
PD_STAND
Position-Control Stand Mode
The robot stands in position-control mode and initializes its joints before entering force-control mode
Force-Control Action
MOTION
Motion Mode
In this mode, the robot can walk, perform upper-body motions, dance, and more
/motion/control/arm_joint_command
Force-Control Action
SIT_DOWN
Sit-Down Mode
Used together with the STAND_UP mode
Force-Control Action
STAND_UP
Stand-Up Mode
Used together with the SIT_DOWN mode
Force-Control Action
LIE_DOWN
Lie-Down Mode
Used together with the GET_UP mode
Force-Control Action
GET_UP
Get-Up Mode
Used together with the LIE_DOWN mode
Force-Control Action
PACKAGE_LIE_DOWN
Packing-Box Lie-Down Mode
Used together with the PACKAGE_GET_UP mode
Force-Control Action
PACKAGE_GET_UP
Packing-Box Get-Up Mode
Used together with the PACKAGE_LIE_DOWN mode
In general, switching states other than force-control states programmatically is not recommended. Programmatic switching is recommended only among force-control states. Other transitions involve operations such as lifting or lowering the robot and should only be performed manually.
Control interfaces generally have Action requirements. Interfaces without explicitly stated Action requirements, as well as query interfaces, generally have no Action restrictions.
Except for walking control commands, the robot's other joint-control topic interfaces are occupied by the motion_player module by default. Stop the motion_player module before sending joint-control commands. The commands are as follows:
This is an asynchronous interface. Completion of the call does not mean the switch has completed. Use the GetAction interface to check whether the switch is complete.
MotionControl_LocomotionMode_DEFAULT is the default mode
MotionControl_LocomotionMode_NAVIGATION is navigation mode
forward_velocity: Forward velocity scale factor. The sent scale factor ranges from -1.0 to 1.0. `+` means forward and `-` means backward. The actual speed is calculated by `mc`.
lateral_velocity: Lateral velocity scale factor. The sent scale factor ranges from -1.0 to 1.0. `+` means moving left and `-` means moving right. The actual speed is calculated by `mc`.
angular_velocity: Angular velocity scale factor. The sent scale factor ranges from -1.0 to 1.0. `+` means rotating left and `-` means rotating right. The actual speed is calculated by `mc`.
Example Script
examples/mc/walk.py
Notes
The ROS2 message type is `ros2_plugin_proto/msg/RosMsgWrapper`. Run `source prebuilt/ros2_plugin_proto_aarch64/share/ros2_plugin_proto/local_setup.bash` before using it.
This interface has invocation restrictions and can only be called in the MOTION state.
name: Joint names. Must be fixed as ["left_shoulder_pitch_joint","left_shoulder_roll_joint","left_shoulder_yaw_joint",
"left_elbow_joint",
"left_wrist_roll_joint",
"left_wrist_pitch_joint",
"left_wrist_yaw_joint",
"right_shoulder_pitch_joint",
"right_shoulder_roll_joint",
"right_shoulder_yaw_joint",
"right_elbow_joint",
"right_wrist_roll_joint",
"right_wrist_pitch_joint",
"right_wrist_yaw_joint"]
position: Joint angles. You must fill in the angle values of all 14 joints.
velocity: Invalid field. Set it to 0.0.
effort: Invalid field. Set it to 0.0.
Example Script
examples/mc/arm.py
Notes
It is recommended to call this interface at 100 Hz. Make sure the interval between adjacent commands does not exceed 30 ms, the speed does not exceed 4 rad/s, and the commands remain as smooth as possible. Otherwise, jitter may occur. At a minimum, a basic low-pass filter is recommended: `y(k) = (1 - a) * y(k - 1) + a * x(k)`.
The angle limits are as follows (unit: rad)
left_shoulder_pitch_joint: ±2.967
left_shoulder_roll_joint: ±1.588
left_shoulder_yaw_joint: ±2.793
left_elbow_joint: -1.047 ~ 2.444
left_wrist_roll_joint: ±0.576
left_wrist_pitch_joint: ±1.623
left_wrist_yaw_joint: ±2.793
right_shoulder_pitch_joint: ±2.967
right_shoulder_roll_joint: ±1.588
right_shoulder_yaw_joint: ±2.793
right_elbow_joint: -1.047 ~ 2.444
right_wrist_roll_joint: ±0.576
right_wrist_pitch_joint: ±1.623
right_wrist_yaw_joint: ±2.793
This interface has invocation restrictions and can only be called in the MOTION state.
Because the `motion_player` module continuously sends commands to the `motion_control` module, stop the `motion_player` module before sending commands.
double waist_pitch // range: [-0.5, 0.5] unit: rad double waist_roll // range: [-0.3, 0.3] unit: rad double waist_yaw // range: [-1.57, 1.57] unit: rad double waist_height // range: [-0.4, 0.0] unit: m
Example Script
examples/mc/move_waist.py
Notes
The ROS2 message type is `ros2_plugin_proto/msg/RosMsgWrapper`. Run `source prebuilt/ros2_plugin_proto_aarch64/share/ros2_plugin_proto/local_setup.bash` before using it.
Because the `motion_player` module continuously sends commands to the `motion_control` module, stop the `motion_player` module before sending commands.
name: Joint names. Must be fixed as ["head_yaw_joint", "head_pitch_joint"]
position: Joint angles. The first value represents the yaw degree of freedom, ranging from -0.9 to 0.9. The second value represents the pitch degree of freedom, ranging from -0.3 to 0.3.
velocity: Invalid field. Leave it empty.
effort: Invalid field. Leave it empty.
Example Script
examples/mc/neck.py
Notes
Note: this interface can only be called in the motion state.
position: Joint angles. The first value represents the yaw degree of freedom, ranging from -0.9 to 0.9. The second value represents the pitch degree of freedom, ranging from -0.3 to 0.3.
Example Script
examples/mc/joint_state.py
Notes
Because the `motion_player` module continuously sends commands to the `motion_control` module, stop the `motion_player` module before sending commands.
frame_id: Hand type of A3. A3 supports two types: AgiHand and O10Hand. If left empty, AgiHand is used by default. The current hand type can be identified from the `header.frame_id` field in the `hand_joint_state` topic.
name: Joint names. This field may be left empty to use the default values, or obtained from the `name` field of the `hand_joint_state` topic.
position: Joint angles. The order corresponds to the joints listed in the `name` field. The range is 0 to 2000. This is an abstract unitless value, where 0 means fully open and 2000 means fully closed.
velocity: Invalid field. Leave it empty.
effort: Joint torque, in the same order as the joints in the `name` field. When the hand type is AgiHand, the range is 0 to 5700, where 0 means the corresponding linear actuator motor applies no torque, and 5700 means the torque reaches the maximum 5.7 N. Leave this field empty for O10Hand.
Example Script
examples/mc/hand.py
Notes
The finger control logic stops motion when either the torque or the position condition is satisfied. For example, if you send a target position of 1000 and a torque of 5700 for a finger, and nothing blocks the finger, the torque will not continue increasing after the position reaches 1000, and the torque value will remain relatively small. If an external object blocks the finger, such as when grasping an object, the torque will continue increasing to around 5700, corresponding to 5.7 N output from the linear actuator.
This interface has invocation restrictions and can only be called in the `motion` state.
Because the `motion_player` module continuously sends commands to the `motion_control` module, stop the `motion_player` module before sending commands.
position: Joint angles of each finger, ranging from 0 to 2000
velocity: Invalid field
effort: Torque of each finger, ranging from 0 to 5700.
For AgiHand, the output contains 12 dimensions corresponding to each joint. For O10Hand, the output is formed by concatenating multidimensional arrays.
It also includes pressure sensor array data for both hands, arranged as follows:
- Left-hand pressure: 16-dim thumb + 16-dim index + 16-dim middle + 16-dim ring + 16-dim pinky + 25-dim palm + 25-dim back_of_hand
- Right-hand pressure: Same structure and order as the left hand, appended after the left-hand data
Example Script
examples/mc/joint_state.py
Notes
Due to zero-position offset, the position range may drift slightly. This is normal.
Because of the internal linkage mechanism, rotating shafts, and spring-level mechanisms in the fingers, the torque may occasionally show slightly negative values (within -1000). This is normal.
Negative values may also appear when the fingers are affected by external force. This is normal.