从零入门激光SLAM(十三)——LeGo-LOAM源码超详细解析4

大家好呀,我是一个SLAM方向的在读博士,深知SLAM学习过程一路走来的坎坷,也十分感谢各位大佬的优质文章和源码。随着知识的越来越多,越来越细,我准备整理一个自己的激光SLAM学习笔记专栏,从0带大家快速上手激光SLAM,也方便想入门SLAM的同学和小白学习参考,相信看完会有一定的收获。如有不对的地方欢迎指出,欢迎各位大佬交流讨论,一起进步。博主创建了一个科研互助群****Q:772356582,欢迎大家加入讨论。

一、整体框架

1.1 目的

主要根据里程计获得的先验位姿进行后端优化,闭环检测和图优化

1.2 输入

//接收相机坐标系下的点和里程计
//上一帧角点
subLaserCloudCornerLast = nh.subscribe<sensor_msgs::PointCloud2>("/laser_cloud_corner_last", 2, &mapOptimization::laserCloudCornerLastHandler, this); 
//上一帧面点
subLaserCloudSurfLast = nh.subscribe<sensor_msgs::PointCloud2>("/laser_cloud_surf_last", 2, &mapOptimization::laserCloudSurfLastHandler, this);
//上一帧无效点
subOutlierCloudLast = nh.subscribe<sensor_msgs::PointCloud2>("/outlier_cloud_last", 2, &mapOptimization::laserCloudOutlierLastHandler, this); 
//里程计位姿
subLaserOdometry = nh.subscribe<nav_msgs::Odometry>("/laser_odom_to_init", 5, &mapOptimization::laserOdometryHandler, this);  
//IMU数据
subImu = nh.subscribe<sensor_msgs::Imu> (imuTopic, 50, &mapOptimization::imuHandler, this); 

1.3 输出

//机器人关键帧在全局坐标系下的位置信息,轨迹
pubKeyPoses = nh.advertise<sensor_msgs::PointCloud2>("/key_pose_origin", 2);
//机器人周围激光雷达点云数据
pubLaserCloudSurround = nh.advertise<sensor_msgs::PointCloud2>("/laser_cloud_surround", 2);
//经过位姿图优化和点云配准后的里程计信息
pubOdomAftMapped = nh.advertise<nav_msgs::Odometry> ("/aft_mapped_to_init", 5);
//机器人历史轨迹的点云数据
pubHistoryKeyFrames = nh.advertise<sensor_msgs::PointCloud2>("/history_cloud", 2);
//经过ICP配准后的机器人激光雷达点云数据
pubIcpKeyFrames = nh.advertise<sensor_msgs::PointCloud2>("/corrected_cloud", 2);
//机器人最近获取的点云数据
pubRecentKeyFrames = nh.advertise<sensor_msgs::PointCloud2>("/recent_cloud", 2);
//经过位姿图优化和点云配准后的机器人点云数据用于建图
pubRegisteredCloud = nh.advertise<sensor_msgs::PointCloud2>("/registered_cloud", 2);

主函数

主要的功能是在run函数里面

int main(int argc, char** argv)
{
    ros::init(argc, argv, "lego_loam");
    ROS_INFO("\033[1;32m---->\033[0m Map Optimization Started.");
    mapOptimization MO;
    // 1.进行闭环检测与闭环的功能
    std::thread loopthread(&mapOptimization::loopClosureThread, &MO);
    // 2.将数据发布到ros中,可视化
    std::thread visualizeMapThread(&mapOptimization::visualizeGlobalMapThread, &MO);
    ros::Rate rate(200);
    while (ros::ok())
    {
        ros::spinOnce();
        MO.run(); //进入执行run函数
        rate.sleep();
    }
    loopthread.join();
    visualizeMapThread.join();
    return 0;
}
// 3.run函数
void run(){
	if (timeLaserOdometry - timeLastProcessing >= mappingProcessInterval) {
		timeLastProcessing = timeLaserOdometry;
		transformAssociateToMap(); //转换到map坐标系下
		extractSurroundingKeyFrames(); //提取周围的关键帧
		downsampleCurrentScan(); //下采样当前帧
		// 当前扫描进行边缘优化,图优化以及进行LM优化的过程
		scan2MapOptimization();
		saveKeyFramesAndFactor(); //保存关键帧和因子
		correctPoses(); //校正位姿
		publishTF(); //发布坐标变换
		publishKeyPosesAndFrames(); //发布关键帧和因子
		clearCloud();}}} //清除点云

二、函数解析

