手眼标定-眼在手上
前言:
手眼标定是实现视觉抓取的重要过程之一,用于确定相机坐标系与机械臂末端执行器坐标系之间的转换关系。
1、准备标定板
使用棋盘格或ArUco码作为固定标定板,放置在机械臂工作空间内。
1.1位置选择
-
固定在工作空间内
将标定板(棋盘格或ArUco码)固定在机械臂工作区域的平整表面上,确保机械臂末端携带相机移动到不同位姿时,标定板始终在视野范围内。 -
避免遮挡
确保标定板周围无遮挡物,机械臂运动时不会碰撞到标定板或其他物体。
1.2尺寸与比例
-
尺寸适配
标定板大小应与工作空间匹配,建议标定板占据相机视野的1/3~1/2面积。例如:-
若工作空间为0.5m×0.5m,使用边长0.3m的标定板
-
棋盘格角点数量建议为6×9或7×10(便于检测)
-
-
测量精度
精确测量标定板方格的实际边长(例如25mm),并在代码中准确设置参数(SQUARE_SIZE
)。
1.3 确定棋盘格角点数量,棋盘格方格边长(米)
1.3.1 确定棋盘格角点数量
棋盘格的角点数量指的是内部交叉点的行数和列数,而非整个棋盘的总行或列数。以下是具体步骤:
-
物理棋盘格设计
-
若棋盘格有 MM 行和 NN 列黑白相间的方格,则内部角点数量为:
角点行数=M−1,角点列数=N−1角点行数=M−1,角点列数=N−1 -
示例:
-
一个实际由 7行×10列方格 组成的棋盘格,其内部角点数量为 6行×9列。
-
代码中应配置为
CHECKERBOARD = (6, 9)
。
-
-
-
选择角点数量的原则
-
检测稳定性:角点数量不宜过少(如4×4以下),否则可能导致标定精度不足。
-
视野适配:确保棋盘格在相机视野中占据 1/3~1/2面积,避免边缘角点被裁剪。
-
常见配置:推荐使用 6×9 或 7×10 的角点布局,平衡检测精度与实用性。
-
1.3.2 测量棋盘格方格的实际边长
方格的边长是棋盘格的物理尺寸,需精确测量并转换为米单位:
-
测量方法
-
使用游标卡尺或高精度尺子,测量单个黑白方格的边长。
-
重复测量多个方格并取平均值,减少误差。
-
示例:若测量值为 25.0 mm,则代码中设置为
SQUARE_SIZE = 0.025
(米)。
-
-
误差控制
-
标定精度对方格边长的测量误差敏感,建议误差控制在 ±0.1 mm 以内。
-
若使用打印的棋盘格,需确保打印分辨率不低于 300 DPI,避免缩放失真。
-
-
标定程序中的参数设置
# 标定参数配置示例 CHECKERBOARD = (6, 9) # 角点行数×列数(非方格数!) SQUARE_SIZE = 0.025 # 单位:米(需与物理测量一致)
1.3.3 验证棋盘格有效性
-
角点检测测试
使用OpenCV的
findChessboardCorners
函数验证检测效果:ret, corners = cv2.findChessboardCorners(gray_image, CHECKERBOARD) if ret: cv2.drawChessboardCorners(image, CHECKERBOARD, corners, ret)
注:合格标准:角点检测稳定,绿色网格线完整覆盖棋盘格(如下图)。
-
标定误差分析
标定完成后,检查重投影误差(Reprojection Error):
-
若平均误差 < 0.5像素,说明棋盘格参数设置合理。
-
若误差较大,需检查方格边长测量精度或角点数量配置。
-
2、数据采集
机械臂末端携带相机移动到不同位姿,满足以下条件:
2.1标定板的放置
-
光照与环境
-
均匀光照
避免强光直射或阴影干扰,使用漫反射光源,确保标定板表面光照均匀。 -
背景简洁
标定板周围背景应为单一颜色(如白色或黑色),避免复杂纹理干扰角点检测。
-
-
方向与角度
-
平面对齐
标定板应尽量与机械臂基座坐标系的一个平面(如XY平面)平行,以简化坐标转换关系。若无法完全平行,至少保证标定板表面平整。 -
多角度覆盖
机械臂需移动到不同位姿,使标定板在相机视野中呈现多种角度(倾斜、俯视、侧视等),覆盖以下情况:-
标定板位于视野中心、左上、右下等位置
-
标定板与相机成像平面形成不同夹角(30°~60°为佳)
-
-
2.2位姿变化包含旋转和平移
2.3采集15-20组有效数据
3、坐标关系
通过AX=XB模型求解相机到机械臂末端的变换矩阵X
部分Python代码:
# ---------------------------- 主程序流程 ----------------------------
def main():
# 初始化组件
robot = RobotSimulator()
calibrator = HandEyeCalibrator()
cap = cv2.VideoCapture(0) # 独立初始化相机
# 生成采样位姿(示例,需根据实际工作空间调整)
sample_poses = [
[0.0, -0.3, 0.5, 0.2, 0.0],
[0.5, -0.2, 0.4, -0.3, 0.1],
# 添加更多位姿...
]
# 数据采集循环
for idx, joints in enumerate(sample_poses[:NUM_CALIB_POSES]):
# 控制机械臂移动
robot.move_to_joints(joints)
# 采集图像
ret, frame = cap.read()
if not ret:
continue
# 处理左目图像(假设双目图像左右排列)
left_frame = frame[:, 0:640]
# 收集数据
if calibrator.collect_pose_pair(joints, left_frame):
print(f"成功采集第{len(calibrator.robot_poses)}/{NUM_CALIB_POSES}组数据")
# 显示检测结果
cv2.imshow("Calibration View", left_frame)
if cv2.waitKey(1000) & 0xFF == ord('q'):
break
# 执行标定计算
try:
X = calibrator.calculate_calibration()
print("\n标定矩阵X (camera to end-effector):\n", X)
np.save(SAVE_PATH, X)
print(f"标定结果已保存至 {SAVE_PATH}")
except Exception as e:
print("标定失败:", str(e))
# 释放资源
cap.release()
cv2.destroyAllWindows()
常见问题解答:
问:为什么角点数量比方格数少1?
答:角点是方格的交汇点。例如,3个方格在水平方向会产生2个内部角点。
问:能否使用非正方形棋盘格?
答:不可以。标定算法默认方格为正方形,非正方形将导致标定失败。
问:棋盘格需要严格平整吗?
答:必须保持平整!褶皱或弯曲会显著增加标定误差。