Skip to content
⚙ Development Guide > SDK > API

Usage Examples#

Initialize the client AirbotClient.__init__(host: str = "localhost", port: int = 50051)
from arm_sdk import AirbotClient   # Import the AirbotClient class from the arm_sdk package

def main():
    client_arm = AirbotClient(host="localhost", port=50051)  # Initializing AirbotClient automatically connects to the robotic arm server at localhost:50051
    client_arm.close() # Release the connection and exit safely

if __name__ == "__main__":
    main()
Get current robotic arm joint data get_arm_joint_state() -> Optional[ArmJointState]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time

def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_arm_joint_state()  # Get joint state
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")

if __name__ == "__main__":
    main()
Get current robotic arm motor data get_arm_motor_state() -> Optional[ArmMotorState]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_arm_motor_state()  # Get motor state
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")


if __name__ == "__main__":
    main()
Get current end-effector joint data get_eef_joint_state() -> Optional[EEFJointState]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_eef_joint_state()  # Get end-effector state
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")


if __name__ == "__main__":
    main()
Get current end-effector motor data get_eef_motor_state() -> Optional[EEFMotorState]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_eef_motor_state()  # Get end-effector motor state
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")


if __name__ == "__main__":
    main()
Get the current Cartesian-space pose of the robotic arm tool end get_end_pose() -> Optional[CartesianPose]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_end_pose()  # Get tool-end pose
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")


if __name__ == "__main__":
    main()
Get the current operating state of the robotic arm server get_service_state() -> Optional[ServiceState]
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.enter_gravity_compensation_mode()  # Enter gravity-compensation mode

        try:
            while True:
                state = arm.get_service_state()  # Get server data
                if state:
                    print(state)
                time.sleep(0.01)
        except KeyboardInterrupt:
            print("\n[INFO] Interrupted by user, exiting...")


if __name__ == "__main__":
    main()
Get current robotic arm firmware information get_firmware_info() -> Optional[ArmFirmwareInfo]
from arm_sdk import AirbotClient, ArmControlOptions, Controller


def main():
    with AirbotClient(port=50051) as arm:  # Using a context manager for the Client lifecycle is recommended
        try:
            fw_info = arm.get_firmware_info()  # Get firmware information
            print(fw_info)

        except KeyboardInterrupt:
            pass
        finally:
            arm.close()


if __name__ == "__main__":
    main()
Set the maximum robotic arm joint velocity and maximum motion percentage set_arm_speed(arm_speed: list[float]) -> bool
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

if __name__ == "__main__":
    main()
Set the maximum end-effector velocity and maximum motion percentage set_eef_speed(eef_speed: list[float]) -> bool
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.set_eef_speed(
            1.0 * math.pi
        )  # Set the maximum motor velocity to 1.0 * pi

if __name__ == "__main__":
    main()
