4

ALOAM的流程

 1 year ago
source link: https://charon-cheung.github.io/2023/02/24/%E6%BF%80%E5%85%89SLAM/LOAM%E7%B3%BB%E5%88%97/ALOAM%E7%9A%84%E6%B5%81%E7%A8%8B/#laserMapping-%E6%B5%81%E7%A8%8B
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
ALOAM的流程
2023-02-24|LOAM系列|
Word count: 1.5k|Reading time: 5 min

LOAM是一个激光里程计算法,没有闭环检测,也就没有加入图优化框架,该算法把SLAM问题分为两个算法并行运行:一个odometry算法,10Hz;另一个mapping算法,1Hz,最终将两者输出的pose做整合,实现10Hz的位姿实时输出。

LOAM源码主要由四个节点构成,分别完成特征点提取,高频低精度odom, 低频高精度odom, 双频odom融合的功能。实际上, 四个节点的执行顺序完全是串行的,很容易改成单进程的版本。

scanRegistration 流程

  1. 原始点云去除无效点和很近的点,成为无序点云

  2. 通过Lidar坐标系下点的仰角以及水平夹角计算点云的scanID和fireID(点在每个scan的ID为fireID)

  3. 以上是每根线作为独立的子点云,将子点云合并为一帧有序点云

  4. 根据曲率计算4种特征点,角点曲率大,面点曲率小。计算曲率,除了开始5个点和结束的5个点,以当前点为中心,前5个和后5个点都参与计算。然后针对每条scan,提取特征点:

    lS283iQqceOGHYz.png

    曲率最大的前2个点认为是sharp点,最大的前20个点认为是less_sharp
    曲率最小的前4个点认为是flat点,将除了角点之外的所有点(包括flat)都加入 less_flat
  5. 发布4种特征点与滤波后的当前帧点云

laserOdometry 流程

// 后面可以看到,这是点云特征匹配时的优化变量
double para_q[4] = {0, 0, 0, 1};
double para_t[3] = {0, 0, 0};

// 下面的2个分别是优化变量 para_q 和 para_t 的映射:表示的是
// world坐标系下的两个位姿之间的增量,例如 △P = P0.inverse() * P1
Eigen::Map<Eigen::Quaterniond> q_last_curr(para_q);
Eigen::Map<Eigen::Vector3d> t_last_curr(para_t);
  1. 订阅4种特征点的消息,各自加入队列,每次取一帧进行匹配
  2. 用当前帧的角点和面点,与上一帧的角点和面点建立约束。点到线以及点到面的ICP,迭代2次

2.1 sharp点: 将当前帧的sharp点 PcurPcur, 从当前帧的lidar坐标系转换到上一帧的Lidar坐标系,转换后的点云记做 P^lastP^last, 同时将所有点补偿到起始时刻。
每个点的转换公式: po=Rpi+tpo=Rpi+t

使用KD树,寻找上一帧点云 PlastPlast 和 P^lastP^last 中的每个点 P^last iP^lasti 最相近的那个,记做 closesticlosesti,最小距离记做min_square_dis。这是找到了第1个点,还要找第2个。

第2个点和第1个不在同一条scan,在上下的线上寻找。找到比min_square_dis更小,而且是最小的距离min_square_dis2,对应点的索引为 closestjclosestj。必须有两个点,否则不加入ceres优化。

// 残差 = 点O到直线AB的距离
ceres::CostFunction *cost_function = LidarEdgeFactor::Create( $$ p_{cur} $$, $$ P_{closest_\ i} $$, $$ P_{closest_\ j} $$, s);
problem.AddResidualBlock(cost_function, loss_function, para_q, para_t);
// 统计约束的数量

2.2 flat点: 找平面点O最近的3个点A B C,第1个A点也是用KD树找到,一般情况下,B和A在同一条scan,C在不同的scan。必须有三个点,否则不加入ceres优化。

// 残差 = 点O到平面ABC的距离
ceres::CostFunction* cost_function = LidarPlaneFactor::Create(curr_point, last_point_a, last_point_b, last_point_c, s);
problem.AddResidualBlock(cost_function, loss_function, para_q, para_t);
// 统计约束的数量


两种约束的数量不要太少

  1. 对于sharp点,将当前帧Lidar坐标系下的点变换到上一帧的Lidar坐标系下,然后在上一帧的Lidar坐标系计算点到线(找到的原上一帧点云的2个点)的残差。 对于flat点,将当前帧Lidar坐标系下的点变换到上一帧的Lidar坐标系下,然后在上一帧的Lidar坐标系计算点到平面(找到的原上一帧点云的3个点组成的平面)的残差。

    Y4u9x57EDHinqck.png
  2. 经过2次点到线以及点到面的ICP点云配准之后,得到最优的位姿增量 para_qpara_t,更新上一帧的位姿,得到当前帧的位姿,这里说的位姿都指世界坐标系下的位姿,世界坐标系本质就是第1帧的lidar坐标系。

tcur=tcur+qcur∗tlasttcur=tcur+qcur∗tlast
qcur=qcur∗qlastqcur=qcur∗qlast
  1. 发布当前帧在世界坐标系在的位姿,也就是 tcurtcur 和 qcurqcur , corner_less_sharp特征点、surf_less_flat特征点、滤波后的点云

laserMapping 流程

地图的移动机制的目的:尽量将雷达保持在特征地图中心处,以保证在做点云配准时,可以保证在雷达附近可以找到特征点云地图中的特征。

XvatJ3crDGfUEyZ.png
  1. 接收laserOdometry发布的特征点,submap中的corner特征和surf特征在匹配中作为target;而当前帧点云中的两种特征在匹配中作为source。

  2. 基本流程与laserOdometry相同,同样地也分为点到线和点到面的匹配。submap中的点云都是world坐标系,而当前帧的点云都是Lidar坐标系,所以在搜寻最近邻点时,先用预测的Mapping位姿w_curr,将Lidar坐标系下的特征点变换到world坐标系下

  3. 在submap的corner特征点(target)中,寻找距离当前帧corner特征点(source)最近的5个点,求出这5个点的中心。判断这5个点是不是呈线状分布,如果是线状,以中心点构建两个虚拟点。和laserOdometry处理sharp点一样,加入ceres优化,这样比laserOdometry中的ICP过程更鲁棒

  4. 对点到面的情况,也是找5个最近点,使用最小二乘拟合出平面(不是PCA了),如果平面够平,把当前帧的点和平面法向量加入ceres优化,其实也是把点到平面的距离作为残差。

  5. 完成ICP(迭代2次)的特征匹配后,用最后匹配计算出的优化变量w_curr,更新增量wmap_wodom,为下一次Mapping做准备

Mapping线程耗时长,容易丢帧。LOAM最终输出的实时位姿是Mapping线程计算的低频位姿和Odometry线程计算的高频位姿做了整合。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK