建图定位与坐标变换2

坐标变换

1. A_to_B的问题(A2B)

  在建图定位初学者中,肯定有很多童鞋被坐标变换搞迷糊了,只要搞明白了坐标变换,建图定位上手或者在学习过程中会容易很多,首先解决谁to谁的问题。在上一篇博客中,参考slam十四讲,进行了扫盲。
假设我们定义两个坐标系1坐标系2向量a,那么向量 a a a 在两个坐标系下的坐标为 a 1 a_1 a1, a 2 a_2 a2,那么:

                   a 2 a_2 a2 = R 21 a 1 R_{21}a_1 R21a1 + t 21 t_{21} t21

这里的 R 21 R_{21} R21 是指“把坐标系1的向量变换到坐标系2”中。也就是 1_to_2。此时可以求解得到向量a在坐标系2下的坐标 a 2 a2 a2

2. 连续变换

变换矩阵 T ,连续变换不是一个线性关系,假设进行了两次变换: R 1 , t 1 R_1,t_1 R1,t1 , R 2 , t 2 R_2,t_2 R2,t2:
在这里插入图片描述那么,从 a 到 c 的变换为:
在这里插入图片描述利用变换矩阵T :
在这里插入图片描述依次左乘,前一个变换矩阵在右边,后续进行的变换矩阵 T 2 T_2 T2 左乘变换矩阵 T 1 T_1 T1

3. 用于点的映射

  有两个坐标系, 坐标系W 和 坐标系A,那么 A 在 W 中的相对位姿可以用从 W 的原点到 A 的原点的平移量和A中坐标轴(xyz)在W中的旋转量来表示。
  如果将坐标位姿信息用于点的映射的话,那么 W A T W_{A^T} WAT表示:将 A A A 坐标系中的点转换到 W W W坐标系中。其实,根据这个语法关系可以得出这样一个表达式:
                   W p = W A T × A p W_p=W_{A^T} × A_p Wp=WAT×Ap
转换 W A T W_{A^T} WAT的逆是转换 A W T A_{W^T} AWT,点映射的逆是原转换的反方向。转换的逆可以通过btTransform的成员函数inverse()得到。

4. TF 举栗子

  在自家无人驾驶平台上平台上,车顶安装了三台Lidar,主激光安装支架正中央,支架的两边安装了两台侧激光,在完成多激光的位姿标定后,得到了两组TF,这两组TF在后续中如何使用呢。先上标定结果:
在这里插入图片描述
  上图为标定之后,将三台激光同时在rviz里显示,有的看到图片后会产生疑问,为什么没有点云,这里我解释一下,是视角问题,这一圈点云是打在了车顶上的点云,其它打在地上的点云,由于放大rviz截图,所以看不见了。定义各激光的frame_id。

  • 主激光的frame_id : rslidar ;
  • 左激光的frame_id: velodyne_left ;
  • 右激光的frame_id: velodyne_right ;
    通过标定,得知rslidar与velodyne_left , rslidar与velodyne_right之间的TF。
0.|<node pkg="tf" type="static_transform_publisher" name="link1_link2_broadcaster" args="x y z qx qy qz qx link1 link2 100" />
1.|<node pkg="tf" type="static_transform_publisher" name="velodyne_right_to_rslidar" args="-0.00525205 -0.691748 -0.188128 0.00466339 0.00257724 0.505748  /rslidar /velodyne_right 10" />
2.|<node pkg="tf" type="static_transform_publisher" name="velodyne_left_to_rslidar" args="-0.00770524 0.787548 -0.0191263 0.00413675 -0.00719475 -0.54002  /rslidar /velodyne_left 10" />
  • x y z :代表 link2 相对与 link1 的位置变换。即:velodyne_right 相对于rslidar的位置变换
  • yaw pitch roll 表示link2相对与link1的位姿变换,即:velodyne_right 相对于rslidar的旋转变换,其中 yaw 为绕 z 轴的旋转, pitch 为绕 y 轴的旋转, roll 为绕 x 轴的旋转,逆时针旋转为正,顺时针旋转为负。
  • 参数 10 表示每隔10毫秒发布一次。

通过4*4变换矩阵T,若已知velodyne坐标系下的点的坐标,可以得到该点在rslidar坐标系下的坐标:
                  R p R_{p} Rp = R V T ∗ V p R_{V^T}*V_p RVTVp
R V T R_{V^T} RVT代表变换矩阵T, V p V_p Vp 代表velodyne坐标系下的向量, R p R_{p} Rp 代表rslidar坐标系下的向量。

5. 代码验证

/*节点说明:
  车体坐标系:base_link(base)
  主激光坐标系:rslidar (rs)
  侧激光坐标系:velodyne(vel)
*/

#include <ros/ros.h>
#include <iostream>
#include <cmath>
#include <Eigen/Dense>
#include <Eigen/Geometry>

