Skip to content

Xarm Robot

XarmRobot

Bases: Robot

Control the xArm robot arm with SDK.

Usage:

xarm = XarmRobot()
xarm.do(HandControl(...))

Attributes:

Name Type Description
ip

The IP address of the xArm robot.

arm

The XArmAPI instance for controlling the robot.

home_pos

The home position of the robot arm.

Source code in mbodied/robots/xarm_robot.py
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
class XarmRobot(Robot):
    """Control the xArm robot arm with SDK.

    Usage:
    ```python
    xarm = XarmRobot()
    xarm.do(HandControl(...))
    ```

    Attributes:
        ip: The IP address of the xArm robot.
        arm: The XArmAPI instance for controlling the robot.
        home_pos: The home position of the robot arm.
    """

    def __init__(self, ip: str = "192.168.1.228", use_realsense: bool = False):
        """Initializes the XarmRobot and sets up the robot arm.

        Args:
            ip: The IP address of the xArm robot.
            use_realsense: Whether to use a RealSense camera for capturing images
        """
        self.ip = ip

        self.arm = XArmAPI(self.ip, is_radian=True)
        self.arm.motion_enable(True)
        self.arm.clean_error()
        self.arm.set_mode(0)
        self.arm.set_state(0)

        self.arm.set_gripper_mode(0)
        self.arm.set_gripper_enable(True)
        self.arm.set_gripper_speed(2000)

        self.home_pos = [300, 0, 325, math.radians(180), 0, 0]
        self.arm_speed = 200
        self.arm.set_position(*self.home_pos, wait=True, speed=self.arm_speed)
        self.arm.set_gripper_position(800, wait=True)
        self.arm.set_collision_sensitivity(3)
        self.arm.set_self_collision_detection(True)

        self.use_realsense = False
        if use_realsense:
            self.use_realsense = True
            from mbodied.hardware.realsense_camera import RealsenseCamera

            self.realsense_camera = RealsenseCamera(width=640, height=480, fps=30)

    def do(self, motion: HandControl | list[HandControl]) -> None:
        """Executes HandControl(s).

        HandControl is in meters and radians.

        Args:
            motion: The HandControl motion(s) to be executed.
        """
        if not isinstance(motion, list):
            motion = [motion]
        for m in motion:
            current_pos = self.arm.get_position()[1]
            current_pos[0] += m.pose.x * 1000
            current_pos[1] += m.pose.y * 1000
            current_pos[2] += m.pose.z * 1000
            current_pos[3] += m.pose.roll
            current_pos[4] += m.pose.pitch
            current_pos[5] += m.pose.yaw
            self.arm.set_position(*current_pos, wait=True, speed=self.arm_speed)
            self.arm.set_gripper_position(0 if m.grasp.value <= 0.5 else 800, wait=True)

    def get_state(self) -> HandControl:
        """Gets the current pose (absolute HandControl) of the robot arm.

        Returns:
            The current pose of the robot arm.
        """
        current_pos = self.arm.get_position()[1]
        current_pos[0] = round(current_pos[0] / 1000, 5)
        current_pos[1] = round(current_pos[1] / 1000, 5)
        current_pos[2] = round(current_pos[2] / 1000, 5)
        current_pos[3] = round(current_pos[3], 3)
        current_pos[4] = round(current_pos[4], 3)
        current_pos[5] = round(current_pos[5], 3)

        hand_control = current_pos.copy()
        if self.arm.get_gripper_position()[1] >= 750:
            hand_control.append(1)
        else:
            hand_control.append(0)
        return HandControl.unflatten(hand_control)

    def prepare_action(self, old_pose: HandControl, new_pose: HandControl) -> HandControl:
        """Calculates the action between two poses.

        Args:
            old_pose: The old pose(state) of the hardware.
            new_pose: The new pose(state) of the hardware.

        Returns:
            The action to be taken between the old and new poses.
        """
        # Calculate the difference between the old and new poses. Use absolute value for grasp.
        old = list(old_pose.flatten())
        new = list(new_pose.flatten())
        result = [(new[i] - old[i]) for i in range(len(new) - 1)] + [new[-1]]
        return HandControl.unflatten(result)

    def capture(self) -> Image:
        """Captures an image from the robot camera."""
        if self.use_realsense:
            rgb_image, _, _ = self.realsense_camera.capture_realsense_images()
            return Image(rgb_image, size=(224, 224))
        return Image(size=(224, 224))

    def get_observation(self) -> Image:
        """Captures an image for recording."""
        return self.capture()

__init__(ip='192.168.1.228', use_realsense=False)

Initializes the XarmRobot and sets up the robot arm.

Parameters:

Name Type Description Default
ip str

The IP address of the xArm robot.

'192.168.1.228'
use_realsense bool

Whether to use a RealSense camera for capturing images

