Source code for mbodied.hardware.xarm_interface

# Copyright 2024 mbodi ai
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import math

from gymnasium import spaces
from xarm.wrapper import XArmAPI

from mbodied.hardware.recording_interface import RecordingHardwareInterface
from mbodied.types.motion.control import HandControl
from mbodied.types.sense.vision import Image


[docs] class XarmInterface(RecordingHardwareInterface): """Control the xArm robot arm with SDK. Usage: xarm = XarmInterface() 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", record=False): """Initializes the XarmInterface and sets up the robot arm. Args: ip: The IP address of the xArm robot. record: Whether to record the state of the robot arm to dataset. """ if record: recorder_kwargs = { "name": "xarm_record", "observation_space": spaces.Dict( {"image": Image(size=(224, 224)).space(), "instruction": spaces.Text(1000)}, ), "action_space": HandControl().space(), "out_dir": "xarm_dataset", } super().__init__(**recorder_kwargs) self.ip = ip self.arm = XArmAPI(self.ip) 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(1000) self.arm.set_gripper_mode(0) self.home_pos = [300, 0, 325, -180, 0, 0] self.arm.set_position(*self.home_pos, wait=True, speed=200) self.arm.set_gripper_position(800, wait=True)
[docs] def do(self, motion: HandControl) -> None: """Executes a given HandControl motion. HandControl is in meters and radians, so we convert it to mm and degrees here. Args: motion: The HandControl motion to be executed. """ current_pos = self.arm.get_position()[1] current_pos[0] += motion.pose.x * 1000 current_pos[1] += motion.pose.y * 1000 current_pos[2] += motion.pose.z * 1000 current_pos[3] += math.degrees(motion.pose.roll) current_pos[4] += math.degrees(motion.pose.pitch) current_pos[5] += math.degrees(motion.pose.yaw) self.arm.set_position(*current_pos, wait=False, speed=200) self.arm.set_gripper_position(motion.grasp.value * 800, wait=False)
[docs] def set_pose(self, motion: HandControl) -> None: """Sets the robot arm to a given absolute HandControl pose.""" current_pos = self.arm.get_position()[1] current_pos[0] = motion.pose.x * 1000 current_pos[1] = motion.pose.y * 1000 current_pos[2] = motion.pose.z * 1000 current_pos[3] = math.degrees(motion.pose.roll) current_pos[4] = math.degrees(motion.pose.pitch) current_pos[5] = math.degrees(motion.pose.yaw) self.arm.set_position(*current_pos, wait=True, speed=200) self.arm.set_gripper_position(motion.grasp.value * 800, wait=True)
[docs] def get_pose(self) -> HandControl: """Gets the current pose (absolute HandControl) of the robot arm. Returns: A list of the current pose values [x, y, z, r, p, y]. """ current_pos = self.arm.get_position()[1] current_pos[0] = round(current_pos[0], 2) / 1000 current_pos[1] = round(current_pos[1], 2) / 1000 current_pos[2] = round(current_pos[2], 2) / 1000 current_pos[3] = round(math.radians(current_pos[3]), 6) current_pos[4] = round(math.radians(current_pos[4]), 6) current_pos[5] = round(math.radians(current_pos[5]), 6) hand_control = current_pos.copy() hand_control.append(self.arm.get_gripper_position()[1] / 800) return HandControl.unflatten(hand_control)
[docs] def capture(self) -> Image: """Captures an image from the robot camera. Placeholder for real camera input.""" return Image(size=(224, 224))