int main(int argc, char *argv[])
{
    ros::init(argc, argv, "trans_vv6_node");
    ros::NodeHandle nh;

    Eigen::Matrix4d Tf_rs_to_vel;                        //定义4*4的变换矩阵
    Eigen::Matrix4d Tf_base_to_rs;                   //定义4*4位姿变换矩阵
        
    Eigen::Translation3d tl_rs_to_vel(0.0,1.0,0.0);      //rstovel平移 
    Eigen::Vector3d  eulerAngle_rs_to_vel(0.0,0.0,M_PI/2);    //rstovel旋转角      
    
    Eigen::Translation3d tl_base_to_rs(0.0,1.0,0.0);     //basetors平移
    Eigen::Vector3d  eulerAngle_base_to_rs(0.0,0.0,0);   //basetors旋转

    Eigen::Vector4d a_vel;                //velodyne坐标系下的向量a_ve
    Eigen::Vector4d a_rs;                 //定义rslidar坐标系下的向量a_rs
    Eigen::Vector4d a_base;               //车体坐标系下的向量

    Eigen::AngleAxisd rollAngle_1(Eigen::AngleAxisd(eulerAngle_base_to_rs(2),Eigen::Vector3d::UnitX()));
    Eigen::AngleAxisd pitchAngle_1(Eigen::AngleAxisd(eulerAngle_base_to_rs(1),Eigen::Vector3d::UnitY()));
    Eigen::AngleAxisd yawAngle_1(Eigen::AngleAxisd(eulerAngle_base_to_rs(0),Eigen::Vector3d::UnitZ()));
    Tf_base_to_rs = (tl_base_to_rs*yawAngle_1*pitchAngle_1*rollAngle_1).matrix();

    Eigen::AngleAxisd rollAngle_2(Eigen::AngleAxisd(eulerAngle_rs_to_vel(2),Eigen::Vector3d::UnitX()));
    Eigen::AngleAxisd pitchAngle_2(Eigen::AngleAxisd(eulerAngle_rs_to_vel(1),Eigen::Vector3d::UnitY()));
    Eigen::AngleAxisd yawAngle_2(Eigen::AngleAxisd(eulerAngle_rs_to_vel(0),Eigen::Vector3d::UnitZ()));
    Tf_rs_to_vel = (tl_rs_to_vel*yawAngle_2*pitchAngle_2*rollAngle_2).matrix();

    
    //a_rs = Tf_rs_to_vel*a_vel;
    //a_base = Tf_base_to_rs*a_rs;
    //a_base=Tf_base_to_rs*Tf_rs_to_vel*a_vel;

    //a_vel = Tf_rs_to_vel.inverse()*a_rs;
    //a_base=Tf_base_to_rs*a_rs;

    //a_vel = (Tf_base_to_rs*Tf_rs_to_vel).inverse()*a_base;
    //Eigen::Vector4d a_vel_ = Tf_rs_to_vel.inverse()*Tf_base_to_rs.inverse()*a_base;

    

//***********通过vel下的向量计算出其在rs下的向量值

    a_vel << 1,1,1,1;     
    a_rs = Tf_rs_to_vel*a_vel;
    
    std::cout<<"a_vel: "<<a_vel.transpose()<<std::endl;
    std::cout<<"a_rs: "<<a_rs.transpose()<<std::endl; //a_rs 输出为(1,0,1,1)

    a_rs << 1,-1,1,1;
    a_vel = Tf_rs_to_vel.inverse()*a_rs;
    std::cout<<"a_vel: "<<a_vel.transpose()<<std::endl; //a_vel 输出为(1,1,2,1)
    std::cout<<"a_rs: "<<a_rs.transpose()<<std::endl;
    std::cout<<"***********************"<<std::endl;
//***********通过vel下的向量计算出其在a_base下的向量值

    a_vel << 1,1,1,1;
    a_rs = Tf_rs_to_vel*a_vel;
    a_base = Tf_base_to_rs*a_rs;
    Eigen::Vector4d a_base_ = Tf_base_to_rs*Tf_rs_to_vel*a_vel;

    std::cout<<"a_vel: "<<a_vel.transpose()<<std::endl; //1,1,1,1
    std::cout<<"a_rs: "<<a_rs.transpose()<<std::endl;   //1,0,1,1
    std::cout<<"a_base: "<<a_base.transpose()<<std::endl; //1,1,1,1
    std::cout<<"a_base_: "<<a_base_.transpose()<<std::endl;//1,1,1,1
    std::cout<<"***********************"<<std::endl;
    
    a_base << 1,0,1,1;
    a_rs = Tf_base_to_rs.inverse()*a_base;
    a_vel = (Tf_base_to_rs*Tf_rs_to_vel).inverse()*a_base;
    Eigen::Vector4d a_vel_ = Tf_rs_to_vel.inverse()*Tf_base_to_rs.inverse()*a_base;

    std::cout<<"a_base: "<<a_base.transpose()<<std::endl; //1,0,1,1
    std::cout<<"a_rs: "<<a_rs.transpose()<<std::endl;     //1,-1,1,1
    std::cout<<"a_vel: "<<a_vel.transpose()<<std::endl;   //1,1,2,1
    std::cout<<"a_vel_: "<<a_vel_.transpose()<<std::endl;//1,1,2,1
    
    ros::spin();

    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值