Files
lerobot_piper/piper_scripts/piper_demo_endpose.py
2025-05-07 11:29:56 +08:00

300 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*-coding:utf8-*-
# 注意demo无法直接运行需要pip安装sdk后才能运行
from typing import (
Optional,
)
import time
from piper_sdk import *
import pygame
import threading
import time
from typing import Dict
def enable_fun(piper:C_PiperInterface_V2):
'''
使能机械臂并检测使能状态,尝试5s,如果使能超时则退出程序
'''
enable_flag = False
# 设置超时时间(秒)
timeout = 5
# 记录进入循环前的时间
start_time = time.time()
elapsed_time_flag = False
while not (enable_flag):
elapsed_time = time.time() - start_time
print("--------------------")
enable_flag = piper.GetArmLowSpdInfoMsgs().motor_1.foc_status.driver_enable_status and \
piper.GetArmLowSpdInfoMsgs().motor_2.foc_status.driver_enable_status and \
piper.GetArmLowSpdInfoMsgs().motor_3.foc_status.driver_enable_status and \
piper.GetArmLowSpdInfoMsgs().motor_4.foc_status.driver_enable_status and \
piper.GetArmLowSpdInfoMsgs().motor_5.foc_status.driver_enable_status and \
piper.GetArmLowSpdInfoMsgs().motor_6.foc_status.driver_enable_status
print("使能状态:",enable_flag)
piper.EnableArm(7)
piper.GripperCtrl(0,1000,0x01, 0)
print("--------------------")
# 检查是否超过超时时间
if elapsed_time > timeout:
print("超时....")
elapsed_time_flag = True
enable_flag = True
break
time.sleep(1)
pass
if(elapsed_time_flag):
print("程序自动使能超时,退出程序")
exit(0)
class EndPoseController:
def __init__(self):
pygame.init()
pygame.joystick.init()
if pygame.joystick.get_count() == 0:
raise Exception("未检测到手柄")
self.joystick = pygame.joystick.Joystick(0)
self.joystick.init()
# 末端初始姿态 [X, Y, Z, RX, RY, RZ]
# {'X': 56127, 'Y': 0, 'Z': 213266, 'RX': 0, 'RY': 84999, 'RZ': 0, 'gripper': -70} # 右臂
self.pose = [0.056127, 0, 0.213266, 0, 84.999, 0]
self.speeds = [0.0] * 6
# 夹爪状态和速度
self.gripper = 0.0
self.gripper_speed = 0.0
# 末端位姿限制
self.pose_limits = [
(-0.6, 0.6), # X (m)
(-0.6, 0.6), # Y (m)
(0.05, 0.6), # Z (m) - 设置最小高度防止碰撞
(-180, 180), # RX (deg)
(-180, 180), # RY (deg)
(-180, 180) # RZ (deg)
]
# 控制参数
self.linear_step = 0.003 # 线性移动步长(m),降低以提高精度
self.angular_step = 0.1 # 角度步长(deg),提高以便更好控制
# 摇杆死区
self.deadzone = 0.15
# 控制模式
self.fine_control_mode = False # 精细控制模式
self.running = True
self.thread = threading.Thread(target=self.update_pose)
self.thread.start()
print("末端位姿控制器已启动")
print("使用方向键上下左右控制XY右摇杆控制Z")
print("L1/R1控制RX△/□控制RY右摇杆Y轴控制RZ")
print("按下L3(左摇杆按下)切换精细/普通控制模式")
def update_pose(self):
while self.running:
try:
pygame.event.pump()
except Exception as e:
print(f"控制器错误: {e}")
self.stop()
continue
# 检查精细控制模式切换
if self.joystick.get_button(10): # L3按钮
self.fine_control_mode = not self.fine_control_mode
print(f"切换到{'精细' if self.fine_control_mode else '普通'}控制模式")
time.sleep(0.3) # 防止多次触发
# 根据控制模式调整步长
current_linear_step = self.linear_step * (0.1 if self.fine_control_mode else 1.0)
current_angular_step = self.angular_step * (0.1 if self.fine_control_mode else 1.0)
# 方向键控制XY
hat = self.joystick.get_hat(0)
hat_up = hat[1] == 1 # Y+
hat_down = hat[1] == -1 # Y-
hat_left = hat[0] == -1 # X-
hat_right = hat[0] == 1 # X+
# 右摇杆控制Z和RZ
right_y = -self.joystick.get_axis(4) # Z控制取反使向上为正
left_y = -self.joystick.get_axis(1) # RZ控制取反使向上为正
# 应用死区
right_y = 0.0 if abs(right_y) < self.deadzone else right_y
left_y = 0.0 if abs(left_y) < self.deadzone else left_y
# 设置XY速度方向键控制
# self.speeds[0] = current_linear_step if hat_right else (-current_linear_step if hat_left else 0.0) # X
# self.speeds[1] = current_linear_step if hat_up else (-current_linear_step if hat_down else 0.0) # Y
self.speeds[0] = current_linear_step if hat_up else (-current_linear_step if hat_down else 0.0) # X
self.speeds[1] = current_linear_step if hat_left else (-current_linear_step if hat_right else 0.0) # Y
# 设置Z速度右摇杆Y轴控制
self.speeds[2] = self._apply_nonlinear_mapping(right_y) * current_linear_step # Z
# L1/R1控制RX旋转
LB = self.joystick.get_button(4) # RX-
RB = self.joystick.get_button(5) # RX+
self.speeds[3] = (-current_angular_step if LB else (current_angular_step if RB else 0.0))
# △/□控制RY旋转
triangle = self.joystick.get_button(2) # RY+
square = self.joystick.get_button(3) # RY-
self.speeds[4] = (current_angular_step if triangle else (-current_angular_step if square else 0.0))
# 左摇杆Y轴控制RZ旋转
self.speeds[5] = self._apply_nonlinear_mapping(left_y) * current_angular_step * 2 # RZ增加系数使旋转更明显
# 夹爪控制(圈/叉)
circle = self.joystick.get_button(1) # 夹爪开
cross = self.joystick.get_button(0) # 夹爪关
self.gripper_speed = 0.01 if circle else (-0.01 if cross else 0.0)
# 更新末端位姿
for i in range(6):
self.pose[i] += self.speeds[i]
# 位置限制
for i in range(3):
min_val, max_val = self.pose_limits[i]
self.pose[i] = max(min_val, min(max_val, self.pose[i]))
# 角度归一化处理
for i in range(3, 6):
self.pose[i] = self._normalize_angle(self.pose[i])
# 更新夹爪
self.gripper += self.gripper_speed
self.gripper = max(0.0, min(0.08, self.gripper))
time.sleep(0.02)
def _normalize_angle(self, angle):
"""将角度归一化到[-180, 180]范围内"""
while angle > 180:
angle -= 360
while angle < -180:
angle += 360
return angle
def _apply_nonlinear_mapping(self, value):
"""应用非线性映射以提高控制精度"""
# 保持符号,但对数值应用平方映射以提高精度
sign = 1 if value >= 0 else -1
return sign * (abs(value) ** 2)
def get_action(self) -> Dict:
"""获取当前末端位姿和夹爪状态"""
return {
'X': self.pose[0]*1000,
'Y': self.pose[1]*1000,
'Z': self.pose[2]*1000,
'RX': self.pose[3],
'RY': self.pose[4],
'RZ': self.pose[5],
'gripper': self.gripper*1000
}
def stop(self):
"""停止控制器"""
self.running = False
if self.thread.is_alive():
self.thread.join()
pygame.quit()
print("末端位姿控制器已退出")
def reset(self):
"""重置到初始位姿"""
self.pose = [0.056127, 0, 0.213266, 0, 84.999, 0] # 使用您提供的初始位姿
self.speeds = [0.0] * 6
self.gripper = 0.0
self.gripper_speed = 0.0
print("已重置到初始位姿")
if __name__ == "__main__":
piper = C_PiperInterface_V2("can0")
piper.ConnectPort()
piper.EnableArm(7)
enable_fun(piper=piper)
piper.GripperCtrl(0,1000,0x01, 0)
factor = 1000
position = [
55.0, \
0.0, \
206.0, \
0, \
85.0, \
0, \
0]
# position = [0.0, \
# 0.0, \
# 80.0, \
# 0, \
# 203.386, \
# 0, \
# 0.8]
count = 0
teleop = EndPoseController()
while True:
print(piper.GetArmEndPoseMsgs())
# print(piper.GetArmStatus())
import time
# count = count + 1
# # print(count)
# if(count == 0):
# print("1-----------")
# position = [
# 55.0, \
# 0.0, \
# 206.0, \
# 0, \
# 85.0, \
# 0, \
# 0]
# elif(count == 200):
# print("2-----------")
# position = [
# 55.0, \
# 0.0, \
# 260.0, \
# 0, \
# 85.0, \
# 0, \
# 0]
# elif(count == 400):
# print("1-----------")
# position = [
# 55.0, \
# 0.0, \
# 280.0, \
# 0, \
# 85.0, \
# 0, \
# 0]
# count = 0
position = teleop.get_action()
position = list(position.values())
X = round(position[0]*factor)
Y = round(position[1]*factor)
Z = round(position[2]*factor)
RX = round(position[3]*factor)
RY = round(position[4]*factor)
RZ = round(position[5]*factor)
joint_6 = round(position[6]*factor)
print(X,Y,Z,RX,RY,RZ, joint_6)
# piper.MotionCtrl_1()
piper.MotionCtrl_2(0x01, 0x00, 100, 0x00)
piper.EndPoseCtrl(X,Y,Z,RX,RY,RZ)
piper.GripperCtrl(abs(joint_6), 1000, 0x01, 0)
time.sleep(0.1)
pass