UR机器人手眼标定

54 篇文章 6 订阅
40 篇文章 23 订阅

一、UR机器人位姿表示
默认情况下UR机器人的基坐标系和TCP如下图所示:
在这里插入图片描述

注意这里的TCP位置和坐标系都是在默认TCP配置的情况下,默认的TCP配置如下图所示:
在这里插入图片描述

如果用户想要自己设置TCP的位置和坐标系就可以在这个基础上进行配置,上图中的X,Y,Z,RX,RY,RZ表示用户自定义TCP与机器人默认TCP之间的关系(注意不是相对于基坐标系的关系)。X,Y,Z表示位置关系,RX,RY,RZ是使用的旋转矢量法表示的姿态关系,旋转矢量法见下一节。
当UR机器人回零后,机器人默认的TCP相对于基座标系的位姿如下图:
在这里插入图片描述

注意这里是实际值,与理论值相比有一些误差,比如理论值X=0,而实际可能不是0。这里的姿态描述方式使用的是旋转矢量法。

UR机器人的Pose表示的是TCP坐标系相对于基座标系的位置和姿态。一个坐标系相对于另一个坐标系的姿态的表示方法有很多种,比如:X-Y-Z固定角,Z-Y-X欧拉角,RPY角,四元数等。而UR机器人里面使用的是旋转矢量法。
在介绍旋转矢量法之前先看一下等效轴角坐标系表示法。在《机器人学导论》中对等效轴角法有详细讲解,如下图所示,这种方法是用一个单位向量
在这里插入图片描述

和一个转动角度θ来表示两个坐标系之间的旋转关系。具体介绍如下图所示:
在这里插入图片描述

而旋转矢量法用一个旋转矢量:
在这里插入图片描述

来表示两个坐标系之间的旋转关系,其中旋转矢量法与等效轴角坐标系之间的关系是:Rx=θkx,Ry=θky,Rz=θkz。
由旋转矢量求旋转矩阵的方法可以按照如下公式:
在这里插入图片描述

使用上述公式之前需要先求出θ和kx,ky,kz,求法如下:
在这里插入图片描述
在这里插入图片描述

可以看出如果θ=0°或180°时,旋转轴根本无法确定,上式也将无解。这也是旋转矢量法的一个明显缺点。
反过来,如果已知旋转矩阵,可以通过如下公式求解等效轴角表示法,进而求出旋转矢量表示法:
在这里插入图片描述

注意2-82中的r33应改为r23,这是书中的一处错误。

由以上叙述可以知道,对于同一姿态,旋转矩阵的表示不唯一。所以在UR机器人中,通过面板观察到的TCP Pose可能与通过脚本命令get_actual_tcp_pose()所得到的不一样,这是正常现象。如果不相信可以将它们都转换成RPY角就会发现,它们表示的是同一个姿态。

二、UR机器人手眼标定

获取相机坐标系和机器人TCP之间的旋转关系

相机坐标系下三维坐标
PW=T6TmPC
则变成:
Pw*(T6^-1)=Tm*Pc
获取5个相机坐标系下三维坐标点以及5个机器人坐标系下三维坐标点,
以及采集5个相机坐标系下三维坐标点时机器人的位姿(x,y,z,Rx,Ry,Rz)

由相机位姿获取T6矩阵:
MATLAB程序:

function [ Rt ] = URP2Rt( x, y, z, Rx, Ry, Rz )

theta = (Rx^2 + Ry^2 + Rz^2)^0.5;
kx = Rx/theta;
ky = Ry/theta;
kz = Rz/theta;
v = 1 - cos(theta);
s = sin(theta);
c = cos(theta);
R = [kx*kx*v + c, kx*ky*v - kz*s, kx*kz*v + ky*s;
    kx*ky*v + kz*s, ky*ky*v + c, ky*kz*v - kx*s;
    kx*kz*v - ky*s, ky*kz*v + kx*s, kz*kz*v + c;];
t = [x, y, z]';
Rt = [R t; 0 0 0 1];

end

C++程序:

Mat Cal_URT6(Mat T6, float Robot_postion[7])//计算T6矩阵
{
	float Px, Py, Pz, rota, rotb, rotc;
	Px = Robot_postion[1] * 1000;
	Py = Robot_postion[2] * 1000;
	Pz = Robot_postion[3] * 1000;

	rota = Robot_postion[4];
	rotb = Robot_postion[5];
	rotc = Robot_postion[6];

	float theta = sqrt(Robot_postion[4]*Robot_postion[4]+Robot_postion[5]*Robot_postion[5]+Robot_postion[6]*Robot_postion[6]);
    float kx = rota/theta;
	float ky = rotb/theta;
	float kz = rotc/theta;

	float v= 1-cos(theta);
	float s = sin(theta);
	float c = cos(theta);

	float m1[3][3]={kx*kx*v+c,kx*ky*v-kz*s,kx*kz*v+ky*s,kx*ky*v + kz*s, ky*ky*v + c, ky*kz*v - kx*s,kx*kz*v - ky*s, ky*kz*v + kx*s, kz*kz*v + c};
	Mat R1(3, 3, CV_32F, m1);

	float m4[3][1] = { Px, Py, Pz };
	Mat T1(3, 1, CV_32F, m4);

	float m5[1][4] = { 0, 0, 0, 1 };
	Mat T2(1, 4, CV_32F, m5);
	Mat A;
	hconcat(R1, T1, A);//A = [b c]
	vconcat(A, T2, T6);//A = [b;c]
	return T6;
}

进行手眼标定