2.1 transformAssociateToMap

  • 作用:将坐标转移到世界坐标系下,得到可用于建图的Lidar坐标
  • 输入:transformBefMapped[] 前一帧在世界坐标系的位姿
  •  transformSum  当前帧的位姿
    
  • 输出:transformTobeMapped当前帧在世界坐标系的位置
  • 代码:
 void transformAssociateToMap()
    {
	 float x1 = cos(transformSum[1]) * (transformBefMapped[3] - transformSum[3]) 
		 - sin(transformSum[1]) * (transformBefMapped[5] - transformSum[5]);
	 float y1 = transformBefMapped[4] - transformSum[4];
	 float z1 = sin(transformSum[1]) * (transformBefMapped[3] - transformSum[3]) 
		 + cos(transformSum[1]) * (transformBefMapped[5] - transformSum[5]);
	 float x2 = x1;
	 float y2 = cos(transformSum[0]) * y1 + sin(transformSum[0]) * z1;
	 float z2 = -sin(transformSum[0]) * y1 + cos(transformSum[0]) * z1;
	 // 计算平移增量
	 transformIncre[3] = cos(transformSum[2]) * x2 + sin(transformSum[2]) * y2;
	 transformIncre[4] = -sin(transformSum[2]) * x2 + cos(transformSum[2]) * y2;
	 transformIncre[5] = z2;
	 ……
		 x1 = cos(transformTobeMapped[2]) * transformIncre[3] - sin(transformTobeMapped[2]) 
		 * transformIncre[4];
	 y1 = sin(transformTobeMapped[2]) * transformIncre[3] + cos(transformTobeMapped[2])
		 * transformIncre[4];
	 z1 = transformIncre[5];

	 x2 = x1;
	 y2 = cos(transformTobeMapped[0]) * y1 - sin(transformTobeMapped[0]) * z1;
	 z2 = sin(transformTobeMapped[0]) * y1 + cos(transformTobeMapped[0]) * z1;

	 transformTobeMapped[3] = transformAftMapped[3] 
		 - (cos(transformTobeMapped[1]) * x2 + sin(transformTobeMapped[1]) * z2);
	 transformTobeMapped[4] = transformAftMapped[4] - y2;
	 transformTobeMapped[5] = transformAftMapped[5] 
		 - (-sin(transformTobeMapped[1]) * x2 + cos(transformTobeMapped[1]) * z2);}

详情请见。。。
https://www.guyuehome.com/46822

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/610952.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux -- 日志

一 日志的重要性 在之前的编程经历中&#xff0c;如果我们的程序运行出现了问题&#xff0c;都是通过 标准输出 或 标准错误 将 错误信息 直接输出到屏幕上&#xff0c;以此来排除程序中的错误。 这在我们以往所写的程序中使用没啥问题&#xff0c;但如果出错的是一个不断在运行…

fb设备驱动框架分析

一、字符设备注册过程&#xff1a; 归根到底&#xff0c;fb设备也是一个字符设备&#xff0c;所以逃不开常规的字符设备驱动框架&#xff1a; Linux内核中编写字符设备驱动通常遵循以下步骤&#xff1a; ①、定义主设备号&#xff1a; 在Linux中&#xff0c;每个字符设备都…

MySQL 通过 systemd 启动时 hang 住了……

mysqld&#xff1a;哥&#xff0c;我起不来了…… 作者&#xff1a;贲绍华&#xff0c;爱可生研发中心工程师&#xff0c;负责项目的需求与维护工作。其他身份&#xff1a;柯基铲屎官。 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编…

如何查看页面对应的Selenium定位参数

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

谷歌外链怎么发?

既要数量也要质量&#xff0c;要保证你的链接广泛分布&#xff0c;在数量上&#xff0c;确实需要你的链接在各种平台上有所展现&#xff0c;这样能提升你网站的知名度和曝光率&#xff0c;但是&#xff0c;光有数量是不够的&#xff0c;如果这些链接的内容不行&#xff0c;那对…

泰迪智能科技企业数据挖掘流程分析及特色服务优势

企业发展会沉淀大量的数据&#xff0c;数据中囊括了企业业务各种维度指标&#xff0c;通过数据挖掘和数据分析 &#xff0c;让企业业务了解过去、现在和未来将要发生什么&#xff0c;从而更好的调整企业发展方向。泰迪智能科技企业数据挖掘平台是面向企业级用户快速处理数据构建…

2024年湖北省专升本C语言程序设计大题真题解析

2024年湖北省的专升本考试已于4月30日举行&#xff0c;考试中&#xff0c;出现了许多不同的考试题目&#xff0c;我在网上找到一所高校专升本的大题&#xff08;好像是湖北师范的&#xff0c;后续会有湖北理工的大题真题解析&#xff0c;敬请期待&#xff09;&#xff0c;那么我…

在新页面中跳转到指定 div容器位置

要在打开新的页面时跳转到指定 div&#xff0c;我们需要结合 HTML、JavaScript 和后端技术来实现。以下是两种常见的方法&#xff1a; 使用 URL 参数传递目标 div 信息 HTML (新页面): 在新页面的链接中&#xff0c;添加参数来指示目标 div 的 id&#xff0c;例如&#xff1a;…

