手眼标定学习总结:camera和vicon标定实践

本文档仅用于记录自己在科研过程中研究手眼标定的过程。

关于原理的总结,见上一篇博客。手眼标定学习总结:原理、Tsai方法和Matlab代码

又经过了元旦3天的调试,今天终于搞定了标定过程。特此记录!

1. camera to target

首先标定相机在target(棋盘格)的坐标。采用核心matlab代码如下:

% calcCameraPose
function [R, t, imagePoints] = calcCameraPose(I, markerSize)
    cameraParams= load('cameraParams.mat');
    [imagePoints,boardSize] = detectCheckerboardPoints(I);
    worldPoints =  generateCheckerboardPoints(boardSize, markerSize);
    worldPoints = [worldPoints, zeros(length(worldPoints), 1)];
    [R,t] = estimateWorldCameraPose(imagePoints,worldPoints,cameraParams.cameraParams);
    t = t';
return 

% 计算camera2target的R和t
[orientation, location, imagePoints] = calcCameraPose(I, 20);
t_t_c = location;
R_t_c = orientation';

需要注意的是:

  1. R_t_c/t_t_c表示将一个点在camera系下的坐标,变换到target系下的坐标
  2. 所调用的函数estimateWorldCameraPose ,得到的是camera在world下的“朝向”和“位置”。所谓的“朝向”是相机按照当前相机坐标系,旋转后抵达world系。所以“将一个点从camera移动到world”对应的旋转矩阵应该是“朝向”的逆变换。(坐标系->坐标系一点)

2. gipper to base

采用VICON系统提供从gripper到base的坐标变换。

首先在VICON中创建刚体,#1和#2两个点连线确定的是z轴的负方向,#1和#3与z-方向的分量为y+方向,剩下确定的是x方向。
在这里插入图片描述
其次,VICON提供的旋转角度和平移,有多种表示方式,例如XYZ/ZYX以及 Helical Axis。前面的都是欧拉角,最后一个是轴角表示。最终导出的数据也是轴角表示。

注意轴角的旋转部分,导出单位是度°,在计算时需要变成弧度,且模长表示旋转角度。

这里的“旋转”和“平移”表示,base系经过此变换后,抵达gripper系(询问了杜博,一般人体是以胯关节为起点,计算出base到胯的变换后,后续其他关节全部相对于胯进行计算)。所以将一个点从gripper系变换到base系恰好是这个旋转,不需要求逆。

将VICON数据转成标准的gripper2base的轴角,核心代码如下:

filename = "vicon_data/"+int2str(idx)+".csv";
fid = fopen(filename, "r");
for j = 1:20             % skip the "titles" of csv file.
    tmp = fgetl(fid);
end
d = textscan(fid, '%d,%d,%f,%f,%f,%f,%f,%f', 1);
rvec(i, :) = deg2rad([d{3}, d{4}, d{5}]);
tvec(i, :) = [d{6}, d{7}, d{8}];

3. 手眼标定

直接进入手眼标定部分,载入两个csv文件,之后进行(核心部分代码)

%% calculate relative transformation
N = 18;
T_b_g_list = zeros(4, 4, N);
T_t_c_list = zeros(4, 4, N);
for i = 1:N
    r_t_c = rvec_t_c(i, :)';
    t_t_c = tvec_t_c(i, :)';
    R_t_c = Rodrigues(r_t_c);
    T_t_c = [R_t_c, t_t_c; 0,0,0,  1];
    
    r_b_g = rvec_b_g(i, :)';
    t_b_g = tvec_b_g(i, :)';
    R_b_g = Rodrigues(r_b_g);
    T_b_g = [R_b_g, t_b_g; 0,0,0,  1];
    T_t_c_list(:,:,i) = T_t_c;
    T_b_g_list(:,:,i) = T_b_g;
end

%% calculate Gij and Cij
Cij_list = [];
Gij_list = [];
for k = 1:N-1
    i = k;
    j = k+1;
    Cij = inv(T_t_c_list(:,:,i)) * T_t_c_list(:,:,j);
    Gij = inv(T_b_g_list(:,:,i)) * T_b_g_list(:,:,j);
    Cij_list = [Cij_list, Cij];
    Gij_list = [Gij_list, Gij];
end

% X is T_g_c when given GX = XC
T_g_c = tsai(Gij_list, Cij_list)

4. 注意事项

手眼标定的精度受实验实采数据的影响极大!
参考文章:手眼标定,我的结果显示手和眼相距上千米!手眼标定结果准确率如何提高?

一开始没有注意摆放的位姿,比较随意,甚至用代码随机生成了一系列的位姿,进行手眼标定。虽然仿真时精确计算的结果是准确的,但只要增加些小的扰动,会产生极大的误差。一开始以为是算法的数值稳定性问题,后来发现是数据给的不合适。所以一定要用实测数据进行验证!

简单来说,总结如下:

  1. 由于camera和gripper之间距离较近,所以尽可能让pose和pose之间的相对距离变化尽可能的小,如果太远,标定的距离远小于移动距离,会造成计算不精确。同时,我注意到,如果单位用m来表示,误差会较大。如果改成cm或mm,则相对误差较小,可能是Tsai算法或代码实现中数值计算中的一些问题。
  2. 计算一组相对位姿时,尽可能让相机有不同的旋转,以体现出camera到gripper的旋转。

其实这些在Tsai的论文中做了数值上的推导,只是我一开始没有当回事而已。截图一些结论:
在这里插入图片描述

5. 完整代码与数据

详见github链接。
https://github.com/LarryDong/HandEye-Tsai

后记

从11月开始,搞这个手眼标定。自己一个人,绕来绕去,终于算是搞定了。真的是不容易。感慨一下!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值