Set the robotic arm controller switch_controller(controller: Controller, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller  # Import AirbotClient and the Controller enum from the arm_sdk package


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        arm.switch_controller(
            Controller.servo_control
        )  # Switch to the servo controller

if __name__ == "__main__":
    main()
Enter gravity-compensation mode enter_gravity_compensation_mode(timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient  # Import the AirbotClient class from the arm_sdk package


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        arm.enter_gravity_compensation_mode() # Enter gravity-compensation mode

if __name__ == "__main__":
    main()
Control the robotic arm in joint space move_joint(pos: float, options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(Controller.direct_control)  # Switch to the forward controller
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        pos = [1.0, -1.0, 1.0, 0.0, 0.0, 0.0]  # Set the target position
        options.eff = [8.0, 8.0, 8.0, 8.0, 8.0, 8.0]  # Set the motor current threshold

        arm.move_joint(pos, options)  # Send the control command


if __name__ == "__main__":
    main()

💡 options parameters required by each controller for robotic arm joint-space control

Controller Required options Parameter Notes
Controller.direct_control options.eff Motor current threshold
options.eef_eff End-effector torque
Controller.servo_control options.eff Motor current threshold
options.eef_pos Target end-effector position (if an end effector is present)
options.eef_eff End-effector current threshold (if an end effector is present)
Controller.planning_control
See Appendix 4.3 for details
options.eff Motor current threshold
options.sampling_time Trajectory sampling period (seconds)
options.allow_planning_time Maximum planning time
options.velocity_scaling_factor Velocity scaling factor
options.acceleration_scaling_factor Acceleration scaling factor
options.force_calc_lin Whether to enable the interpolation strategy to force planning after linear planning fails
options.lin_interpolate_num Number of interpolation points after linear planning fails
options.lin_hard_threshold Hard velocity threshold for linear-planning failure
options.circ_is_center Whether the circular-trajectory path point is the center of the circle
options.allow_blend_fail Allow blending failure
options.motion_type Planning mode; accepted strings are PTP and RRT_CONNECT
Controller.mit_control options.kp Motor kp
options.kd Motor kd
options.torque Motor torque
options.eef_torque End-effector torque
options.eef_kp End-effector kp
options.eef_kd End-effector kd
Control the end effector in joint space move_eef(pos: float, options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(Controller.direct_control) # Switch to the forward controller
        arm.set_eef_speed(
            math.pi
        )  # Set the maximum motor velocity to 1.0 * pi

        pos = 0.07  # Set the target position
        options.eef_eff = 6.0  # Set the motor current threshold

        arm.move_eef(pos, options)  # Send the control command


if __name__ == "__main__":
    main()
Control the robotic arm in Cartesian space move_end_pose(pos: CartesianPose, options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(Controller.direct_control) # Switch to the forward controller
        arm.set_arm_speed(
            [math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        pos = CartesianPose((0.4, 0.0, 0.3), (0.0, 0.0, 0.0, 1.0)) # Set the target pose
        options.eff = [8.0, 8.0, 8.0, 8.0, 8.0, 8.0]  # Set the motor current threshold

        arm.move_end_pose(pos, options)  # Send the control command


if __name__ == "__main__":
    main()
Plan and control a Cartesian-space linear trajectory move_end_pose_linear(start: CartesianPose, target: CartesianPose, options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(
            Controller.planning_control
        )  # Switch to the joint_trajectory controller
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        start = CartesianPose((0.4, 0.0, 0.3), (0.0, 0.0, 0.0, -1.0))  # Set the start pose
        target = CartesianPose((0.4, 0.1, 0.3), (0.0, 0.0, 0.0, -1.0))  # Set the target pose
        options.eff = [8.0, 8.0, 8.0, 8.0, 8.0, 8.0]  # Set the motor current threshold
        options.sampling_time = 0.01  # Set the trajectory sampling period
        options.allow_planning_time = 5.0  # Set the maximum planning time
        options.velocity_scaling_factor = 0.1  # Set the velocity scaling factor
        options.acceleration_scaling_factor = 1.0  # Set the acceleration scaling factor
        options.force_calc_lin = False  # Set force_calc_lin
        options.lin_hard_threshold = 10.0  # Set the hard velocity threshold at singularities
        options.lin_interpolate_num = 5  # Set the number of linear interpolation points at singularities

        arm.move_end_pose_linear(start, target, options)  # Send the control command


if __name__ == "__main__":
    main()
Plan and control a Cartesian-space circular trajectory move_end_pose_circle(start: CartesianPose, path: CartesianPose, target: CartesianPose, options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(
            Controller.planning_control
        )  # Switch to the joint_trajectory controller
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        start = CartesianPose((0.4, -0.2, 0.2), (0.0, 0.0, 0.0, 1.0)) # Set the start pose 
        path = CartesianPose((0.6, 0.0, 0.2), (0.0, 0.0, 0.0, 1.0)) # Set the path-point pose 
        target = CartesianPose((0.2, 0.3, 0.1), (0.0, 0.0, 0.0, 1.0)) # Set the target pose 
        options.eff = [8.0, 8.0, 8.0, 8.0, 8.0, 8.0]  # Set the motor current threshold
        options.sampling_time = 0.01  # Set the trajectory sampling period
        options.allow_planning_time = 5.0  # Set the maximum planning time
        options.velocity_scaling_factor = 0.1    # Set the velocity scaling factor
        options.acceleration_scaling_factor = 1.0  # Set the acceleration scaling factor
        options.circ_is_center = False  # Set whether path in CIRC is the center of the arc's circle

        arm.move_end_pose_circle(start, path, target, options)  # Send the control command


if __name__ == "__main__":
    main()
Plan and control multiple robotic arm joint-space waypoints move_joint_waypoints(waypoints: list[list[float]], options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(
            Controller.planning_control
        )  # Switch to the joint_trajectory controller
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        waypoints = []
        waypoints.append([1.0, -1.0, 1.0, 0.0, 0.0, 0.0])  # Set waypoints1
        waypoints.append([0.0, -1.0, 1.0, 0.0, 0.0, 0.0])  # Set waypoints2
        options.min_blend_radius = 0.001  # Set the minimum blending radius
        options.sampling_time = 0.01  # Set the trajectory sampling period
        options.allow_planning_time = 5.0  # Set the maximum planning time
        options.velocity_scaling_factor = 0.1  # Set the velocity scaling factor
        options.acceleration_scaling_factor = 1.0  # Set the acceleration scaling factor
        options.allow_blend_fail = True  # Set allow_blend_fail

        arm.move_joint_waypoints(waypoints, options)


if __name__ == "__main__":
    main()
Plan and control multiple robotic arm Cartesian-space waypoints move_end_pose_waypoints(waypoints: list[CartesianPose], options: ArmControlOptions, timeout_ms: int = 1000) -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose
import math


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership

        options = ArmControlOptions()  # Initialize a default ArmControlOptions data structure

        arm.switch_controller(
            Controller.planning_control
        )  # Switch to the joint_trajectory controller
        arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum motor velocity to 1.0 * pi

        waypoints = []
        waypoints.append(
            CartesianPose(position=(0.4, 0.0, 0.3), orientation=(0.0, 0.0, 0.0, 1.0))
        )  # Set waypoints1
        waypoints.append(
            CartesianPose(position=(0.4, 0.0, 0.1), orientation=(0.0, 0.0, 0.0, 1.0))
        )  # Set waypoints2
        waypoints.append(
            CartesianPose(position=(0.4, 0.0, 0.5), orientation=(0.0, 0.0, 0.0, 1.0))
        )  # Set waypoints3

        options.min_blend_radius = 0.005  # Set the minimum blending radius
        options.sampling_time = 0.01  # Set the trajectory sampling period
        options.allow_planning_time = 5.0  # Set the maximum planning time
        options.velocity_scaling_factor = 0.1  # Set the velocity scaling factor
        options.acceleration_scaling_factor = 1.0  # Set the acceleration scaling factor
        options.allow_blend_fail = True  # Set allow_blend_fail

        arm.move_end_pose_waypoints(waypoints, options)


if __name__ == "__main__":
    main()
Return the robotic arm to zero return_zero() -> bool
from arm_sdk import AirbotClient, Controller, ArmControlOptions, CartesianPose


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Acquire control ownership
        arm.return_zero() # Send the return-to-zero command


if __name__ == "__main__":
    main()
Emergency-stop and recover the robotic arm set_arm_emergency_stop(mode: bool) -> bool
from arm_sdk import AirbotClient
import time


def main():
    with AirbotClient() as arm:  # Using a context manager for the Client lifecycle is recommended
        arm.acquire_control()  # Emergency stop requires control ownership
        arm.set_arm_emergency_stop(mode=True)  # Emergency stop
        time.sleep(5.0)
        arm.set_arm_emergency_stop(mode=False)  # Recover control


if __name__ == "__main__":
    main()
Clear robotic arm motor error codes clear_arm_motor_err() -> bool
from arm_sdk import AirbotClient, Controller
import time


def main():
    client = AirbotClient(port=50051)  # Initializing AirbotClient automatically connects to the robotic arm server; the default host is localhost and the server address and port are localhost:50051 
    client.acquire_control()  # Control ownership is required
    client.clear_arm_motor_err() # Clear robotic arm motor error codes


if __name__ == "__main__":
    main()
Clear end-effector motor error codes clear_eef_motor_err() -> bool
from arm_sdk import AirbotClient, Controller
import time


def main():
    client = AirbotClient(port=50051)  # Initializing AirbotClient automatically connects to the robotic arm server; the default host is localhost and the server address and port are localhost:50051 
    client.acquire_control()  # Control ownership is required
    client.clear_eef_motor_err() # Clear end-effector motor error codes


if __name__ == "__main__":
    main()
Use a utility function for one-to-one control
from arm_sdk import AirbotClient, Controller, ArmControlOptions, utilities
import time


def main():
    port_play: int = 50051,
    port_replay: int = 50052,
    pendant_model: str = "REPLAY",
    gripper_model: str = "G2",
    eff: tuple[float, float, float, float, float, float] = (
        8.0,
        8.0,
        8.0,
        8.0,
        8.0,
        8.0,
    ),
    hz: float = 50.0,
    duration_s: float = 0.0,
    client_arm = AirbotClient(port=port_play)
    client_replay = AirbotClient(port=port_replay)

    dt = 1.0 / max(hz, 1.0)

    try:
        ok = client_arm.acquire_control()
        if not ok:
            raise RuntimeError(
                "Failed to acquire control for PLAY (another client may be controlling)."
            )

        client_arm.switch_controller(
            Controller.servo_control
        )  # Switch to the servo_control controller
        client_arm.set_arm_speed(
            [1.0 * math.pi] * 6
        )  # Set the maximum robotic arm motor velocity to 1.0 * pi
        client_arm.set_eef_speed(
            1.0 * math.pi
        )  # Set the maximum end-effector motor velocity to 1.0 * pi

        options_arm = ArmControlOptions()
        options_arm.eff = list(eff)

        t0 = time.time()

        while True:
            if duration_s > 0.0 and (time.time() - t0) >= duration_s:
                break

            states = client_replay.get_arm_joint_state()
            pos = states.angles

            states_eef = client_replay.get_eef_joint_state()

            pendant_pos = states_eef.eef_pos

            gripper_pos = utilities.map_pendant_to_gripper(
                pos=pendant_pos,
                from_pendant=pendant_model,
                to_gripper=gripper_model,
            )
            print("Gripper pos: ", gripper_pos)
            print("EEF pos: ", pendant_pos)

            options_arm.eef_pos = gripper_pos
            options_arm.eef_eff = 10.0

            client_arm.move_joint(list(pos), options_arm)

            time.sleep(dt)

    except KeyboardInterrupt:
        pass
    finally:
        client_arm.close()
        client_replay.close()


if __name__ == "__main__":
    main()