7.1 Motion Control

7.1 Motion Control

7.1.1 Overview

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 TypeAction CodeNameDescriptionAvailable Control Interfaces
Safety ActionPASSIVEDefault ModeThe default action after motion control starts
Safety ActionDAMPINGDamping ModeThe joints can still be moved, but they have high damping and can be held in place
Position-Control ActionPD_STANDPosition-Control Stand ModeThe robot stands in position-control mode and initializes its joints before entering force-control mode
Force-Control ActionMOTIONMotion ModeIn this mode, the robot can walk, perform upper-body motions, dance, and more
  • /motion/control/arm_joint_command
Force-Control ActionSIT_DOWNSit-Down ModeUsed together with the STAND_UP mode
Force-Control ActionSTAND_UPStand-Up ModeUsed together with the SIT_DOWN mode
Force-Control ActionLIE_DOWNLie-Down ModeUsed together with the GET_UP mode
Force-Control ActionGET_UPGet-Up ModeUsed together with the LIE_DOWN mode
Force-Control ActionPACKAGE_LIE_DOWNPacking-Box Lie-Down ModeUsed together with the PACKAGE_GET_UP mode
Force-Control ActionPACKAGE_GET_UPPacking-Box Get-Up ModeUsed 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:

bash
Stop `motion_player` command
 curl -i \ -H 'content-type:application/json' \ -X POST 'http://127.0.0.1:50080/json/stop_app' \ -d '{"app_name": "motion_ player"}'
Restart `motion_player` command
 curl -i \ -H 'content-type:application/json' \ -X POST 'http://127.0.0.1:50080/json/start_app' \ -d '{"app_name": "motion_ player"}'

Note: after stopping the motion_player module, actions in the resource management module cannot be played.

7.1.2 State Machine Switching and Query RPC Interfaces

Interface Namepb:/aimdk.protocol.MotionControlActionService/SetAction
Function OverviewSwitch the motion control state machine
Interface Type HTTP JSON RPC
URLhttp://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/SetAction
Input Parameters
text
{
  "header": {
    "timestamp": {
      "seconds": 1763614279,
      "nanos": 847810000,
      "ms_since_epoch": 1763614279847
    },
    "control_source": "ControlSource_SAFE"
  },
  "command": {
      "action": "MotionControlAction_GET_UP",
      "ext_action": "GET_UP"
  }
}
  • action: Obtain it from the GetAvailableActions interface
  • ext_action: Obtain it from the GetAvailableActions interface
Output Parameters
text
{
  "header": {
    "code": "0",
    "msg": "called successfully.",
    "timestamp": {
      "seconds": "1763643079",
      "nanos": 849593506,
      "ms_since_epoch": "0"
    },
    "trace_id": "",
    "domin": ""
  },
  "state": "CommonState_SUCCESS"
}
  • state: Request status
Example Scriptexamples/mc/S_SetAction.py
Notes
  • 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.
  • This interface has no Action restrictions
Interface Namepb:/aimdk.protocol.MotionControlActionService/GetAction
Function OverviewQuery the motion control state machine
Interface Type HTTP JSON RPC
URLhttp://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/GetAction
Input Parameters
text
{}
Output Parameters
text
{
  "header": {
    "code": "0",
    "msg": "called successfully.",
    "timestamp": {
      "seconds": "1763643026",
      "nanos": 8207141,
      "ms_since_epoch": "0"
    },
    "trace_id": "",
    "domin": ""
  },
  "info": {
    "current_action": "MotionControlAction_PASSIVE",
    "ext_action": "",
    "status": "MotionControlActionStatus_RUNNING"
  }
}
  • current_action: The currently running Action
  • ext_action: Extended Action, generally not used
  • status: Action status, generally not used
Example Scriptexample/mc/S_GetAction.py
Notes
  • This interface has no Action restrictions

7.1.3 RPC Interface for Querying Available Robot Actions

