激光SLAM与ROS中,map、odom、laser_link、base_link几个坐标系和坐标转换的理解

由于SLAM过程中需要用到不同的传感器对环境进行感知和观测,而每一个传感器都应一种坐标系,所以在整个SLAM过程中涉及到非常多次的坐标变换,想要搞清楚SLAM的过程,需要对这些坐标变换有充分的理解,本文主要记录一下我对于激光SLAM中坐标变换的理解(ROS下)

在ROS中,常见的坐标系有map,odom,base_link,laser_link,下面分别对这几个坐标系之间的变换进行阐述

base_link\rightarrowlaser_link

两个坐标系的理解:

base_link一般就是指以机器人为原点的坐标系,可以直接理解成机器人本身,laser_link指以激光雷达为中心的坐标系(其余类似于imu这些装在机器人身上的传感器坐标系都类似laser_link),这两个坐标系之间的变换比较简单,一般都是静态的,因为传感器一旦安装在机器人身上就不会再发生移动,所以只需要发布一个静态的TF变换即可完成base_link到laser_link之间的变换。

 如图所示,雷达扫描到前方3m处有一个障碍物,但是对于机器人来说,该障碍物在前方的6m处,造成这个差距的原因就是两者在不同的坐标系下观测同一障碍物,坐标变换的目的就是把这种观测进行统一,要么在雷达坐标系下认为3m处有障碍,要么在机器人坐标系下认为6m处有障碍。

坐标变换何时用到?

当机器人身上的传感器采集到数据时,这些数据都是位于各个传感器坐标系下的,比如雷达通过icp算法得到的行进里程,如果想要在世界坐标下绘制机器人的运动轨迹,就需要用到laser_link到base_link的坐标变换,把里程数据从雷达坐标系转换到机器人坐标系,再逐层向odom和map进行转换。

谁来发布?

一般由我们直接编写静态坐标变换来发布

odom\rightarrowbase_link

两个坐标系的理解:

odom是里程计坐标系,在这个坐标系下已经可以描述机器人的运动了,由机器人里程计发布的信息转换到odom坐标系后,就能够直观的反映机器人的运动里程。odom与base_link之间的坐标变换就由里程计进行发布。机器人运动的时候,是相对于odom这个系在运动,机器人往前运动了10m,是指在odom这个系上运动了10m,但是注意odom和map这两个坐标系不是重合的,要知道机器人在map上运动了多少,还需要做一个odom到map的转换。odom和map不重合的原因就是存在误差,在odom上前进了10m是传感器测出来的,但是真实移动的距离不一定是10m。

坐标变换何时用到?

机器人的里程计,如雷达等,通过icp等算法获得了机器人在两帧数据之间的运动(x,y,theta),把一段时间内的(x,y,theta)进行累加,就获得了这段时间内机器人的运动轨迹和里程,但是(x,y,theta)是传感器得到的,处于laser_link下,所以需要转换到base_link再转换到odom才能够得到相应的轨迹和里程。

谁来发布?

一般由里程计发布

map\rightarrowodom

两个坐标系的理解:

map是世界坐标,一般我们就站在map的角度观测机器人的运动,机器人在SLAM过程中建立的地图也是在map坐标系下的,ROS中机器人的运动可以理解成发布从base_link\rightarrowmap的坐标变换,让base_link在map中动起来,map到base_link的坐标转换是被定位模块计算出来的。但定位模块并不发布map到base_link的转换,相反它先接受从odom到base_link的转换, 再计算并广播map到odom的位置转换关系,是一个间接的过程。

坐标变换何时用到?

map主要在建图时用到,建图的过程实际上就是在map中的正确位置扫描周围信息,建立栅格地图的过程,而正确的位置,就是通过把odom中的位置变换到map中得到的。

谁来发布?

一般由定位模块进行发布

代码中如何体现坐标变换?

在代码中,一般通过tf这个库来进行坐标变换的处理,通过建立一个变换矩阵T来存储两个坐标系之间的坐标变换,在进行坐标变换时,遵循以下步骤:

  1. 把数据转换为TF所需要的格式,从TF中创建一个容器V存储这个数据
  2. 通过乘以变换矩阵T的方式进行坐标变换,V(base_link) = V(laser_link) * T(laser_link to base_link)
  3. 得到V(base_link)后再把数据从TF格式转换为原始格式,供进一步处理

举例:

  tf2::Transform corr_ch;
 
    if (output_.valid)
    {
        // 将雷达数据转换为TF格式数据corr_ch_1
        tf2::Transform corr_ch_l;
        CreateTfFromXYTheta(output_.x[0], output_.x[1], output_.x[2], corr_ch_l);
 
        // 将雷达坐标系下的数据 转换成 base_link坐标系下
        corr_ch = base_to_laser_ * corr_ch_l * laser_to_base_;
 
        // 将base_link坐标系下的数据,转换到odom坐标系下
        base_in_odom_ = base_in_odom_keyframe_ * corr_ch;
   
    }

猜你喜欢

转载自blog.csdn.net/weixin_43890835/article/details/131546455