Files
lerobot/robot_client/robots/realman/motors_bus.py
1002142102@qq.com cc31254055 1.增加xbox控制器和飞行手柄控制器
2.增加多臂多控制器模式
3.末端姿态由欧拉角控制切换到四元数控制
4.增加vr手柄控制器

Signed-off-by: 1002142102@qq.com <1002142102@qq.com>
2025-12-24 14:02:34 +08:00

306 lines
9.8 KiB
Python

import threading
import time
from typing import Any, Dict
from Robotic_Arm.rm_robot_interface import *
from lerobot.motors import Motor, MotorCalibration, MotorsBus
from .robot_mock import RealmanMock
from scipy.spatial.transform import Rotation as R
import numpy
#动作执行成功
ACTION_SUCCESS = 0
class RealmanMotorsBus(MotorsBus):
model_number_table={}
model_ctrl_table={
"realman":{}
}
ip: str
port: int
"""
对Realman SDK的二次封装
"""
def __init__(
self,
port: str,
motors:dict[str, Motor],
gripper_range:list[int],
joint: list,
udp_ip: str,
udp_port: int,
mock: bool = False,
calibration: dict[str, MotorCalibration] | None = None,
):
super().__init__(port,motors, calibration)
address = port.split(':')
self.ip = address[0]
self.port = int(address[1])
self.motors = motors
self.gripper_range = gripper_range
self.init_joint_position = joint
self.safe_disable_position = joint
self.mock = mock
if mock:
#self.rmarm = RealmanMock()
self.rmarm = RoboticArm(rm_thread_mode_e.RM_DUAL_MODE_E)
else:
self.rmarm = RoboticArm(rm_thread_mode_e.RM_DUAL_MODE_E)
self.handle = None
self.init_pose = numpy.zeros(8)
self.init_pose[-2] = 1
self.running = False
custom = rm_udp_custom_config_t()
custom.joint_speed = 0
# custom.lift_state = 1
custom.hand_state = 1
custom.plus_state = 1
custom.plus_base=1
custom.expand_state = 1
custom.arm_current_status = 1
custom.expand_state = 1
self.udp_config = rm_realtime_push_config_t(1, True, udp_port, 0, udp_ip, custom)
self.lock = threading.Lock()
self.temp_pose = numpy.zeros(8)
@property
def motor_names(self) -> list[str]:
return list(self.motors.keys())
@property
def motor_models(self) -> list[str]:
return [model for _, model in self.motors.values()]
@property
def motor_indices(self) -> list[int]:
return [idx for idx, _ in self.motors.values()]
def update_arm_state(self, state:rm_realtime_arm_joint_state_t):
joint = list(state.joint_status.joint_position)
gripper = state.expandState.pos
pose = state.waypoint.position
euler = state.waypoint.euler
pose = [pose.x, pose.y, pose.z, euler.rx, euler.ry, euler.rz, 0]
self.current_arm_state = {"joint": joint, "gripper": gripper, "pose": pose}
def connect(self, enable=True) -> bool:
'''
使能机械臂并检测使能状态,尝试5s,如果使能超时则退出程序
'''
self.handle = self.rmarm.rm_create_robot_arm(self.ip, self.port)
if self.mock:
self.rmarm.rm_set_arm_run_mode(0)#仿真模式
else:
self.rmarm.rm_set_arm_run_mode(1)
enable_flag = False
loop_flag = False
# 设置超时时间(秒)
timeout = 5
# 记录进入循环前的时间
start_time = time.time()
elapsed_time_flag = False
while not loop_flag:
elapsed_time = time.time() - start_time
print("--------------------")
if enable:
# 获取机械臂状态
ret = self.rmarm.rm_get_current_arm_state()
if ret[0] == 0: # 成功获取状态
enable_flag = True
else:
enable_flag = False
# 断开所有连接,销毁线程
RoboticArm.rm_destory()
print("使能状态:", enable_flag)
print("--------------------")
if(enable_flag == enable):
loop_flag = True
enable_flag = True
break
else:
loop_flag = False
enable_flag = False
# 检查是否超过超时时间
if elapsed_time > timeout:
print("超时....")
elapsed_time_flag = True
enable_flag = True
break
time.sleep(1)
# self.rmarm.rm_set_realtime_push(self.udp_config)
# self.arm_state_callback = rm_realtime_arm_state_callback_ptr(self.update_arm_state)
# self.rmarm.rm_realtime_arm_state_call_back(self.arm_state_callback)
self.rmarm.rm_movej(self.init_joint_position[:-1], 5, 0, 0, 1)
self.init_pose = self.getQuatPose()
resp = enable_flag
self.running = True
threading.Thread(target=self.update_pose).start()
threading.Thread(target=self.update_gripper).start()
print(f"Returning response: {resp}")
return resp
def getQuatPose(self)->tuple[int,rm_current_arm_state_t]:
state = rm_current_arm_state_t()
ret = rm_get_current_arm_state(self.handle, byref(state))
return numpy.array([
state.pose.position.x,
state.pose.position.y,
state.pose.position.z,
state.pose.quaternion.w,
state.pose.quaternion.x,
state.pose.quaternion.y,
state.pose.quaternion.z,
self.rmarm.rm_get_gripper_state()[1]['actpos']
])
def read_pose(self):
return self.init_pose
def motor_names(self):
return
def read_calibration(self):
return
def set_calibration(self):
return
def revert_calibration(self):
return
def apply_calibration(self):
"""
移动到初始位置
"""
self.write_arm(target_joint=self.init_joint_position)
def write(self, data_name: str, motor: str, value, *, normalize: bool = True, num_retry: int = 0):
return False
def write_arm(self, target_joint: list):
ret = self.rmarm.rm_movej(self.init_joint_position[:-1], 5, 0, 0, 1)
if ret != 0:
print("movej error:", ret)
return ret
ret = self.rmarm.rm_set_gripper_position(target_joint[-1], block=False, timeout=2)
return ret
def read(self) -> Dict:
"""
- 机械臂关节消息,单位1度;[-1, 1]
- 机械臂夹爪消息,[-1, 1]
"""
joint_state = self.read_pose()
return {
"joint_1": joint_state[0]/180,
"joint_2": joint_state[1]/180,
"joint_3": joint_state[2]/180,
"joint_4": joint_state[3]/180,
"joint_5": joint_state[4]/180,
"joint_6": joint_state[5]/180,
"gripper": (joint_state[6]-500)/500
}
5
def disconnect(self, disable_torque = True):
self.safe_disconnect()
def safe_disconnect(self):
"""
Move to safe disconnect position
"""
self.write_arm(target_joint=self.safe_disable_position)
self.running = False
# 断开所有连接,销毁线程
"""
向机械臂写入动作
"""
def sync_write(self,name,actionData: dict[str, Any]):
if name =="Goal_Position":
self.write_arm(target_joint=actionData)
elif name == "Goal_Velocity":#速度透传模式
values = numpy.array(list(actionData.values()))
with self.lock:
self.temp_pose += numpy.array([*values[:6],0,values[-1]])
def update_pose(self):
while self.running:
with self.lock:
self.temp_pose[-1] = self.temp_pose[-1]*1000
temp = self.init_pose + self.temp_pose
newr = R.from_rotvec(self.temp_pose[3:6].tolist())
oldr = R.from_quat(self.init_pose[3:7].tolist())
temp[3:7] = (oldr * newr).as_quat()
self.temp_pose.fill(0)
ret = self.rmarm.rm_movep_canfd(temp[:-1].tolist(), False)
if ret == 0:
self.init_pose = temp
else:
print(f"Error: {ret}")
time.sleep(0.01)
def clamp(self,value, min_value, max_value):
return max(min(value, max_value), min_value)
def update_gripper(self):
while self.running:
if self.init_pose[-1]>0:
self.rmarm.rm_set_gripper_release(500,False,0)
self.init_pose[-1] = 0
elif self.init_pose[-1]<0:
self.rmarm.rm_set_gripper_pick(500,300,False,0)
self.init_pose[-1] = 0
def sync_read(self, data_name, motors = None, *, normalize = True, num_retry = 0):
if data_name == "Present_Position":
return self.read()
@property
def is_connected(self) -> bool:
return self.handle is not None
@property
def is_calibrated(self) -> bool:
return True
def write_calibration(self, calibration_dict, cache = True):
pass
def _get_half_turn_homings(self, positions):
pass
def _find_single_motor(self, motor: str, initial_baudrate: int | None = None) -> tuple[int, int]:
return 0,self.motors[motor].id
def _encode_sign(self, data_name, ids_values):
pass
def _decode_sign(self, data_name, ids_values):
pass
def _split_into_byte_chunks(self, value, length):
pass
def broadcast_ping(self, num_retry = 0, raise_on_error = False):
pass
def _handshake(self) -> None:
pass
def _assert_protocol_is_compatible(self, instruction_name):
return True
"""
配置电机
"""
def configure_motors(self, return_delay_time=0, maximum_acceleration=254, acceleration=254) -> None:
pass
def disable_torque(self, motors: int | str | list[str] | None = None, num_retry: int = 0):
pass
def _disable_torque(self, motor: int, model: str, num_retry: int = 0):
pass
def enable_torque(self, motors = None, num_retry = 0):
pass