当前位置:网站首页>aloam 代码阅读与总结
aloam 代码阅读与总结
2022-07-02 15:56:00 【xiaoma_bk】
文章目录
Aloam
A-LOAM是LOAM的高级实现,它使用 Eigen 和 Ceres Solver 来简化代码结构。 此代码由LOAM和LOAM_NOTEA修改而来。 这段代码简洁明了,没有复杂的数学推导和冗余操作。 对于 SLAM 初学者来说是一本很好的学习资料。节点示意图:
KITTI Example
- 下载 KITTI Odometry dataset 数据集到 你数据集文件夹,设置
dataset_folder和sequence_number参数。 - 请注意,您还可以通过在
kitti_helper.launch中设置适当的参数来将 KITTI 数据集转换为包文件以便于使用。
- 下载 KITTI Odometry dataset 数据集到 你数据集文件夹,设置
Summary
优点:
- 代码确实简洁了不少,如果有loam基础在看这个,确实一目了然。
建议:
计算曲率时,每一线间的转变未考虑进去,不过不影响,因为提取特征时都跳过了每一线的起始多少个点
基于曲率大小筛选特征时,因为点云已经基于曲率排过序了
- 角点:if 判断曲率需大于0.1成立,否则直接break不好吗,一直遍历完不浪费时间
- 平面点:if 判断曲率需小于0.1成立,否则直接break不好吗,一直遍历完不浪费时间
找临近后确定 直线和平面时 感觉没lio-sam中精度高
ceres优化,来个手动求导不好吗
rosbag read_write
- 读写rosbag 用到 bag 类,具体使用见下例子:
// 定义读写对象,并申明
rosbag::Bag i_bag, o_bag;
i_bag.open(src_bag, rosbag::bagmode::Read);
o_bag.open(new_bag, rosbag::bagmode::Write);
// 定义一个数组
std::vector<std::string> topics;
topics.push_back(std::string(imu_topic));
topics.push_back(std::string(pcd_topic));
// 申明 rosbag::View对象
rosbag::View view(i_bag, rosbag::TopicQuery(topics));
///< 读取方法一:
for (auto m : view) {
// 遍历view
sensor_msgs::Imu::ConstPtr imu = m.instantiate<sensor_msgs::Imu>();
if (imu == nullptr) {
// 是否有imu
std::cerr << "imu null " << std::endl;
} else {
std::cout << "imu stamp:" << imu->header.stamp << std::endl;
o_bag.write(imu_topic, imu->header.stamp, imu);
}
sensor_msgs::PointCloud2::ConstPtr pcd =
m.instantiate<sensor_msgs::PointCloud2>();
if (pcd == nullptr) {
std::cerr << "pcd null " << std::endl;
} else {
std::cout << "pcd stamp:" << pcd->header.stamp << std::endl;
o_bag.write(pcd2_topic, pcd->header.stamp, pcd);
}
}
///< 读取方法二:
rosbag::View view(bag);
for (const rosbag::ConnectionInfo* c : view.getConnections()) {
const std::string& topic = c->topic;
if (topic_to_publisher.count(topic) == 0) {
ros::AdvertiseOptions options(c->topic, kQueueSize, c->md5sum,
c->datatype, c->msg_def);
topic_to_publisher[topic] = node_handle.advertise(options);
}
}
scanRegistration
主函数:
- Ros节点
- ros 节点初始化
scanRegistration - 读取参数:
scan_line、minimum_range
- ros 节点初始化
- 只支持 16,32,64 线的 velodyne,不对则 return
- 订阅话题:
/velodyne_pointslaserCloudHandler
- 发布话题:
sensor_msgs::PointCloud2>("/velodyne_cloud_2", 100);sensor_msgs::PointCloud2>("/laser_cloud_sharp", 100);sensor_msgs::PointCloud2>("/laser_cloud_less_sharp", 100);sensor_msgs::PointCloud2>("/laser_cloud_flat", 100);sensor_msgs::PointCloud2>("/laser_cloud_less_flat", 100);sensor_msgs::PointCloud2>("/laser_remove_points", 100);
- 基于参数 确定是否发布每条线 正常不执行
laserCloudHandler
- 上来一个系统初始化,就是单纯跳过多少帧
- 点云转 pcl格式,pcl::removeNaNFromPointCloud
- 移除最近点,removeClosedPointCloud
- 遍历每个点,求 点到 激光的距离,若距离小于阈值,则 continue
- 否则将点放入新一个容器中
- 起始角度计算:
- 开始角:startOri = -atan2(pointp[0].y,pointp[0].x)
- 结束角:endOri = -atan2(pointp[size-1].y,pointp[size-1].x)+2π
- 若 endOri-startOri > 3π endOri -= 2π
- 若 endOri-startOri < 3π endOri += 2π
- 计算 scanID + relTime
- scanID 哪一线,好计算
- relTime 与初始点的时间差 算与初始点的水平角*周期/总角度
- 计算每个点的曲率
- 跟 loam计算一样
- 每一线间的转变未考虑进去,不过不影响,因为提取特征时都跳过了每一线的起始多少个点
- 遍历 多线
N_SCANS,对于每一线,将点云均分成6份:- 计算每一份的起始下标: sp,ep
- 将每一份的点云按曲率从小到大排序
std::sort函数 - 找角点,反向遍历已排好序的点云
- 若曲率大于 0.1 且 周围点可以为特征点 时:
- 找曲率最大的2 点放入
cornerPointsSharp点云标记:2 - 找曲率 最大的20个放入
cornerPointsLessSharp点云标记:1 - 若该点标为特征点时, 周围的5个点不可以为特征点
- 找曲率最大的2 点放入
- 若曲率大于 0.1 且 周围点可以为特征点 时:
- 找平面点,正向遍历已排好序的点云
- 若曲率小于 0.1 且 周围点可以为特征点 时:
- 找曲率最大的4 点放入
surfPointsFlat点云标记:-1 - 若该点标为特征点时, 周围的5个点不可以为特征点
- 找曲率最大的4 点放入
- 若曲率小于 0.1 且 周围点可以为特征点 时:
- 若 标记为-1 则放入
surfPointsLessFlatScan
laserOdometry
主函数:
- Ros节点
- ros 节点初始化
laserOdometry - 读取参数:
mapping_skip_frame默认2
- ros 节点初始化
- 订阅话题:
/velodyne_cloud_2laserCloudFullResHandler- 这个点云就是去了最近点和 nan的
- 这个回调也比较简单,将 数据放入队列中
- 四种特征,角点,角点less,平面点,平面点less
- 这四个回调都比较简单,就把数据放入队列中而已
- 发布:
- 角点 和 平面点
velodyne_cloud_3laser_odom_to_initlaser_odom_path
- while 主线程,ros::spin0nce,100hz
- 上面5种数据都到 且 取第一个数据时间都一致时
- 当5种数据都到后,时间肯定一致,不一致ros报错
- 5种数据进行 pcl数据转换
- 若 systemInited== flase时:
- 直接赋值 systemInited=true
- 否则,优化两次,对于每一次都执行下列操作:
- 优化变量为 位姿 para_q,para_t,4+3个自由度
- 遍历角点特征:
- 将角点转换到里程计坐标系,TransformToStart
- 通过kdTree找到 直线
- 通过kdTree 找到上一帧中的最近角点下标
pointSearchInd - 该点下标 上下两range中最近的一个点作为 另一个点
- 两点构成一条直线
- 通过kdTree 找到上一帧中的最近角点下标
- 通过 LidarEdgeFactor 构造ceres直接约束
- 并添加残差
- 遍历平面特征:
- 将平面点转换到里程计坐标系,TransformToStart
- 通过kdTree找到 平面
- 通过kdTree 找到上一帧中的最近角点下标
pointSearchInd - 该点下标 上下两range中最近的一个点作为 另一个点
- 同一ring中 往前伸一个 平面特征作为 第三个点
- 通过kdTree 找到上一帧中的最近角点下标
- 通过 LidarPlaneFactor 构造ceres直接约束
- 并添加残差
- 构建求解器:迭代4次,QR分解,得到解
- 更新
q_w_curr和t_w_curr - 更新 上一帧 角点和平面点kdTree
- 上面5种数据都到 且 取第一个数据时间都一致时
TransformToStart
- 记录了上一次里程计坐标系的关系,直接按上次的关系进行转换
- 即认为 当前帧初值与上一帧初值一样,方便计算
LidarEdgeFactor
- 点到直线的距离,自动求导
LidarPlaneFactor
- 点到平安的距离,自动求导
laserMapping
主函数:
- ros节点初始化
- 定义节点
laserMapping - 读取参数:
mapping_line_resolution0.4mapping_plane_resolution0.8
- 定义节点
- 订阅话题:
/laser_cloud_corner_lastlaserCloudCornerLastHandler/laser_cloud_surf_lastlaserCloudSurfLastHandler/laser_odom_to_initlaserOdometryHandler/velodyne_cloud_3laserCloudFullResHandler
- 发布话题:
- 主线程 mapping_process process
callback
- 3个激光回调都将数据放入各自的队列中,有互斥锁
- 激光里程计回调除了将数据放入队列中后,还基于里程计漂移将数据从世界坐标系发出
process
while 1循环,2s执行一次
- 数据同步,并转换成pcl格式
- 若 3种点云数据 和 里程计数据都不为空时:
- 若某一种据比
cornerLastBuf.front()数据早时,则 pop
- 若某一种据比
- 取各个数据的第一个数据,应该 这四种数据的时间一致
- 同一节点发的,且四种数据的时间戳给的一样
- 将3种点云数据通过pcl 转换为各自对象,并从队列中 pop_front
- 若
cornerLastBuf非空时, pop其数据,保证实时性
- 若 3种点云数据 和 里程计数据都不为空时:
- 得到当前帧在世界坐标系的位姿 transformAssociateToMap()
- L W T = O W T ∗ L O T { _L^WT=_O^WT*_L^OT} LWT=OWT∗LOT
- 1、优化处理 找当前估计的lidar位姿属于哪个cube,I/J/K对应cube的索引
- cube中心位置索引,50m的分辨率,初始值 [10,10,5]
- 2、如果当前帧lidar位姿对应的cube在整个大cube边缘则将索引向中心方向挪动一个单位
- width 方向:centerCubeI 和 中心位置索引都相应改变
- centerCubeI 在 width 方向的小端 ,将帧cube指针向中心方向平移,即 i = i-1
- centerCubeI 在 width 方向的大端 ,将帧cube指针向中心方向平移,即 i = i+1
- height 方向:centerCubeJ 和 中心位置索引都相应改变
- centerCubeJ 在 height 方向的小端 ,将帧cube指针向中心方向平移,即 i = i-1
- centerCubeJ 在 height 方向的大端 ,将帧cube指针向中心方向平移,即 i = i+1
- depth 方向:centerCubeK 和 中心位置索引都相应改变
- centerCubeK 在 depth 方向的小端 ,将帧cube指针向中心方向平移,即 i = i-1
- centerCubeK 在 depth 方向的大端 ,将帧cube指针向中心方向平移,即 i = i+1
- width 方向:centerCubeI 和 中心位置索引都相应改变
- 3、取 centerCube周围的点云组成 局部地图
- 当前 centerCube 的 三个方向各扩展2个各自的 有效数组
- 将 centerCube周围有效数组的 角点、平面点地图集点云想加起来
- 4、当前帧 角点 和 平面点特征 进行降采样
- 5、得到当前帧与地图匹配的位姿
- 如果满足 角点地图个数大于10 且 平面点地图点个数大于50,才执行
- 将地图点云放入 kdtree中方便查找
- 迭代两次 求解:
- 遍历当前帧 角点特征,构建ceres误差模型
- 当前角点转到世界坐标系,并找5个最近点
- 若5个点都小于1m时
- 得到 5个点的协方差,并计算其特征值和特征向量
- 如果确实是线特征,构建线特征模型 (注意特征库按升序对特征值进行排序)
- 遍历当前帧 面点特征,构建ceres误差模型
- 转到世界坐标系,并找5个最近点
- 若5个点都小于1m时,构建5个点的方程: ax+by+c=1
- 若平面5个点到平面的距离都小于0.2m,证明平面成立,构建面特征模型
- 构建面特征模型
- 求解 得到 匹配结果
- 遍历当前帧 角点特征,构建ceres误差模型
- 6、优化完成后,更新数据
- 进行位姿更新
- 跟新当前帧中角点 在 cube,并加入地图
- 跟新当前帧中 平面点 在 cubeI,并放入地图
- 7、对地图进行体素滤波 降采样
- 8、发布相应的数据
边栏推荐
- 把xshell連接服務器關掉,運行的jar包就自動停止的解决方案
- Simple linear programming problem
- [target tracking] | data set summary
- 松翰SN8P2511 SOP8单片机 可代烧录 提供单片机方案开发 单片机解密
- 把xshell连接服务器关掉,运行的jar包就自动停止的解决方案
- 【Zuul】com.netflix.zuul.exception.ZuulException: Hystrix Readed time out
- [非线性控制理论]7_High gain and High Frequency
- Turn off the xshell connection server and the running jar package will stop automatically
- Solving simple differential equations
- 977.有序数组的平方
猜你喜欢