void Collectpoint1()
{
	Robot_postion[0] = 1 ;
	Robot_postion[1] = -0.08126;
	Robot_postion[2] = -0.40936;
	Robot_postion[3] = -0.62562;
	Robot_postion[4] = 5.067 ;
	Robot_postion[5] = -0.962;
	Robot_postion[6] = -3.564;
	float m1[3][1] = {-6.46543, 7.98035, 190.538};

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 1; j++)
		{
			Ps1.at<float>(i, j) = m1[i][j];
		}
	}
	cout << "Ps1=" << Ps1 << endl;

	T61 = Cal_URT6(T6_robot, Robot_postion);
	//cout << "T61=" << T61<< endl;

	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			Ts1[i][j] = T61.at<float>(i, j);
			cout << Ts1[i][j] << ",";
		}
		cout << endl;
	}
}
void Get_Tm()
{
	cout << "Ts11=" << endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << Ts1[i][j] << ",";
		}
		cout << endl;
	}
	cout << "Ts22=" << endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << Ts2[i][j] << ",";
		}
		cout << endl;
	}
	cout << "Ts33=" << endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << Ts3[i][j] << ",";
		}
		cout << endl;
	}
	cout << "Ts44=" << endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << Ts4[i][j] << ",";
		}
		cout << endl;
	}
	cout << "Ts55=" << endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << Ts5[i][j] << ",";
		}
		cout << endl;
	}



	float w1[1][4] = { -82.58,-401.29,-640.25,1 };
	Pw1 = Mat(4, 1, CV_32F, w1);
	cout << "Pw1=" << Pw1 << endl;

	float  w2[1][4] = { -82.58,-401.29,-640.25,1 };
	Pw2 = Mat(4, 1, CV_32F, w2);
	cout << "Pw2=" << Pw2 << endl;

	float  w3[1][4] = { -82.58,-401.29,-640.25,1 };
	Pw3 =Mat(4, 1, CV_32F, w3);
	cout << "Pw3=" << Pw3 << endl;

	float  w4[1][4] = { -82.58,-401.29,-640.25,1};
	Pw4 = Mat(4, 1, CV_32F, w4);
	cout << "Pw4=" << Pw4 << endl;

	float  w5[1][4] = { -82.58,-401.29,-640.25,1};
	Pw5 =Mat(4, 1, CV_32F, w5);
	cout << "Pw5=" << Pw5 << endl;

	//Mat TV_61(4, 4, CV_32F);
	//Mat TV_62(4, 4, CV_32F);
	//Mat TV_63(4, 4, CV_32F);
	//Mat TV_64(4, 4, CV_32F);
	//Mat TV_65(4, 4, CV_32F);

	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			T61.at<float>(i, j) = Ts1[i][j];
			T62.at<float>(i, j) = Ts2[i][j];
			T63.at<float>(i, j) = Ts3[i][j];
			T64.at<float>(i, j) = Ts4[i][j];
			T65.at<float>(i, j) = Ts5[i][j];
		}
	}
	T61 = Mat(4, 4, CV_32F, Ts1);
	T62 = Mat(4, 4, CV_32F, Ts2);
	T63 = Mat(4, 4, CV_32F, Ts3);
	T64 = Mat(4, 4, CV_32F, Ts4);
	T65 = Mat(4, 4, CV_32F, Ts5);

	cout << "T61=" << T61 << endl;
	cout << "T62=" << T62 << endl;
	cout << "T63=" << T63 << endl;
	cout << "T64=" << T64 << endl;
	cout << "T65=" << T65 << endl;

	invert(T61, TV_61, DECOMP_SVD);
	cout << "TV_61=" << TV_61 << endl;

	invert(T62, TV_62, DECOMP_SVD);
	cout << "TV_62=" << TV_62 << endl;

	invert(T63, TV_63, DECOMP_SVD);
	cout << "TV_63=" << TV_63 << endl;

	invert(T64, TV_64, DECOMP_SVD);
	cout << "TV_64=" << TV_64 << endl;

	invert(T65, TV_65, DECOMP_SVD);
	cout << "TV_65=" << TV_65 << endl;

	Pw11_1 = TV_61*Pw1;
	cout << "Pw11_1=" << Pw11_1 << endl;
	Pw22_2 = TV_62*Pw2;
	cout << "Pw22_2=" << Pw22_2 << endl;
	Pw33_3 = TV_63*Pw3;
	cout << "Pw33_3=" << Pw33_3 << endl;
	Pw44_4 = TV_64*Pw4;
	cout << "Pw44_4=" << Pw44_4 << endl;
	Pw55_5= TV_65*Pw5;
	cout << "Pw55_4=" << Pw55_5 << endl;


	Pw11_1(Rect(0, 0, 1, 3)).copyTo(Pw11);
	//cout << "Pw11=" << Pw11 << endl;
	Pw22_2(Rect(0, 0, 1, 3)).copyTo(Pw22);
	//cout << "Pw22=" << Pw22 << endl;
	Pw33_3(Rect(0, 0, 1, 3)).copyTo(Pw33);
	//cout << "Pw33=" << Pw33 << endl;
	Pw44_4(Rect(0, 0, 1, 3)).copyTo(Pw44);
	//cout << "Pw44=" << Pw44 << endl;
	Pw55_5(Rect(0, 0, 1, 3)).copyTo(Pw55);
	cout << "Pw55=" << Pw55 << endl;


	hconcat(Ps1, Ps2, A1);
	//cout << "A1=" << A1 << endl;
	hconcat(A1, Ps3, A2);
	//cout << "A2=" << A2 << endl;
	hconcat(A2, Ps4, A3);
	//cout << "A3=" << A3 << endl;
	hconcat(A3, Ps5, PS);
	cout << "PS=" << PS << endl;


	hconcat(Pw11, Pw22, B1);
	//cout << "B1=" << B1 << endl;
	hconcat(B1, Pw33, B2);
	//cout << "B2=" << B2 << endl;
	hconcat(B2, Pw44, B3);
	//cout << "B3=" << B3 << endl;
	hconcat(B3, Pw55, PW);
	cout << "PW=" << PW << endl;

	PS.copyTo(PSS);
	cout << "PSS=" << PSS << endl;

	PW.copyTo(PWW);
	cout << "PWW=" << PWW << endl;

	int row = PSS.rows;
	int col = PSS.cols;
	MatrixXd in(row, col);
	MatrixXd out(row, col);
	cv2eigen(PSS, in);
	cv2eigen(PWW, out);
	cout << "in=" << in << endl;
	cout << "out=" << out << endl;

	MatrixXd T;
	T = Eigen::umeyama(in, out, 0);//9ms
	cout << "Tm_Matrix = " << T << endl;

参考文献:https://blog.csdn.net/u014170067/article/details/83834043/

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值