致远M3 Session 敏感信息泄露漏洞复现

0x01 产品简介 M3移动办公是致远互联打造的一站式智能工作平台,提供全方位的企业移动业务管理,致力于构建以人为中心的智能化移动应用场景,促进人员工作积极性和创造力,提升企业效率和效能,是为企业量身定制的移动智慧协同平台。 0x02 漏洞概述 致远M3 server多个日志文…

Vue3自定义指令封装-按钮权限控制v-permission、hasPermissions

背景&#xff1a;平常所接触到的系统权限控制&#xff0c;大部分都是菜单、路由级别的控制&#xff0c;但后台管理系统中&#xff0c;很多操作都是与职责和角色挂钩的&#xff0c;同样一个列表&#xff0c;不同人的操作列并不都一样&#xff0c;有些页面存在一些含有重要数据的…

万物生长大会 | 创邻科技再登杭州准独角兽榜单

近日&#xff0c;由民建中央、中国科协指导&#xff0c;民建浙江省委会、中国投资发展促进会联合办的第八届万物生长大会在杭州举办。 在这场创新创业领域一年一度的盛会上&#xff0c;杭州市创业投资协会联合微链共同发布《2024杭州独角兽&准独角兽企业榜单》。榜单显示&…

MathType2024官方版数学公式编辑器功能全面介绍

在数字化学习和科研的浪潮中&#xff0c;数学公式的编辑与展示成为了不可或缺的一部分。MathType&#xff0c;作为一款专业的数学公式编辑器&#xff0c;凭借其强大的功能和便捷的操作&#xff0c;为科研人员、教师、学生等广大用户提供了极大的便利。下面&#xff0c;我们将对…

基于.NET WinForms 数据CURD功能的实现

使用开发工具 VS 2022 C#&#xff0c;数据库MS SQL SERVER 2019 &#xff0c;基于NET WinForms&#xff0c;实现数据记录的创建(Create)、更新(Update)、读取(Read)和删除(Delete)等功能。主要控件包括&#xff1a;DataGridView&#xff0c;SqlDataApater &#xff0c; DataTab…

字符以及字符串函数

字符以及字符串函数 求字符串长度strlen 长度不受限制的字符串函数strcpystrcatstrcmp 长度受限制的字符串函数strncpystrncatstrncmp 字符串查找strstrstrtok 错误信息报告strerror 字符分类函数字符转换函数tolowertoupper 内存操作函数memcpymemmovememcmpmemset 这篇文章注…

软件开发故事 - 我对 CTO 撒谎并挽救了项目

原文&#xff1a;GrumpyOldDev - 2024.04.18 这是几年前的事情了。还记得在我职业生涯的初期&#xff0c;父亲曾告诉我&#xff0c;做好工作往往意味着要在上司的阻碍下做好需要做的事情。他的意思是&#xff0c;你可以让上司成功并感到快乐&#xff1b;也可以让上司做每一个决…

Linux的编译器

程序编译的过程 程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程涉及多个阶段&#xff0c;主要包括预处理、编译、汇编和链接。下面详细介绍每个阶段&#xff1a; 1. 预处理&#xff08;Preprocessing&#xff09; 在实际编译之前&#xff0c;源代码文件首…

让云上用户拥有安全感 可信或成云服务器标配安全能力之一!

什么是虚拟主机 虚拟主机就是利用网络空间技术&#xff0c;把一台服务器分成许多的“虚拟”的主机&#xff0c;每一台网络空间都具有独立的域名和IP地址&#xff0c;具有完整的Internet服务器功能。网络空间之间完全独立&#xff0c;在外界看来&#xff0c;每一台网络空间和一台…

gpustat 不能使用问题

突然间就不能用了&#xff0c;可能是环境出了问题&#xff0c;如果GPU没问题的话&#xff0c;那么换个环境重新安装试一下&#xff08;pip install gpustat&#xff09;&#xff0c;目前是换个环境就可以了&#xff08;做个笔记&#xff09;

【神器来袭】快速解放双手,朋友圈自动转发工具,告别繁琐操作!

朋友圈作为一个重要的营销推广渠道&#xff0c;如果能实现自动转发&#xff0c;那对于很多企业或个人来说&#xff0c;是极好的。下面&#xff0c;就给大家分享一个实用且便捷的朋友圈运营工具——个微管理系统&#xff0c;让大家都能快速推广。 1、多账号登录&#xff0c;定时…

企业如何有效做好源代码防泄密工作之九种干货分享

企业为解决源码泄密风险问题&#xff0c;许多单位采取拆除光驱软驱、封掉USB接口、限制上网等方法来进行限制&#xff1b;或者安装一些监控软件&#xff0c;监控员工的日常工作&#xff0c;使其不敢轻举妄动&#xff1b;或者安装各种网络信息安全防护产品&#xff0c;如防火墙&…