添加手眼标定程序
This commit is contained in:
parent
c265e99df3
commit
1d26d00175
@ -54,9 +54,9 @@ class AdmittanceController(BaseController):
|
||||
self.state.pose_error[3:] = -rot_err_quat.as_rotvec(degrees=False)
|
||||
# 期望加速度
|
||||
wrench_err = self.state.external_wrench_tcp - self.state.desired_wrench
|
||||
KD_vel = self.D @ (self.state.arm_desired_twist - self.state.desired_twist)
|
||||
KD_pose = self.K @ self.state.pose_error
|
||||
self.state.arm_desired_acc = self.M_inv @ (wrench_err - KD_vel - KD_pose)
|
||||
D_vel = self.D @ (self.state.arm_desired_twist - self.state.desired_twist)
|
||||
K_pose = self.K @ self.state.pose_error
|
||||
self.state.arm_desired_acc = self.M_inv @ (wrench_err - D_vel - K_pose)
|
||||
self.clip_command(self.state.arm_desired_acc, "acc")
|
||||
## 更新速度和位姿
|
||||
self.state.arm_desired_twist += self.state.arm_desired_acc * dt
|
||||
|
Binary file not shown.
@ -812,32 +812,9 @@ if __name__ == "__main__":
|
||||
sleep(1)
|
||||
dobot.setEndEffector(i=9,tool_i="{0.0,0.0,154.071,0.0,0.0,0.0}")
|
||||
dobot.chooseEndEffector(i=9)
|
||||
# print(dobot.getPose())
|
||||
# print(dobot.get_arm_position())
|
||||
# pos,rot_quat = dobot.get_arm_position()
|
||||
# print("pos",pos)
|
||||
# print("rot_quat",rot_quat)
|
||||
print("Arm pose:",dobot.getPose())
|
||||
|
||||
# while(True):
|
||||
# print("反馈角度",dobot.feedbackData.QActual)
|
||||
# print("反馈四元数",dobot.feedbackData.ActualQuaternion)
|
||||
# print("反馈TCP笛卡尔实际坐标值",dobot.feedbackData.ToolVectorActual)
|
||||
# sleep(0.008)
|
||||
|
||||
dobot.Get_feedInfo_angle()
|
||||
sleep(0.008)
|
||||
dobot.Get_feedInfo_pose()
|
||||
sleep(0.5)
|
||||
|
||||
cur = dobot.Get_feedInfo_angle() # 参考关节角度
|
||||
short_cur = [f"{x:.3f}" for x in cur]
|
||||
|
||||
target = dobot.getInverseKin([250.000045,-134.999537,344.115807,-179.999982,-0.000408,-90.000642],-1,-1,1,"{" + ",".join(map(str, short_cur)) + "}")
|
||||
print(target)
|
||||
# for i in range(400):
|
||||
# posJ[2] += 0.04
|
||||
# dobot.ServoJoint(posJ,t=0.008,aheadtime=20,gain=200)
|
||||
# sleep(0.007)
|
||||
# dobot.RunPoint_P_inPose([, 0, 154.071, 0, 0, 0])
|
||||
|
||||
|
||||
# dobot.start_drag()
|
||||
|
260
Massage/MassageControl/tools/auto_visual_valibration.py
Normal file
260
Massage/MassageControl/tools/auto_visual_valibration.py
Normal file
@ -0,0 +1,260 @@
|
||||
import cv2
|
||||
import os
|
||||
from datetime import datetime
|
||||
import numpy as np
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import time
|
||||
from scipy.spatial.transform import Rotation as R
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parent.parent))
|
||||
sys.path.append('/home/jsfb/jsfb_ws/MassageRobot_aubo/Massage/MassageControl')
|
||||
from hardware.remote_cam import ToolCamera
|
||||
from hardware.aubo_C5 import AuboC5
|
||||
|
||||
np.set_printoptions(precision=8, suppress=True)
|
||||
# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
|
||||
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
|
||||
|
||||
|
||||
# 标定计算类
|
||||
# -- 连接AuboC5
|
||||
# -- 连接 ToolCamera
|
||||
# -- 运动到初始位置 计算下一步运动位姿
|
||||
# -- 开始手眼标定
|
||||
# -- 输出结果
|
||||
class Calibration:
|
||||
def __init__(self, board_size, square_size, file_folder):
|
||||
"""
|
||||
初始化标定计算类。
|
||||
board_size: 标定板的格子数,格式为 (width, height)
|
||||
square_size: 格子的大小,单位为米
|
||||
"""
|
||||
self.board_size = board_size
|
||||
self.square_size = square_size
|
||||
self.file_address = file_folder
|
||||
self.objp = self._create_object_points()
|
||||
self.image_points = []
|
||||
self.robot_poses = []
|
||||
self.cam = ToolCamera(host='127.0.0.1')
|
||||
self.cam.start()
|
||||
self.size = None
|
||||
self.intrinsics_mtx = None
|
||||
self.disorder = None
|
||||
rgb_image, depth_image, camera_intrinsics = self.cam.get_latest_frame()
|
||||
if rgb_image is None :
|
||||
print(f'===============相机连接失败请检查并重试==============')
|
||||
else:
|
||||
print(f'===============相机连接成功==============')
|
||||
self.size = rgb_image.shape[:2]
|
||||
self.intrinsics = camera_intrinsics
|
||||
|
||||
self.arm = AuboC5()
|
||||
self.arm.init()
|
||||
self.obj_points = []
|
||||
print(f'===============机械臂连接成功==============')
|
||||
|
||||
def _create_object_points(self):
|
||||
"""创建标定板的3D点"""
|
||||
objp = np.zeros((self.board_size[0] * self.board_size[1], 3), np.float32)
|
||||
objp[:, :2] = np.mgrid[0:self.board_size[0], 0:self.board_size[1]].T.reshape(-1, 2) * self.square_size
|
||||
return objp
|
||||
|
||||
def collect_data(self):
|
||||
#移动到初始位置
|
||||
pose = [(90) * (np.pi / 180), 4.23 * (np.pi / 180), 124.33 * (np.pi / 180), 61.56 * (np.pi / 180), -89.61 * (np.pi / 180), 0 * (np.pi / 180)]
|
||||
code = self.arm.move_joint(pose,4,wait=True)
|
||||
if code == -1:
|
||||
print("运动到拍照位置失败")
|
||||
#拍照
|
||||
self.check_corners()
|
||||
#运动到下一个位置
|
||||
# 目前只设计了44条轨迹
|
||||
for i in range (0,45):
|
||||
next_pose = self.get_next_pose_ugly(i)
|
||||
self.arm.move_joint(next_pose, 4,wait=True)
|
||||
if code == -1:
|
||||
print("运动到拍照位置失败")
|
||||
else:
|
||||
self.check_corners()
|
||||
|
||||
def check_corners(self):
|
||||
rgb, depth, intrinsics = self.cam.get_latest_frame()
|
||||
gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
|
||||
ret, corners = cv2.findChessboardCorners(gray, self.board_size, None)
|
||||
if ret:
|
||||
robot_pose = self.get_pose_homomat()
|
||||
self.add_sample(gray,corners,robot_pose)
|
||||
print(f"robot_pose = {robot_pose}")
|
||||
|
||||
pic_name = self.file_address + "/"+str(len(self.image_points)) + ".jpg"
|
||||
print(f"save path as: {pic_name}")
|
||||
# 绘制检测到的角点 (用于可视化,可选)
|
||||
cv2.drawChessboardCorners(rgb, self.board_size, corners, ret)
|
||||
cv2.imwrite(pic_name, rgb)
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def add_sample(self, gray, corners,robot_pose):
|
||||
"""
|
||||
添加标定样本。
|
||||
image: 捕获的图像
|
||||
robot_pose: 机械臂的位姿,格式为 [x, y, z, roll, pitch, yaw]
|
||||
"""
|
||||
# 检测棋盘角点
|
||||
|
||||
self.obj_points.append(self.objp)
|
||||
corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria) # 在原角点的基础上寻找亚像素角点
|
||||
if [corners2]:
|
||||
self.image_points.append(corners2)
|
||||
else:
|
||||
self.image_points.append(corners)
|
||||
|
||||
self.robot_poses.append(robot_pose)
|
||||
|
||||
def get_pose_homomat(self):
|
||||
pose = self.arm.robot_rpc_client.getRobotInterface(self.arm.robot_name).getRobotState().getTcpPose()
|
||||
x, y, z, rx, ry, rz = pose
|
||||
r = R.from_euler('xyz', [rx, ry, rz])
|
||||
rotation_matrix = r.as_matrix()
|
||||
translation_vector = np.array([x, y, z]).reshape(3, 1)
|
||||
homo_mat = np.eye(4) # 创建 4x4 单位矩阵
|
||||
homo_mat[:3, :3] = rotation_matrix
|
||||
homo_mat[:3, 3] = translation_vector.flatten()
|
||||
return homo_mat
|
||||
|
||||
def camera_calib(self):
|
||||
# print(f"size is {self.size}")
|
||||
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(self.obj_points, self.image_points, (self.size[1], self.size[0]), None, None)
|
||||
# print("rvecs,tvecs:",rvecs,tvecs)
|
||||
if ret:
|
||||
print("内参矩阵:\n", mtx) # 内参数矩阵
|
||||
print("畸变系数:\n", dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
|
||||
print("++++++++++相机标定完成++++++++++++++")
|
||||
self.intrinsics_mtx = mtx
|
||||
self.disorder = dist
|
||||
else:
|
||||
print("-----------相机标定失败--------------")
|
||||
return rvecs, tvecs
|
||||
|
||||
def split_robot_pose(self):
|
||||
"""
|
||||
将包含 4x4 齐次矩阵的 robot_pose 列表拆分成 R_arm 和 t_arm。
|
||||
Args:
|
||||
robot_pose: 包含 4x4 齐次矩阵的 Python list。
|
||||
Returns:
|
||||
R_arm: 旋转矩阵的 Python list, 每个元素是 3x3 numpy 数组。
|
||||
t_arm: 平移向量的 Python list, 每个元素是 3x1 numpy 数组。
|
||||
"""
|
||||
R_arm = []
|
||||
t_arm = []
|
||||
|
||||
for pose_matrix in self.robot_poses:
|
||||
# # 1. 提取旋转矩阵 (3x3)
|
||||
rotation_matrix = pose_matrix[:3, :3]
|
||||
R_arm.append(rotation_matrix)
|
||||
# R_arm.append(pose_matrix[:3])
|
||||
|
||||
|
||||
# 2. 提取平移向量 (3x1)
|
||||
translation_vector = pose_matrix[:3, 3] # 获取齐次矩阵的平移部分 (1x3 numpy 数组)
|
||||
translation_vector = translation_vector.reshape(3, 1) # 转换为 3x1 的列向量
|
||||
t_arm.append(translation_vector)
|
||||
|
||||
return R_arm, t_arm
|
||||
|
||||
def calibrate(self):
|
||||
rvecs, tvecs = self.camera_calib()
|
||||
r_arm, t_arm= self.split_robot_pose()
|
||||
rvecs_array = np.array(rvecs)
|
||||
tvecs_array = np.array(tvecs)
|
||||
t_arma = np.array(t_arm)
|
||||
r_arma = np.array(r_arm)
|
||||
print(rvecs_array.shape)
|
||||
print(tvecs_array.shape)
|
||||
print(t_arma.shape)
|
||||
print(r_arma.shape)
|
||||
R, t = cv2.calibrateHandEye(r_arma, t_arma, rvecs_array, tvecs_array, cv2.CALIB_HAND_EYE_TSAI)
|
||||
print("+++++++++++手眼标定完成+++++++++++++++")
|
||||
return R, t ,self.intrinsics_mtx
|
||||
|
||||
#得到图片以后 根据pose判断方向:
|
||||
def get_next_pose_future(self):
|
||||
return None
|
||||
def get_next_pose_ugly(self,index):
|
||||
poselist =[
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1267845650875392, -1.5116296651522887, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1791444426473692, -1.4592697875924587, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0220648099678793, -1.5116296651522887, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 0.9697049324080494, -1.4592697875924587, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 0.9173450548482196, -1.4069099100326288, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1267845650875392, -1.6163494202719486, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1791444426473692, -1.6687092978317786, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.2315043202071991, -1.7210691753916085, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.109331272567596, -1.4941763726323454, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1442378576074825, -1.424363202552572, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1791444426473692, -1.3545500324727988, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.2140510276872558, -1.2847368623930255, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.109331272567596, -1.633802712791892, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.1442378576074825, -1.7036158828716652, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0395181024878226, -1.4941763726323454, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.004611517447936, -1.424363202552572, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 0.9697049324080493, -1.3545500324727988, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 0.9347983473681627, -1.2847368623930255, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.5707963267948966, 0.06510078109938851, 2.16996785900455, 1.0395181024878226, -1.4941763726323454, 0.0],
|
||||
[1.5707963267948966, 0.05637413483941686, 2.16996785900455, 1.004611517447936, -1.424363202552572, 0.0],
|
||||
[1.5707963267948966, 0.047647488579445216, 2.16996785900455, 0.9697049324080493, -1.3545500324727988, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.562069680534925, 0.07382742735936015, 2.16996785900455, 1.0395181024878226, -1.4941763726323454, 0.0],
|
||||
[1.5533430342749535, 0.07382742735936015, 2.16996785900455, 1.004611517447936, -1.424363202552572, 0.0],
|
||||
[1.544616388014982, 0.07382742735936015, 2.16996785900455, 0.9697049324080493, -1.3545500324727988, 0.0],
|
||||
[1.5358897417550104, 0.07382742735936015, 2.16996785900455, 0.9347983473681627, -1.2847368623930255, 0.0],
|
||||
[1.5271630954950388, 0.07382742735936015, 2.16996785900455, 0.8998917623282761, -1.2149236923132523, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.579522973054868, 0.07382742735936015, 2.16996785900455, 1.109331272567596, -1.5988961277520053, 0.0],
|
||||
[1.5882496193148397, 0.07382742735936015, 2.16996785900455, 1.1442378576074825, -1.633802712791892, 0.0],
|
||||
[1.5969762655748112, 0.07382742735936015, 2.16996785900455, 1.1791444426473692, -1.6687092978317786, 0.0],
|
||||
[1.6057029118347828, 0.07382742735936015, 2.16996785900455, 1.2140510276872558, -1.7036158828716652, 0.0],
|
||||
[1.6144295580947543, 0.07382742735936015, 2.16996785900455, 1.2489576127271425, -1.7385224679115518, 0.0],
|
||||
[1.5707963267948966, 0.07382742735936015, 2.16996785900455, 1.0744246875277093, -1.5639895427121187, 0.0],
|
||||
[1.579522973054868, 0.07382742735936015, 2.16996785900455, 1.1267845650875392, -1.581442835232062, 0.0],
|
||||
[1.5882496193148397, 0.07382742735936015, 2.16996785900455, 1.1791444426473692, -1.5988961277520053, 0.0],
|
||||
[1.5969762655748112, 0.07382742735936015, 2.16996785900455, 1.2315043202071991, -1.6163494202719486, 0.0],
|
||||
[1.6057029118347828, 0.07382742735936015, 2.16996785900455, 1.283864197767029, -1.633802712791892, 0.0],
|
||||
[1.6144295580947543, 0.07382742735936015, 2.16996785900455, 1.336224075326859, -1.6512560053118353, 0.0]
|
||||
]
|
||||
return poselist[index]
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# 标定板的width 对应的角点的个数 6
|
||||
# 标定板的height 对应的角点的个数 3
|
||||
calibration_board_size = [6,3]
|
||||
calibration_board_square_size = 0.027 #unit - meter
|
||||
systemPath = "/home/jsfb/Documents/"
|
||||
|
||||
now = datetime.now()
|
||||
date_time_str = now.strftime("%d_%H_%M")
|
||||
folder_name = f"calibration_data_{date_time_str}"
|
||||
systemPath+=folder_name
|
||||
os.makedirs(systemPath, exist_ok=True)
|
||||
|
||||
calib = Calibration(calibration_board_size,calibration_board_square_size,systemPath)
|
||||
calib.collect_data()
|
||||
R, t,intrin = calib.calibrate()
|
||||
print("旋转矩阵:")
|
||||
print(R)
|
||||
print("平移向量:")
|
||||
print(t)
|
||||
print(f"内参: {intrin}")
|
550
Massage/MassageControl/tools/full_auto_visual_calibration.py
Normal file
550
Massage/MassageControl/tools/full_auto_visual_calibration.py
Normal file
@ -0,0 +1,550 @@
|
||||
import cv2
|
||||
import os
|
||||
from datetime import datetime
|
||||
import math
|
||||
import numpy as np
|
||||
import sys
|
||||
import random
|
||||
from pathlib import Path
|
||||
import time
|
||||
from scipy.spatial.transform import Rotation as R
|
||||
from scipy.interpolate import CubicSpline
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parent.parent))
|
||||
sys.path.append('/home/jsfb/jsfb_ws/MassageRobot_aubo/Massage/MassageControl')
|
||||
from hardware.remote_cam import ToolCamera
|
||||
from hardware.aubo_C5 import AuboC5
|
||||
|
||||
np.set_printoptions(precision=8, suppress=True)
|
||||
# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
|
||||
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
|
||||
|
||||
|
||||
# 标定计算类
|
||||
# -- 连接AuboC5
|
||||
# -- 连接 ToolCamera
|
||||
# -- 运动到初始位置 计算下一步运动位姿
|
||||
# -- 开始手眼标定
|
||||
# -- 输出结果
|
||||
class Calibration:
|
||||
def __init__(self, board_size, square_size, file_folder):
|
||||
"""
|
||||
初始化标定计算类。
|
||||
board_size: 标定板的格子数,格式为 (width, height)
|
||||
square_size: 格子的大小,单位为米
|
||||
"""
|
||||
self.board_size = board_size
|
||||
self.square_size = square_size
|
||||
self.objp = self._create_object_points()
|
||||
self.image_points = []
|
||||
self.robot_poses = []
|
||||
self.poselist = []
|
||||
self.cam = ToolCamera(host='127.0.0.1')
|
||||
self.cam.start()
|
||||
self.file_address = file_folder
|
||||
rgb_image, depth_image, camera_intrinsics = self.cam.get_latest_frame()
|
||||
cv2.imshow("rgb1",rgb_image)
|
||||
cv2.waitKey(0)
|
||||
if rgb_image is None :
|
||||
print(f'===============相机连接失败请检查并重试==============')
|
||||
else:
|
||||
print(f'===============相机连接成功==============')
|
||||
self.size = rgb_image.shape[:2]
|
||||
self.intrinsics = camera_intrinsics
|
||||
|
||||
self.arm = AuboC5()
|
||||
self.arm.init()
|
||||
self.obj_points = []
|
||||
print(f'===============机械臂连接成功==============')
|
||||
|
||||
def _create_object_points(self):
|
||||
"""创建标定板的3D点"""
|
||||
objp = np.zeros((self.board_size[0] * self.board_size[1], 3), np.float32)
|
||||
objp[:, :2] = np.mgrid[0:self.board_size[0], 0:self.board_size[1]].T.reshape(-1, 2) * self.square_size
|
||||
return objp
|
||||
|
||||
def collect_data(self):
|
||||
#移动到初始位置
|
||||
# move = [(90) * (np.pi / 180), 4.23 * (np.pi / 180), 124.33 * (np.pi / 180), 61.56 * (np.pi / 180), -89.61 * (np.pi / 180), 0 * (np.pi / 180)]
|
||||
move = [(89.74) * (np.pi / 180), 11.21 * (np.pi / 180), 97.12 * (np.pi / 180), 29.06 * (np.pi / 180), -89.61 * (np.pi / 180), 0 * (np.pi / 180)]
|
||||
|
||||
code = self.arm.move_joint(move,4,wait=True)
|
||||
if code == -1:
|
||||
print("运动到拍照位置失败")
|
||||
# time.sleep(3)
|
||||
#拍照
|
||||
rgb, depth, intrinsics = self.cam.get_latest_frame()
|
||||
cv2.imshow("rgb2",rgb)
|
||||
cv2.waitKey(0)
|
||||
|
||||
if self.check_corners_add_sample() is False:
|
||||
print("初始位置下没有找到标定板")
|
||||
rgb, depth, intrinsics = self.cam.get_latest_frame()
|
||||
pose = self.arm.robot_rpc_client.getRobotInterface(self.arm.robot_name).getRobotState().getTcpPose()
|
||||
cv2.imshow("not right",rgb)
|
||||
cv2.waitKey(0)
|
||||
|
||||
|
||||
rgb, depth, intrinsics = self.cam.get_latest_frame()
|
||||
gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
|
||||
ret, corners = cv2.findChessboardCorners(gray, self.board_size, None)
|
||||
robot_pose = self.get_pose_homomat()
|
||||
|
||||
print(f"EE pose:{robot_pose}")
|
||||
|
||||
|
||||
center = self.init_chessboard_center(rgb)
|
||||
print(f"current center EE: {center}")
|
||||
|
||||
|
||||
''' Z轴抖动 '''
|
||||
# EE坐标系下的点
|
||||
trajectory, rpy_values = self.generate_cyclic_trajectory_above_center(center)
|
||||
self.visualization(center,trajectory,rpy_values)
|
||||
homo_trajectory = np.hstack((trajectory, np.ones((len(trajectory), 1))))
|
||||
tcp_pose = self.get_pose_homomat()
|
||||
# 把生成的trajectory 移动到 世界坐标下
|
||||
trajectory = (tcp_pose @ homo_trajectory.T).T[:, :3]
|
||||
rpy_angles = []
|
||||
for tool_point in trajectory:
|
||||
vector_center_to_tool = tool_point - center
|
||||
roll, pitch, yaw = self.get_roll_pitch_yaw(vector_center_to_tool)
|
||||
rpy_angles.append((roll, pitch, yaw))
|
||||
rpy_angles = np.array(rpy_angles)
|
||||
|
||||
pose = self.concatenate_path_and_rpy(trajectory,rpy_angles )
|
||||
|
||||
#世界坐标系下的中心
|
||||
center_homo = np.append(center, 1).reshape(4, 1)
|
||||
tcp_pose = self.get_pose_homomat()
|
||||
center_world_homo = tcp_pose @ center_homo # 4x4 *4x1 =4x1
|
||||
center_world = center_world_homo[:3].flatten()
|
||||
|
||||
print(f"world center: {center_world} \n top pose:\n {pose[:5]}")
|
||||
|
||||
lenOfResult = self.traversal_position_direction(pose)
|
||||
|
||||
''' Z轴抖动 '''
|
||||
|
||||
assert lenOfResult > 20, "没有收集到足够多的数据来完成精确的标定"
|
||||
|
||||
def generate_cyclic_trajectory_above_center(self,center, num_steps=12, x_amplitude=0.12, z_amplitude=0.20, frequency=4, min_z_offset=0.60,step_z=0.01):
|
||||
"""
|
||||
生成所有轨迹点都在中心点上方的周期性波动轨迹。
|
||||
"""
|
||||
trajectory = []
|
||||
rpy_values = []
|
||||
y_constant = center[1]
|
||||
x_values = np.linspace(-x_amplitude, x_amplitude, num_steps)
|
||||
y_values = [center[1]+0.05,center[1]+0.15]
|
||||
# y_values = [center[1]+0.05,center[1]+0.15,center[1]+0.30]
|
||||
# y_values = [center[1]+0.15,center[1]+0.03,center[1]+0.06,center[1]+0.10,center[1]+0.15]
|
||||
# y_values = [center[1],center[1],center[1]]
|
||||
|
||||
|
||||
for i in range(len(y_values)):
|
||||
y = y_values[i]
|
||||
for x in x_values:
|
||||
# 使用绝对值正弦函数确保 Z 始终在 center[2] 之上
|
||||
z = z_amplitude * np.abs(np.sin(frequency * x * np.pi)) + center[2] + min_z_offset + step_z*i
|
||||
|
||||
tool_point = np.array([x + center[0], y, z])
|
||||
|
||||
trajectory.append(tool_point)
|
||||
|
||||
# 计算从中心点射向轨迹点的向量
|
||||
vector_center_to_tool = tool_point - center
|
||||
roll, pitch, yaw = self.get_roll_pitch_yaw(vector_center_to_tool)
|
||||
rpy_values.append((roll, pitch, yaw))
|
||||
|
||||
print(f"above part center:{center}\n {trajectory[:5]}")
|
||||
return np.array(trajectory), np.array(rpy_values)
|
||||
|
||||
def get_roll_pitch_yaw(self,vector):
|
||||
"""
|
||||
计算从原点指向给定向量的 roll, pitch, yaw (弧度).
|
||||
假设 Z 轴向前,Y 轴向上,X 轴向右。
|
||||
"""
|
||||
x, y, z = vector
|
||||
roll = math.atan2(y, z)
|
||||
pitch = math.atan2(-x, math.sqrt(y**2 + z**2))
|
||||
yaw = 0 # 假设指向 tool 的方向没有偏航,或者根据实际需求调整
|
||||
return roll, pitch, yaw
|
||||
|
||||
def concatenate_path_and_rpy(self,path, rpy_angles):
|
||||
"""
|
||||
Concatenates a list of positions [x, y, z] with a corresponding list of RPY angles [roll, pitch, yaw].
|
||||
|
||||
Args:
|
||||
path (list of lists): A list where each inner list contains [x, y, z].
|
||||
rpy_angles (list of lists or tuples): A list where each inner list or tuple contains [roll, pitch, yaw].
|
||||
|
||||
Returns:
|
||||
list of lists: A new list where each inner list is a concatenation of the
|
||||
corresponding position and RPY angles: [x, y, z, roll, pitch, yaw].
|
||||
"""
|
||||
if len(path) != len(rpy_angles):
|
||||
raise ValueError("The lengths of the path and rpy_angles lists must be the same.")
|
||||
|
||||
combined_list = []
|
||||
for i in range(len(path)):
|
||||
position = path[i]
|
||||
orientation = rpy_angles[i]
|
||||
# combined = np.concatenate((position,orientation))
|
||||
combined = np.hstack((position.flatten(), orientation))
|
||||
|
||||
combined_list.append(combined)
|
||||
print(f"combined xyz|rpy :{combined}")
|
||||
|
||||
return combined_list
|
||||
|
||||
def check_corners_add_sample(self):
|
||||
rgb, depth, intrinsics = self.cam.get_latest_frame()
|
||||
gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
|
||||
ret, corners = cv2.findChessboardCorners(gray, self.board_size)
|
||||
pic_name = self.file_address + "/"+str(len(self.image_points)) + ".jpg"
|
||||
|
||||
if ret:
|
||||
robot_pose = self.get_pose_homomat()
|
||||
self.add_sample(gray,corners,robot_pose)
|
||||
|
||||
print(f"save path as: {pic_name}")
|
||||
# 绘制检测到的角点 (用于可视化,可选)
|
||||
# cv2.drawChessboardCorners(rgb, self.board_size, corners, ret)
|
||||
cv2.imwrite(pic_name, rgb)
|
||||
return True
|
||||
|
||||
cv2.imwrite(pic_name, rgb)
|
||||
return False
|
||||
|
||||
def add_sample(self, gray, corners,robot_pose):
|
||||
"""
|
||||
添加标定样本。
|
||||
image: 捕获的图像
|
||||
robot_pose: 机械臂的位姿,格式为 [x, y, z, roll, pitch, yaw]
|
||||
"""
|
||||
# 检测棋盘角点
|
||||
|
||||
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) # 在原角点的基础上寻找亚像素角点
|
||||
# if self._validate_corners(corners2):
|
||||
if [corners2]:
|
||||
self.obj_points.append(self.objp)
|
||||
self.image_points.append(corners2)
|
||||
self.robot_poses.append(robot_pose)
|
||||
print(f"insert {robot_pose}")
|
||||
|
||||
def get_pose_homomat(self):
|
||||
pose = self.arm.robot_rpc_client.getRobotInterface(self.arm.robot_name).getRobotState().getTcpPose()
|
||||
x, y, z, rx, ry, rz = pose
|
||||
r = R.from_euler('xyz', [rx, ry, rz])
|
||||
rotation_matrix = r.as_matrix()
|
||||
translation_vector = np.array([x, y, z]).reshape(3, 1)
|
||||
homo_mat = np.eye(4) # 创建 4x4 单位矩阵
|
||||
homo_mat[:3, :3] = rotation_matrix
|
||||
homo_mat[:3, 3] = translation_vector.flatten()
|
||||
return homo_mat
|
||||
|
||||
def camera_calib(self):
|
||||
|
||||
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(self.obj_points, self.image_points, (self.size[1],self.size[0]) , None, None)
|
||||
if ret:
|
||||
print("内参矩阵:\n", mtx) # 内参数矩阵
|
||||
print("畸变系数:\n", dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
|
||||
print("++++++++++相机标定完成++++++++++++++")
|
||||
else:
|
||||
print("-----------相机标定失败--------------")
|
||||
return rvecs, tvecs
|
||||
|
||||
def split_robot_pose(self):
|
||||
"""
|
||||
将包含 4x4 齐次矩阵的 robot_pose 列表拆分成 R_arm 和 t_arm。
|
||||
Args:
|
||||
robot_pose: 包含 4x4 齐次矩阵的 Python list。
|
||||
Returns:
|
||||
R_arm: 旋转矩阵的 Python list, 每个元素是 3x3 numpy 数组。
|
||||
t_arm: 平移向量的 Python list, 每个元素是 3x1 numpy 数组。
|
||||
"""
|
||||
R_arm = []
|
||||
t_arm = []
|
||||
|
||||
for pose_matrix in self.robot_poses:
|
||||
# 1. 提取旋转矩阵 (3x3)
|
||||
rotation_matrix = pose_matrix[:3, :3]
|
||||
R_arm.append(rotation_matrix)
|
||||
|
||||
# 2. 提取平移向量 (3x1)
|
||||
translation_vector = pose_matrix[:3, 3] # 获取齐次矩阵的平移部分 (1x3 numpy 数组)
|
||||
translation_vector = translation_vector.reshape(3, 1) # 转换为 3x1 的列向量
|
||||
t_arm.append(translation_vector)
|
||||
|
||||
return R_arm, t_arm
|
||||
|
||||
def calibrate(self):
|
||||
rvecs, tvecs = self.camera_calib()
|
||||
r_arm, t_arm= self.split_robot_pose()
|
||||
|
||||
rvecs_array = np.array(rvecs)
|
||||
tvecs_array = np.array(tvecs)
|
||||
t_arma = np.array(t_arm)
|
||||
r_arma = np.array(r_arm)
|
||||
print(rvecs_array.shape)
|
||||
print(tvecs_array.shape)
|
||||
print(t_arma.shape)
|
||||
print(r_arma.shape)
|
||||
R, t = cv2.calibrateHandEye(r_arma, t_arma, rvecs_array, tvecs_array, cv2.CALIB_HAND_EYE_HORAUD)
|
||||
print("+++++++++++手眼标定完成+++++++++++++++")
|
||||
return R, t
|
||||
|
||||
def init_chessboard_center(self,image):
|
||||
'''
|
||||
返回的是EE坐标下的中点
|
||||
'''
|
||||
intrinsics = self.intrinsics
|
||||
# 检测标定板获取初始位置
|
||||
ret, corners = cv2.findChessboardCorners(image, self.board_size)
|
||||
if not ret: raise ValueError("标定板未检测到")
|
||||
|
||||
# 计算标定板中心在相机坐标系中的位置
|
||||
obj_pts = np.array([[i*self.square_size, j*self.square_size, 0] for i in range(self.board_size[0]) for j in range(self.board_size[1])], dtype=np.float32)
|
||||
|
||||
print(intrinsics)
|
||||
camera_matrix = np.array([
|
||||
[intrinsics['fx'], 0, intrinsics['cx']],
|
||||
[0, intrinsics['fy'], intrinsics['cy']],
|
||||
[0, 0, 1]
|
||||
], dtype=np.float32)
|
||||
dist_coeffs = np.array([
|
||||
intrinsics['distortion_coeffs']['k1'],
|
||||
intrinsics['distortion_coeffs']['k2'],
|
||||
intrinsics['distortion_coeffs']['p1'],
|
||||
intrinsics['distortion_coeffs']['p2'],
|
||||
intrinsics['distortion_coeffs']['k3']
|
||||
], dtype=np.float32) # 同样确保数据类型
|
||||
|
||||
print("obj_pts shape:", obj_pts.shape)
|
||||
print("corners shape:", corners.shape)
|
||||
ret, rvec, tvec = cv2.solvePnP(obj_pts, corners, camera_matrix, dist_coeffs)
|
||||
|
||||
# 这里我们假设标定板的初始位置是原点,没有旋转和平移
|
||||
rvec_initial = np.zeros((3, 1), dtype=np.float32) # 初始旋转向量
|
||||
tvec_initial = np.zeros((3, 1), dtype=np.float32) # 初始平移向量
|
||||
|
||||
# 初始变换(标定板到初始坐标系)
|
||||
initial_transform = np.eye(4)
|
||||
initial_transform[:3, :3], _ = cv2.Rodrigues(rvec_initial)
|
||||
initial_transform[:3, 3] = tvec_initial.flatten()
|
||||
print(f"board itselt {initial_transform}")
|
||||
# PnP 结果(初始坐标系到相机)
|
||||
cam2initial = np.eye(4)
|
||||
cam2initial[:3, :3], _ = cv2.Rodrigues(rvec)
|
||||
cam2initial[:3, 3] = tvec.flatten()
|
||||
|
||||
# 合成最终变换:标定板 -> 初始坐标系 -> 相机
|
||||
board2cam = initial_transform @ cam2initial
|
||||
print(f"board2cam\n{board2cam}")
|
||||
# 手眼标定矩阵的逆(相机到TCP的固定变换)
|
||||
cam2tool = np.eye(4)
|
||||
cam2tool[:3, :3] = np.array([[0.0, 1.0 , 0.0],
|
||||
[1.0 , 0.0 , 0.0],
|
||||
[0.0, 0.0 , -1.0]])
|
||||
cam2tool[:3, 3] = np.array([0.00209053, 0.01021561, -0.16877656]).flatten()
|
||||
|
||||
###找到棋盘格中心
|
||||
camera_center = None
|
||||
chessboard_center_object = self.get_chessboard_center_object_points()
|
||||
if chessboard_center_object is not None:
|
||||
# Convert to homogeneous coordinates
|
||||
chessboard_center_homogeneous = np.append(chessboard_center_object, 1)
|
||||
|
||||
# Transform the center to camera coordinates
|
||||
camera_center_homogeneous = cam2tool@ board2cam @ chessboard_center_homogeneous
|
||||
camera_center = camera_center_homogeneous[:3]
|
||||
|
||||
return camera_center
|
||||
|
||||
def get_chessboard_center_object_points(self):
|
||||
rows, cols = self.board_size
|
||||
obj_pts = self.objp
|
||||
if obj_pts is None or len(obj_pts) != rows * cols:
|
||||
return None
|
||||
|
||||
# Get the range of x and y indices
|
||||
x_indices = obj_pts[:, 0].flatten()
|
||||
y_indices = obj_pts[:, 1].flatten()
|
||||
|
||||
center_x_index = (np.max(x_indices) + np.min(x_indices)) / 2.0
|
||||
center_y_index = (np.max(y_indices) + np.min(y_indices)) / 2.0
|
||||
center_z = 0 # Assuming the chessboard is on the Z=0 plane in its frame
|
||||
|
||||
return np.array([center_x_index, center_y_index, center_z])
|
||||
|
||||
def generate_perturbed_joint_angles_rad(self,original_angle):
|
||||
"""
|
||||
Args:
|
||||
original_angle (list or tuple): 包含6个角度值的列表或元组 (单位:度).
|
||||
|
||||
Returns:
|
||||
numpy.ndarray: 一个形状为 (6, 6) 的 numpy 数组,包含6组6个角度值(单位:弧度)。
|
||||
每组数据的含义如下:
|
||||
- 第1组: 原始角度(转换为弧度)。
|
||||
- 第2组: 第五个关节角度 + rand5(转换为弧度)。
|
||||
- 第3组: 第五个关节角度 - rand5(转换为弧度)。
|
||||
- 第4组: 第四个关节角度 + rand4(转换为弧度)。
|
||||
- 第5组: 第四个关节角度 - rand4(转换为弧度)。
|
||||
- 第6组: 第四个关节角度 + rand4,第五个关节角度 + rand5(转换为弧度)。
|
||||
"""
|
||||
original_angle = np.array(original_angle)
|
||||
if original_angle.shape != (6,):
|
||||
raise ValueError("输入的角度列表必须包含6个元素。")
|
||||
original_angle[5] = 0.0
|
||||
|
||||
# 生成随机数
|
||||
rand5 = random.uniform(-20*np.pi/180, 20*np.pi/180) # 第五个关节的随机数,范围可以调整
|
||||
rand4 = random.uniform(-10*np.pi/180, 10*np.pi/180) # 第四个关节的随机数,范围可以调整
|
||||
|
||||
|
||||
angle_array = []
|
||||
|
||||
# 1. 原始角度
|
||||
angle_array.append(original_angle.copy())
|
||||
# 4. += rand4
|
||||
angle_c = original_angle.copy()
|
||||
angle_c[3] -= rand4
|
||||
angle_c[4] -= rand5
|
||||
angle_array.append(angle_c)
|
||||
|
||||
# 5. -= rand4
|
||||
angle_d = original_angle.copy()
|
||||
angle_d[3] += rand4
|
||||
angle_d[4] += rand5
|
||||
angle_array.append(angle_d)
|
||||
|
||||
# 6. +=rand4,-= rand5
|
||||
angle_e = original_angle.copy()
|
||||
angle_e[3] += rand4
|
||||
angle_e[4] -= rand5
|
||||
angle_array.append(angle_e)
|
||||
|
||||
# 6. -= rand4,第五个关节 += rand5
|
||||
angle_f = original_angle.copy()
|
||||
angle_f[3] -= rand4
|
||||
angle_f[4] += rand5
|
||||
angle_array.append(angle_f)
|
||||
|
||||
# 6. -= rand4,第五个关节 += rand5
|
||||
angle_g = original_angle.copy()
|
||||
angle_g[3] -= rand4/2
|
||||
angle_g[4] += rand5/2
|
||||
angle_array.append(angle_g)
|
||||
|
||||
angle_h = original_angle.copy()
|
||||
angle_h[3] += rand4/2
|
||||
angle_h[4] -= rand5/2
|
||||
angle_array.append(angle_h)
|
||||
|
||||
# 将所有角度从度转换为弧度
|
||||
# modified_angles_rad = np.array([np.deg2rad(angles) for angles in angle_array])
|
||||
# import pdb
|
||||
# pdb.set_trace()
|
||||
|
||||
return angle_array
|
||||
|
||||
def traversal_position_direction(self,path):
|
||||
|
||||
for pose in path:
|
||||
current_pose = self.arm.robot_rpc_client.getRobotInterface(self.arm.robot_name).getRobotState().getTcpPose()
|
||||
print(f" elipse path is {pose}\n current pose is {current_pose}" )
|
||||
code = self.arm.move_line( pose )
|
||||
|
||||
if code == -1:
|
||||
print(f"运动到拍照位置失败:{pose}")
|
||||
else:
|
||||
joint = self.arm.robot_rpc_client.getRobotInterface(self.arm.robot_name).getRobotState().getJointPositions()
|
||||
angle_list = self.generate_perturbed_joint_angles_rad(joint)
|
||||
print(f"\n {angle_list}\n Angles Position ")
|
||||
for joint in angle_list:
|
||||
print(f"current joint: {joint}")
|
||||
code = self.arm.move_joint(joint,4,wait=True)
|
||||
if code != -1:
|
||||
print(f"move success")
|
||||
self.check_corners_add_sample()
|
||||
|
||||
return len(self.robot_poses)
|
||||
|
||||
def visualization(self,center,trajectory,rpy_values):
|
||||
# 可视化
|
||||
fig = plt.figure(figsize=(10, 8))
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
# 绘制中心点
|
||||
ax.scatter(*center, color='r', marker='o', s=100, label='Center Point')
|
||||
|
||||
# 绘制轨迹
|
||||
ax.plot(trajectory[:, 0], trajectory[:, 1], trajectory[:, 2], color='b', label='Tool Trajectory')
|
||||
|
||||
# 可视化 RPY 值 (每隔几个点显示一个)
|
||||
num_samples_rpy = 20
|
||||
indices = np.linspace(0, len(rpy_values) - 1, num_samples_rpy, dtype=int)
|
||||
for i in indices:
|
||||
tool_point = trajectory[i]
|
||||
roll, pitch, yaw = rpy_values[i]
|
||||
vector = tool_point - center
|
||||
# 将箭头的起始点移动到 tool_point
|
||||
ax.quiver(tool_point[0], tool_point[1], tool_point[2],
|
||||
vector[0], vector[1], vector[2],
|
||||
length=0.2, color='g', alpha=0.7, label='Vector Center to Tool' if i == indices[0] else "")
|
||||
# 将文本标签的位置移动到 tool_point 附近
|
||||
ax.text(tool_point[0] + 0.05, tool_point[1] + 0.05, tool_point[2] + 0.05,
|
||||
f'RPY:({math.degrees(roll):.2f},{math.degrees(pitch):.2f},{math.degrees(yaw):.2f})',
|
||||
color='g', fontsize=8)
|
||||
|
||||
ax.set_xlabel('X')
|
||||
ax.set_ylabel('Y')
|
||||
ax.set_zlabel('Z')
|
||||
ax.set_title('Cyclic Trajectory Above Center Point')
|
||||
ax.legend()
|
||||
ax.view_init(azim=-120, elev=30)
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
|
||||
# 打印 RPY 值 (示例)
|
||||
# print("\nRoll, Pitch, Yaw values (degrees) along the trajectory:")
|
||||
# for i, (r, p, y) in enumerate(rpy_values):
|
||||
# if i % 10 == 0: # Print every 10th value
|
||||
# print(f"Step {i}: Roll: {math.degrees(r):.2f}, Pitch: {math.degrees(p):.2f}, Yaw: {math.degrees(y):.2f}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# 标定板的width 对应的角点的个数 6
|
||||
# 标定板的height 对应的角点的个数 3
|
||||
calibration_board_size = [9,6]
|
||||
calibration_board_square_size = 0.020 #unit - meter
|
||||
systemPath = "/home/jsfb/Documents/"
|
||||
|
||||
now = datetime.now()
|
||||
date_time_str = now.strftime("%d_%H_%M")
|
||||
folder_name = f"calibration_data_{date_time_str}"
|
||||
systemPath+=folder_name
|
||||
os.makedirs(systemPath, exist_ok=True)
|
||||
|
||||
calib = Calibration(calibration_board_size,calibration_board_square_size,systemPath)
|
||||
calib.collect_data()
|
||||
r, t = calib.calibrate()
|
||||
print("旋转矩阵:")
|
||||
print(r)
|
||||
print("平移向量:")
|
||||
print(t)
|
||||
|
||||
|
||||
|
||||
# arm = AuboC5()
|
||||
# arm.init()
|
||||
# aubo_algorithm = arm.robot_rpc_client.getRobotInterface(arm.robot_name).getRobotAlgorithm().inverseKinematics()
|
||||
|
||||
# # 查看 rpc_client 对象的所有属性和方法
|
||||
# print(dir(aubo_algorithm))
|
||||
|
@ -0,0 +1,84 @@
|
||||
2025-05-26 15:02:07,413 - 测试日志 - INFO - log.py:106 - 切换到finger_head按摩头
|
||||
2025-05-26 15:02:10,922 - 测试日志 - INFO - log.py:106 - 机械臂测量线程启动
|
||||
2025-05-26 15:02:10,923 - 测试日志 - INFO - log.py:106 - position command: [ 0.25000011 -0.13499942 0.3442838 ]
|
||||
2025-05-26 15:02:10,925 - 测试日志 - INFO - log.py:106 - orientation command: [ 1.79999939e+02 1.09863257e-04 -9.00000000e+01]
|
||||
2025-05-26 15:02:10,927 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000011 -0.13499942 0.3443389 ]
|
||||
2025-05-26 15:02:10,928 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159159e+00 1.91747555e-06 -1.57079633e+00]
|
||||
2025-05-26 15:02:10,929 - 测试日志 - INFO - log.py:106 - position command: [ 0.25000011 -0.13499942 0.34423872]
|
||||
2025-05-26 15:02:10,930 - 测试日志 - INFO - log.py:106 - orientation command: [ 1.79999939e+02 1.09626792e-04 -9.00001567e+01]
|
||||
2025-05-26 15:02:10,931 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999965 -0.13499989 0.3443392 ]
|
||||
2025-05-26 15:02:10,932 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159265e+00 1.43810701e-06 -1.57079872e+00]
|
||||
2025-05-26 15:02:10,947 - 测试日志 - INFO - log.py:106 - position command: [ 0.24999248 -0.13499964 0.3442024 ]
|
||||
2025-05-26 15:02:10,948 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79998049e+02 5.63537890e-05 -9.00001768e+01]
|
||||
2025-05-26 15:02:10,949 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000008 -0.13499965 0.34433948]
|
||||
2025-05-26 15:02:10,951 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159159e+00 9.58738475e-07 -1.57079633e+00]
|
||||
2025-05-26 15:02:10,965 - 测试日志 - INFO - log.py:106 - position command: [ 0.24998647 -0.13499941 0.34417218]
|
||||
2025-05-26 15:02:10,966 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79996532e+02 1.10826636e-04 -9.00001933e+01]
|
||||
2025-05-26 15:02:10,967 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000006 -0.13499954 0.34433917]
|
||||
2025-05-26 15:02:10,968 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.91747644e-06 -1.57079726e+00]
|
||||
2025-05-26 15:02:10,984 - 测试日志 - INFO - log.py:106 - position command: [ 0.24997959 -0.13499632 0.34414674]
|
||||
2025-05-26 15:02:10,985 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79995110e+02 -7.71629391e-04 -9.00002723e+01]
|
||||
2025-05-26 15:02:10,988 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999971 -0.13499977 0.34433887]
|
||||
2025-05-26 15:02:10,990 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159159e+00 9.58737078e-07 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,003 - 测试日志 - INFO - log.py:106 - position command: [ 0.24997405 -0.1349941 0.34412699]
|
||||
2025-05-26 15:02:11,004 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79993630e+02 -1.21707493e-03 -9.00001773e+01]
|
||||
2025-05-26 15:02:11,005 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999979 -0.13499953 0.34433914]
|
||||
2025-05-26 15:02:11,010 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.43810727e-06 -1.57079633e+00]
|
||||
2025-05-26 15:02:11,022 - 测试日志 - INFO - log.py:106 - position command: [ 0.24996921 -0.13499329 0.34411049]
|
||||
2025-05-26 15:02:11,023 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79992392e+02 -1.41061365e-03 -9.00001617e+01]
|
||||
2025-05-26 15:02:11,027 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999976 -0.13499954 0.34433859]
|
||||
2025-05-26 15:02:11,028 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159132e+00 1.91747466e-06 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,040 - 测试日志 - INFO - log.py:106 - position command: [ 0.24996431 -0.13499314 0.344097 ]
|
||||
2025-05-26 15:02:11,042 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79991336e+02 -1.42291447e-03 -9.00001738e+01]
|
||||
2025-05-26 15:02:11,044 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000012 -0.13499965 0.34433951]
|
||||
2025-05-26 15:02:11,044 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159132e+00 1.43810905e-06 -1.57079779e+00]
|
||||
2025-05-26 15:02:11,059 - 测试日志 - INFO - log.py:106 - position command: [ 0.24996024 -0.13499153 0.34408569]
|
||||
2025-05-26 15:02:11,060 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79990418e+02 -1.83792583e-03 -9.00001532e+01]
|
||||
2025-05-26 15:02:11,061 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000006 -0.13499954 0.34433936]
|
||||
2025-05-26 15:02:11,062 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.91747644e-06 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,077 - 测试日志 - INFO - log.py:106 - position command: [ 0.24995717 -0.13499 0.34407685]
|
||||
2025-05-26 15:02:11,078 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79989529e+02 -2.20403839e-03 -9.00001363e+01]
|
||||
2025-05-26 15:02:11,079 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000012 -0.13499953 0.34433917]
|
||||
2025-05-26 15:02:11,080 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.43810740e-06 -1.57079686e+00]
|
||||
2025-05-26 15:02:11,094 - 测试日志 - INFO - log.py:106 - position command: [ 0.249954 -0.13498974 0.34406968]
|
||||
2025-05-26 15:02:11,095 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79988802e+02 -2.26643396e-03 -9.00001428e+01]
|
||||
2025-05-26 15:02:11,098 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999983 -0.13499965 0.34433942]
|
||||
2025-05-26 15:02:11,099 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.91747619e-06 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,112 - 测试日志 - INFO - log.py:106 - position command: [ 0.2499512 -0.13498704 0.34406287]
|
||||
2025-05-26 15:02:11,114 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79988304e+02 -2.84823642e-03 -9.00001578e+01]
|
||||
2025-05-26 15:02:11,115 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999988 -0.13499977 0.34433896]
|
||||
2025-05-26 15:02:11,118 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159265e+00 1.43810701e-06 -1.57079819e+00]
|
||||
2025-05-26 15:02:11,130 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994961 -0.13498602 0.34405822]
|
||||
2025-05-26 15:02:11,131 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79987684e+02 -3.11853240e-03 -9.00000925e+01]
|
||||
2025-05-26 15:02:11,132 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999988 -0.13499989 0.34433929]
|
||||
2025-05-26 15:02:11,133 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159265e+00 9.58737967e-07 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,149 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994811 -0.13498334 0.34405508]
|
||||
2025-05-26 15:02:11,150 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79987145e+02 -3.78674921e-03 -9.00001559e+01]
|
||||
2025-05-26 15:02:11,150 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000006 -0.13499989 0.34433951]
|
||||
2025-05-26 15:02:11,151 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159132e+00 9.58739364e-07 -1.57079779e+00]
|
||||
2025-05-26 15:02:11,168 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994679 -0.13498323 0.3440513 ]
|
||||
2025-05-26 15:02:11,171 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79986832e+02 -3.73867209e-03 -9.00000707e+01]
|
||||
2025-05-26 15:02:11,173 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999988 -0.13499989 0.34433929]
|
||||
2025-05-26 15:02:11,175 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159159e+00 1.43810841e-06 -1.57079872e+00]
|
||||
2025-05-26 15:02:11,189 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994505 -0.1349838 0.3440481 ]
|
||||
2025-05-26 15:02:11,190 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79986625e+02 -3.72589441e-03 -9.00001151e+01]
|
||||
2025-05-26 15:02:11,192 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999983 -0.13499965 0.34433942]
|
||||
2025-05-26 15:02:11,193 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 1.91747670e-06 -1.57079819e+00]
|
||||
2025-05-26 15:02:11,204 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994443 -0.1349842 0.34404624]
|
||||
2025-05-26 15:02:11,208 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79986397e+02 -3.43709370e-03 -9.00001074e+01]
|
||||
2025-05-26 15:02:11,209 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999983 -0.13499965 0.34433908]
|
||||
2025-05-26 15:02:11,211 - 测试日志 - INFO - log.py:106 - orientation current: [ 3.14159212e+00 1.43810651e-06 -1.57079726e+00]
|
||||
2025-05-26 15:02:11,223 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994332 -0.13498559 0.34404457]
|
||||
2025-05-26 15:02:11,226 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79986153e+02 -3.16623999e-03 -9.00001230e+01]
|
||||
2025-05-26 15:02:11,228 - 测试日志 - INFO - log.py:106 - position current:[ 0.24999966 -0.13499989 0.34433914]
|
||||
2025-05-26 15:02:11,228 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159212e+00 9.58738475e-07 -1.57079779e+00]
|
||||
2025-05-26 15:02:11,242 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994286 -0.13498704 0.34404302]
|
||||
2025-05-26 15:02:11,242 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79986006e+02 -2.85488773e-03 -9.00000897e+01]
|
||||
2025-05-26 15:02:11,243 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000018 -0.13499977 0.34433942]
|
||||
2025-05-26 15:02:11,244 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159159e+00 9.58738475e-07 -1.57079686e+00]
|
||||
2025-05-26 15:02:11,259 - 测试日志 - INFO - log.py:106 - position command: [ 0.24994203 -0.13498865 0.34404123]
|
||||
2025-05-26 15:02:11,260 - 测试日志 - INFO - log.py:106 - orientation command: [-1.79985975e+02 -2.50918022e-03 -9.00001638e+01]
|
||||
2025-05-26 15:02:11,261 - 测试日志 - INFO - log.py:106 - position current:[ 0.25000014 -0.13499953 0.34433948]
|
||||
2025-05-26 15:02:11,262 - 测试日志 - INFO - log.py:106 - orientation current: [-3.14159159e+00 9.58738920e-07 -1.57079633e+00]
|
||||
2025-05-26 15:02:11,277 - 测试日志 - INFO - log.py:106 - MassageRobot启动
|
||||
2025-05-26 15:02:11,277 - 测试日志 - INFO - log.py:106 - 机械臂控制线程启动
|
Loading…
x
Reference in New Issue
Block a user