A-LOAM
Last updated on May 7, 2023 pm
[TOC]
Overview
A-LOAM is an Advanced implementation of LOAM (J. Zhang and S. Singh. LOAM: Lidar Odometry and Mapping in Real-time), which uses Eigen and Ceres Solver to simplify code structure.
Code: A-LOAM 注释版
ROS Graph
Pipeline
Lidar Hardware
Hokuyo UTM-30LX
- Vertical
- sweep: \(180^\circ / s\), a rotation from \(-90^\circ\) to \(90^\circ\) or in the inverse direction (lasting for 1s)
- FOV: \(180^\circ\)
- scan rate: 40 lines/sec
- resolution: \(180^\circ / 40 = 4.5^\circ\)
- Horizontal (a scan plane)
- resolution: \(0.25^\circ\) within a scan
- angular speed: \(180^\circ\) between \(-90^\circ\) and \(90^\circ\) with the horizontal orientation of the laser scanner as zero
VLP-16
- Time of flight distance measurement with calibrated reflectivities
- 16 channels
- Measurement range up to 100 meters
- Accuracy: +/- 3 cm (typical)
- Dual returns
- Field of view (vertical): 30° (+15° to -15°)
- Angular resolution (vertical): 2°
- Field of view (horizontal/azimuth): 360°
- Angular resolution (horizontal/azimuth): 0.1° - 0.4°
- Rotation rate: 5 - 20 Hz
Scan Registration
数据预处理
数据清洗
1
2pcl::removeNaNFromPointCloud(laserCloudIn, laserCloudIn, indices);
removeClosedPointCloud(laserCloudIn, laserCloudIn, MINIMUM_RANGE);按线数保存的点云集合
1
2
3float relTime = (ori - startOri) / (endOri - startOri);
point.intensity = scanID + scanPeriod * relTime;
laserCloudScans[scanID].push_back(point);曲率计算 (使用每个点的前后五个点)
1
2
3
4
5
6
7for (int i = 5; i < cloudSize - 5; i++) {
// ...
cloudCurvature[i] = diffX * diffX + diffY * diffY + diffZ * diffZ;
cloudSortInd[i] = i;
cloudNeighborPicked[i] = 0;
cloudLabel[i] = 0;
}
特征提取
根据曲率进行点云特征提取,将每条线上的点分入相应的类别:边沿点和平面点
- sharp edges
- planar surface patches
对于每条线
- 将每个scan的曲率点分成6等份处理,确保周围都有点被选作特征点
对于每一份,曲率大于0.1的点
- 挑选曲率最大的前2个点放入sharp点集合
cornerPointsSharp
,同时cloudLabel[ind] = 2
- 挑选曲率最大的前20个点放入less sharp点集合
cornerPointsLessSharp
,同时cloudLabel[ind] = 1
- 点的前后各5个连续距离比较近的点筛选出去,防止特征点聚集,使得特征点在每个方向上尽量分布均匀
对于每一份,曲率小于0.1的点
- 放入flat点集合
surfPointsFlat
,同时cloudLabel[ind] = -1
- 点的前后各5个连续距离比较近的点筛选出去,防止特征点聚集,使得特征点在每个方向上尽量分布均匀
对于每一份,将剩余的点 cloudLabel[k] <= 0
(包括之前被排除的点)全部归入平面点 surfPointsLessFlatScan
Odometry(高频率,粗定位)
运动畸变矫正
运动畸变示意图如下
Reprojecting point cloud to the end of a sweep
1 |
|
特征匹配 (Scan-Scan)
correspondence for corner features
当前点 curr_point
与 线段 匹配,找到线段的两个端点
last_point_a
: KDTree 搜索最近的点last_point_b
: 在scan增长和下降的方向上分别搜索,不在同一scan但处于一定阈值scan范围内,距离最小的点
correspondence for plane features
当前点 curr_point
与 面 匹配,找到面的三个点
last_point_a
: KDTree 搜索最近的点last_point_b
: 在scan增长(intensity<=closestPointScanID
)和下降(intensity>=closestPointScanID
)的方向上分别搜索,处于一定阈值scan范围内,距离最小的点last_point_c
: 在scan增长(intensity>closestPointScanID
)和下降(intensity<closestPointScanID
)的方向上分别搜索,处于一定阈值scan范围内,距离最小的点
运动估计 ICP
残差度量方式
- 点到线段距离
- 点到面距离
Mapping(低频率,精定位)
基于Cube的地图管理
LOAM采用的是栅格(cube)地图的方法,将整个地图分成21×21×11个珊格,每个珊格是⼀个边⻓50m的正⽅体,当地图逐渐累加时,珊格之外的部分就被舍弃,这样可以保证内存空间不会随着程序的运⾏⽽爆掉,同时保证效率。
特征匹配 (Scan-Map)
将当前帧已经消除畸变的点云转换到全局坐标系 transformAssociateToMap()
,然后与局部地图(local map或者称为submap,源码中使用的是三维栅格cube做的局部地图管理)做特征匹配
用于特征匹配的局部地图 (local map)
1 |
|
correspondence for corner features
当前点 curr_point
与 线段 匹配,找到线段的两个端点
KDTree 搜索最近的5个点(最远点距离小于1米),计算其中心点 center
,并构建协方差矩阵;如果是线特征,协方差矩阵最大特征值对应的特征向量即为线的方向向量 unit_direction
,然后根据中心点和方向向量得到两个端点
last_point_a
last_point_b
correspondence for plane features
当前点 curr_point
与 面 匹配,找到面的法向量
KDTree 搜索最近的5个点(最远点距离小于1米),计算面的法向量
运动估计 ICP
残差度量方式
- 点到线段距离
- 点到面距离
计算出的位姿修正Odometry的位姿
地图增长
获得 laserCloudCornerArray
和 laserCloudSurfArray
,并降采样;当地图逐渐累加时,珊格之外的部分就被舍弃,这样可以保证内存空间不会随着程序的运⾏⽽爆掉,同时保证效率。
1 |
|