finally详解

Daily question - inverted string

【历史上的今天】7 月 2 日:BitTorrent 问世;商业系统 Linspire 被收购;索尼部署 PlayStation Now

【网络是怎样连接的】第六章 请求到达服务器以及响应给客户端(完结)
![链表求和[dummy+尾插法+函数处理链表引用常见坑位]](/img/08/30e8ca2376104d648a82dca8a72c42.png)
链表求和[dummy+尾插法+函数处理链表引用常见坑位]

Are you holding back on the publicity of the salary system for it posts such as testing, development, operation and maintenance?
![[nonlinear control theory]7_ High gain and High Frequency](/img/e5/6c5ca4a89c97d9613cddccb281b35b.png)
[nonlinear control theory]7_ High gain and High Frequency

chrome浏览器快速访问stackoverflow
![[非线性控制理论]8_三种鲁棒控制器的比较](/img/a8/03ed363659a0a067c2f1934457c106.png)
[非线性控制理论]8_三种鲁棒控制器的比较

Modbus协议通信异常
随机推荐
Pms132b single chip microcomputer TWS digital tube Bluetooth charging chamber program development
567.字符串中的排列
每日一题——倒置字符串
PMS132B单片机TWS数码管蓝牙充电仓方案开发
售价仅40元,树莓派Pico开发板加入WiFi模块,刚上市就脱销
应广PMC131 SOP16 16pin八位单片机
嵌入式 ~ 介绍
[非线性控制理论]7_High gain and High Frequency
Solution pour arrêter automatiquement les paquets Jar en cours d'exécution en éteignant le serveur de connexion xshell
This "architect growth note" made 300 people successfully change jobs and enter the big factory, with an annual salary of 50W
MB10M-ASEMI整流桥MB10M
应广单片机开发调试应注意的问题
Pms150c Yingguang MCU development case
Edgenext hit a mixed punch: a lightweight architecture integrating CNN and transformer
Daily question - inverted string
Modbus协议通信异常
Si446 usage record (I): basic data acquisition
Alibaba Tianchi SQL learning notes - Day3
Linux中,mysql设置job任务自动启动
[target tracking] | data set summary
