python机械手标定_基于OpenCV-Python的机器人手眼标定和重投影(九点标定法)

前言:

这一篇,就是记录一下,如何标定,以及计算标定参数和重投影精度。

我好像没有在中文社区,搜到“九点标定”和“重投影”的相关关键词。

但在张正友标定法中,是有一个重投影误差的概念的。

即将算出来的变换矩阵M,代入变换公式中,计算出新的目标坐标,和原坐标的的误差。

用公式表达即:new_target_pos = origin_pos*M

e = MSE(new_target_pos, target_pos)

直观上理解,如果我们的标定参数,覆盖了所有的样本,通过最小二乘法拟合,那么拿到的误差应该就会比较小。

所以我借用深度学习常用的方法,划分了训练集和测试集。

并且测试了不同训练样本对结果的影响。

结果非常amazing啊!其实3点,这个函数也是能用的,但是至少要有3个点,因为1个点两个等式,有6个未知量。

数据集中可能存在一些异常点,异常点对结果的影响非常大!

只要找到合适的数据点,其实优化不优化,结果都比较好。

如果存在误差特别大的点,那就用多一点的数据,效果也不错。

实验流程:Eye-to-Hand Calibration:

摄像机固定,与机器人基坐标系相对位置不变。且机器人末端在固定平面移动,即只需要求一个单应性矩阵的变换关系就行。

实验流程如下:手眼系统场景搭建:相机固定,机械臂带动针尖在固定平面移动。

标定样本采集。包括摄像机图像采集,以及对应的机器人关节构型采集。--calibration_data_collected_main.py

图像处理提取标定针尖,并计算针尖在机器人坐标系下坐标。记录好每个位置点的 针尖像素坐标、针尖世界坐标、末端坐标

计算标定参数矩阵M--calibration_class.py

计算重投影误差avg_e--calibration_class.py

标定实验的主要环境配置和使用到的工具有:操作系统:Windows 7 64bit

图像处理工具:OpenCV-Python 3.4.* 如果安装不上的话,版本是4.* 以上,用estimated2DAffine好像也行,没测试过。

机器人和摄像机:新松SCR5七自由度协作机械臂,海康工业相机MV-CA013-21UC

其中calibration_class.py可以单独使用。只要有独立存在的标定点集即可。

那就上代码?

代码:

计算转换矩阵m

def get_m(self,

origin_points_set,

target_points_set):

# 确保两个点集的数量级不要差距过大,否则会输出None,看到这个输出,我直接好家伙。

# 明明回家前,还能输出一个好的转换矩阵,为什么一回家就报错?我错哪儿了...

m = cv2.estimateRigidTransform(origin_points_set,

target_points_set,

fullAffine=True)

return m

重投影误差计算:

def reproject(self,

origin_points_set,

target_points_set,

m):

error_list = []

for index in range(len(origin_points_set)):

p_origin = list(origin_points_set[index])

p_origin.append(1)

p_origin = np.array(p_origin)

p_tar = target_points_set[index]

new_tar = np.dot(m, p_origin)

error = np.linalg.norm(new_tar-p_tar[:2])

error_list.append(error)

print("avg_e:", np.mean(np.array(error_list)))

return np.mean(np.array(error_list))

重投影误差-训练样本数测试:

数据解析:

横轴为训练样本数,从9开始,到29结束,总样本量为37;

纵轴为误差大小,单位为毫米;

标题解释:xy为针尖坐标,uv为针尖像素像素坐标,xy2uv的意思是通过九点标定,计算出uv=mxy中的m,然后将m代入测试样本,算出新的uv_pred_test=mxy_test,计算误差e=mse(uv_pred, uv_origin_test)

如果是mt的话,则是,通过uv=m*xy计算出了m之后,用类似于下面的线性方程组:

t_rx= (A * t_px) + B * t_py + C);

t_ry= (D * t_px) + E * t_py+ F);

解出xy=mt*uv中的mt。再计算重投影误差。

结果在前言已经分析了。

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

总结:

记录这么多,其实核心内容也没什么创新的。

至于九点标定的重投影误差,我看到19年的ICRA竟然有一篇文章在用。

但是人家是eye-in-hand结构,两个机械臂,结构和原理都比我这个复杂多了...

我这个小项目花了我接近一周的时间,时间都花在哪儿了呢?

回顾了一下:

一个是对整个标定过程的怀疑,我从来没有标定过这种手眼结构,也没找到现成的工具包。

对整个信息流都没有搞明白,所以刚开始甚至都不知道采集哪些数据。

其次就是我们这个没有标定板,特征点的检测,只好利用自己写的针尖检测程序,这个程序我也调了很久,最终利用场景信息,写了一个优化的比较好的检测模块,可以在0.04秒一帧的速度下,实现2个像素以内的误差。

接着就是这个垃圾OpenCV的版本问题,4以上的版本没有cv2.estimateRigidTransform。我只能找3.4的版本。

最后就是浮点数精度的问题,因为像素坐标的取值范围是0-1280,而初始的针尖坐标的取值范围是0-0.8,差三个数量级,直接把点集带入函数,不同的电脑硬件不同,返回值竟然不一样。我在台式机可以拿到一个值非常小的的矩阵m,但是在我的笔记本中,同样的代码和数据,返回值竟然是None?我当时都怀疑我是不是笔记本坏掉了。

做一个测试:

在谷歌的colab上测试,最大精度是float128

测试脚本非常简单:

import numpy as np

print(np.finfo(np.longdouble))

out:Machine parameters for float128

---------------------------------------------------------------

precision = 18 resolution = 1e-18

machep = -63 eps = 1.084202172485504434e-19

negep = -64 epsneg = 5.42101086242752217e-20

minexp = -16382 tiny = 3.3621031431120935063e-4932

maxexp = 16384 max = 1.189731495357231765e+4932

nexp = 15 min = -max

而我的笔记本最大精度则是float64,有意思,这个坑一定要记住,说不定什么时候会被这玩意给坑了。

Machine parameters for float64

---------------------------------------------------------------

precision = 15 resolution = 1.0000000000000001e-15

machep = -52 eps = 2.2204460492503131e-16

negep = -53 epsneg = 1.1102230246251565e-16

minexp = -1022 tiny = 2.2250738585072014e-308

maxexp = 1024 max = 1.7976931348623157e+308

nexp = 11 min = -max

说了这么多,希望对大家有所帮助~

你可能感兴趣的:(python机械手标定)