False
Source code in mbodied/robots/xarm_robot.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def __init__(self, ip: str = "192.168.1.228", use_realsense: bool = False):
    """Initializes the XarmRobot and sets up the robot arm.

    Args:
        ip: The IP address of the xArm robot.
        use_realsense: Whether to use a RealSense camera for capturing images
    """
    self.ip = ip

    self.arm = XArmAPI(self.ip, is_radian=True)
    self.arm.motion_enable(True)
    self.arm.clean_error()
    self.arm.set_mode(0)
    self.arm.set_state(0)

    self.arm.set_gripper_mode(0)
    self.arm.set_gripper_enable(True)
    self.arm.set_gripper_speed(2000)

    self.home_pos = [300, 0, 325, math.radians(180), 0, 0]
    self.arm_speed = 200
    self.arm.set_position(*self.home_pos, wait=True, speed=self.arm_speed)
    self.arm.set_gripper_position(800, wait=True)
    self.arm.set_collision_sensitivity(3)
    self.arm.set_self_collision_detection(True)

    self.use_realsense = False
    if use_realsense:
        self.use_realsense = True
        from mbodied.hardware.realsense_camera import RealsenseCamera

        self.realsense_camera = RealsenseCamera(width=640, height=480, fps=30)

capture()

Captures an image from the robot camera.

Source code in mbodied/robots/xarm_robot.py
143
144
145
146
147
148
def capture(self) -> Image:
    """Captures an image from the robot camera."""
    if self.use_realsense:
        rgb_image, _, _ = self.realsense_camera.capture_realsense_images()
        return Image(rgb_image, size=(224, 224))
    return Image(size=(224, 224))

do(motion)

Executes HandControl(s).

HandControl is in meters and radians.

Parameters:

Name Type Description Default
motion HandControl | list[HandControl]

The HandControl motion(s) to be executed.

required
Source code in mbodied/robots/xarm_robot.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def do(self, motion: HandControl | list[HandControl]) -> None:
    """Executes HandControl(s).

    HandControl is in meters and radians.

    Args:
        motion: The HandControl motion(s) to be executed.
    """
    if not isinstance(motion, list):
        motion = [motion]
    for m in motion:
        current_pos = self.arm.get_position()[1]
        current_pos[0] += m.pose.x * 1000
        current_pos[1] += m.pose.y * 1000
        current_pos[2] += m.pose.z * 1000
        current_pos[3] += m.pose.roll
        current_pos[4] += m.pose.pitch
        current_pos[5] += m.pose.yaw
        self.arm.set_position(*current_pos, wait=True, speed=self.arm_speed)
        self.arm.set_gripper_position(0 if m.grasp.value <= 0.5 else 800, wait=True)

get_observation()

Captures an image for recording.

Source code in mbodied/robots/xarm_robot.py
150
151
152
def get_observation(self) -> Image:
    """Captures an image for recording."""
    return self.capture()

get_state()

Gets the current pose (absolute HandControl) of the robot arm.

Returns:

Type Description
HandControl

The current pose of the robot arm.

Source code in mbodied/robots/xarm_robot.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def get_state(self) -> HandControl:
    """Gets the current pose (absolute HandControl) of the robot arm.

    Returns:
        The current pose of the robot arm.
    """
    current_pos = self.arm.get_position()[1]
    current_pos[0] = round(current_pos[0] / 1000, 5)
    current_pos[1] = round(current_pos[1] / 1000, 5)
    current_pos[2] = round(current_pos[2] / 1000, 5)
    current_pos[3] = round(current_pos[3], 3)
    current_pos[4] = round(current_pos[4], 3)
    current_pos[5] = round(current_pos[5], 3)

    hand_control = current_pos.copy()
    if self.arm.get_gripper_position()[1] >= 750:
        hand_control.append(1)
    else:
        hand_control.append(0)
    return HandControl.unflatten(hand_control)

prepare_action(old_pose, new_pose)

Calculates the action between two poses.

Parameters:

Name Type Description Default
old_pose HandControl

The old pose(state) of the hardware.

required
new_pose HandControl

The new pose(state) of the hardware.

required

Returns:

Type Description
HandControl

The action to be taken between the old and new poses.

Source code in mbodied/robots/xarm_robot.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def prepare_action(self, old_pose: HandControl, new_pose: HandControl) -> HandControl:
    """Calculates the action between two poses.

    Args:
        old_pose: The old pose(state) of the hardware.
        new_pose: The new pose(state) of the hardware.

    Returns:
        The action to be taken between the old and new poses.
    """
    # Calculate the difference between the old and new poses. Use absolute value for grasp.
    old = list(old_pose.flatten())
    new = list(new_pose.flatten())
    result = [(new[i] - old[i]) for i in range(len(new) - 1)] + [new[-1]]
    return HandControl.unflatten(result)