Interface Namepb:/aimdk.protocol.MotionControlActionService/GetAvailableActions
Function OverviewGet available actions
Interface Type HTTP JSON RPC
URLhttp://10.42.10.12:56322/rpc/aimdk.protocol.MotionControlActionService/GetAvailableActions
Input Parameters
text
{ 
    "header": {
      "timestamp": {
        "seconds": "0",
        "nanos": 0,
        "ms_since_epoch": "1744598548952"
      }
    }
}
Output Parameters
text
{
  "header": {
    "code": "0",
    "msg": "called successfully.",
    "timestamp": {
      "seconds": "1775639638",
      "nanos": 585833612,
      "ms_since_epoch": "0"
    },
    "trace_id": "module_mc",
    "domin": ""
  },
  "commands": [
    {
      "action": "MotionControlAction_DAMPING",
      "ext_action": "DAMPING"
    },
    {
      "action": "MotionControlAction_GET_UP",
      "ext_action": "GET_UP"
    },
    {
      "action": "MotionControlAction_LIE_DOWN",
      "ext_action": "LIE_DOWN"
    },
......
  ]
}
  • action: Name of a switchable action
  • ext_action: Action code name corresponding to the `action` output field
Example Scriptexamples/mc/S_SetAction.py
NotesIn general, you first use GetAvailableActions to query the currently switchable actions, and then use SetAction to set the action state.

7.1.4 Walking Control Command Topic Interface

Interface Name/motion/control/locomotion_velocity
Function OverviewWalking control command
Interface Type ROS2 Topic
Input Parameters
text
{
  "data": {
    "mode": MotionControl_LocomotionMode_DEFAULT,
    "forward_velocity": 0.1,
    "lateral_velocity": 0.0,
    "angular_velocity": 0.0
  }
}
  • mode: Velocity control mode
    • 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 Scriptexamples/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.

7.1.5 Arm Control Command and State Topic Interfaces

Interface Name/motion/control/arm_joint_command
Function OverviewArm joint control command
Interface Type ROS2 Topic
Input Parameterssensor_msgs::msg::JointState
  • 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 Scriptexamples/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.
Interface Name/motion/control/arm_joint_state
Function OverviewArm joint state topic
Interface Type ROS2 Topic
Output Parameterssensor_msgs::msg::JointState
  • name: Names of the 14 joints
  • position: Angles of the 14 joints
  • velocity: Velocities of the 14 joints
  • effort: Torques of the 14 joints
Example Scriptexamples/mc/joint_state.py
NotesThis interface has no Action restrictions

7.1.6 Waist Posture Control Topic Interface

Interface Name/motion/control/move_waist
Function OverviewWaist posture control
Interface Type ros2 topic
Input Parameters
text

{
  "header": {
    "timestamp": {
      "seconds": 1763681490,
      "nanos": 943287000,
      "ms_since_epoch": 1763681490943
    },
    "control_source": "ControlSource_MANUAL"
  },
    "waist_pitch": 0.1,
    "waist_roll": 0,
    "waist_yaw": 0,
    "waist_height": -0.1,
}
  • The parameter ranges are as follows:
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 Scriptexamples/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.

7.1.7 Neck Control Command and State Topic Interfaces

Interface Name/motion/control/neck_joint_command
Function OverviewNeck control command
Interface Type ROS2 Topic
Input Parameterssensor_msgs::msg::JointState
  • 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 Scriptexamples/mc/neck.py
Notes
  • Note: this interface can only be called in the motion state.
Interface Name/motion/control/neck_joint_state
Function OverviewNeck state topic
Interface Type ROS2 Topic
Output Parameterssensor_msgs::msg::JointState
  • 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 Scriptexamples/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.

7.1.8 Finger Control Command and State Topic Interfaces

Interface Name/motion/control/hand_joint_command
Function OverviewFinger control command
Interface Type ROS2 Topic
Input Parameterssensor_msgs::msg::JointState
  • 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 Scriptexamples/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.
Interface Name/motion/control/hand_joint_state
Function OverviewFinger state topic
Interface Type ROS2 Topic
Output Parameterssensor_msgs::msg::JointState
  • name: Joint names of each finger
  • frame_id: A3 hand type
  • 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 Scriptexamples/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.
  • This interface has no Action restrictions.