cmvr-es/python/hand_eye_calibration/compute_in_hand.py
2025-08-21 13:56:39 +08:00

140 lines
4.5 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.

# coding=utf-8
"""
眼在手上:使用采集的图片信息和机械臂位姿信息计算
相机坐标系相对于机械臂末端坐标系的旋转矩阵和平移向量
"""
import os
import logging
import yaml
import cv2
import numpy as np
from scipy.spatial.transform import Rotation as R
np.set_printoptions(precision=8, suppress=True)
current_path = os.path.dirname(os.path.abspath(__file__))
images_path = os.path.join(current_path, "data/20250804-1331")
# 加载标定板参数
with open("./config/config.yaml", 'r', encoding='utf-8') as file:
data = yaml.safe_load(file)
XX = data.get("checkerboard_args").get("XX")
YY = data.get("checkerboard_args").get("YY")
L = data.get("checkerboard_args").get("L")
def gen_T_txt():
joint_record_file = os.path.join(images_path, "joints_record.txt")
with open(joint_record_file, "r") as f:
lines = f.readlines()
for line in lines:
temp = line.replace("\n", "").split(" ")
index = temp[0]
joints = temp[2:]
cmd = " ".join(["fk_example", "right"] + joints) + f" -o ./temp/T_ee_{index}.txt"
print(cmd)
os.system(cmd)
print("gen_T_txt finished")
def load_robot_poses_from_fk(folder):
"""
从fk_example输出的多个T_ee_{index}.txt文件构建RobotToolPose矩阵
输出: 3x(4*N) numpy矩阵
"""
files = [f for f in os.listdir(folder) if f.startswith("T_ee_") and f.endswith(".txt")]
if not files:
raise RuntimeError("未找到任何 T_ee_xxx.txt 文件")
# 根据index排序
files.sort(key=lambda x: int(x.split('_')[-1].split('.')[0]))
poses = []
for fname in files:
path = os.path.join(folder, fname)
data = np.loadtxt(path, delimiter=',')
if data.shape != (12,):
raise RuntimeError(f"{fname} 格式错误期望12个值(r11,r12,r13,tx,...,tz)")
# 3x4矩阵
mat = data.reshape(3, 4)
poses.append(mat)
# 拼接成 3x(4*N)
robot_pose_matrix = np.hstack(poses)
out_path = os.path.join(folder, "../RobotToolPose.csv")
np.savetxt(out_path, robot_pose_matrix, delimiter=',', fmt='%.8f')
print(f"RobotToolPose.csv 已生成: {out_path}")
return out_path
def func():
path = os.path.dirname(__file__)
# 设置寻找亚像素角点的参数
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
# 获取标定板角点的位置
objp = np.zeros((XX * YY, 3), np.float32)
objp[:, :2] = np.mgrid[0:XX, 0:YY].T.reshape(-1, 2)
objp = L * objp
obj_points = [] # 存储3D点
img_points = [] # 存储2D点
images_num = [f for f in os.listdir(images_path) if f.endswith('.png')]
for i in range(1, len(images_num) + 1):
image_file = os.path.join(images_path, f"img_{i}.png")
if os.path.exists(image_file):
print(f'{image_file}')
img = cv2.imread(image_file)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, (XX, YY), None)
if ret:
cv2.drawChessboardCorners(img, (XX, YY), corners, ret)
# 显示图像窗口
save_path = os.path.join(current_path, "temp", f"res_{i}.jpg")
cv2.imwrite(save_path, img)
obj_points.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)
img_points.append(corners2 if corners2 is not None else corners)
N = len(img_points)
# 标定得到图案在相机坐标系下的位姿
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)
print("-----------------------------------------------------")
# === 新增读取fk_example结果构建RobotToolPose ===
csv_file = load_robot_poses_from_fk(os.path.join(path, "temp"))
tool_pose = np.loadtxt(csv_file, delimiter=',')
R_tool = []
t_tool = []
for i in range(int(N)):
R_tool.append(tool_pose[0:3, 4*i:4*i+3])
t_tool.append(tool_pose[0:3, 4*i+3])
R_, t_ = cv2.calibrateHandEye(R_tool, t_tool, rvecs, tvecs, cv2.CALIB_HAND_EYE_TSAI)
return R_, t_
if __name__ == '__main__':
gen_T_txt()
rotation_matrix, translation_vector = func()
rotation = R.from_matrix(rotation_matrix)
quaternion = rotation.as_quat()
print(f"旋转矩阵是:\n {rotation_matrix}")
print(f"平移向量是:\n {translation_vector}")
print(f"四元数是:\n {quaternion}")