3D激光SLAM:ALOAM---后端lasermapping 里程计到地图位姿更新维护

简介: 在上一篇[博客](https://www.guyuehome.com/38662)(ALOAM:后端lasermapping通过Ceres进行帧到地图的位姿优化)中,通过Ceres优化得到了 **当前帧到地图的最优位姿**下面要做的是更新地图模块中维护的一个位姿,这个位姿就是**odom到map之间的位姿变换**。**为什么要更新这个位姿呢?**因为在前面[这篇](https://www.guyuehome.com/38611)博客中(ALOAM:后端laserMapping代码结构与数据处理分析),在收到前端里程计数据后,会以前端里程计的频率,向外发布一个高频率当前帧到地图坐标系下

前言

在上一篇博客(ALOAM:后端lasermapping通过Ceres进行帧到地图的位姿优化)中,通过Ceres优化得到了 当前帧到地图的最优位姿

下面要做的是更新地图模块中维护的一个位姿,这个位姿就是odom到map之间的位姿变换

为什么要更新这个位姿呢?
因为在前面这篇博客中(ALOAM:后端laserMapping代码结构与数据处理分析),在收到前端里程计数据后,会以前端里程计的频率,向外发布一个高频率当前帧到地图坐标系下的位姿。
在这里插入图片描述
这这里用到了T_map_odom,就是在后端通过Ceres得到当前帧到map的位姿后,再计算odom到map的位姿,所以要更新这个位姿,为下一帧做准备。

并且在进行栅格地图位置更新处理的时候,也通过上一帧维护的T_map_odom,得到当前帧的一个初值估计。所以得到当前帧到map的位姿后,需要更新odom到map的位姿,为下一帧的处理做准备。相关内容在这篇博客(ALOAM:后端lasermapping地图栅格化处理与提取)的这个地方:
在这里插入图片描述

odom到map之间的位姿更新原理

通过Ceres的优化 得到了,当前帧到map的位姿变换
在这里插入图片描述
前端里程计向后端发布的是,当前帧到odom的位姿变换
在这里插入图片描述
那么计算odom到map的位姿变换的公式为:
在这里插入图片描述
写成旋转+平移的齐次矩阵的形式,上面的公式则变为:
在这里插入图片描述
那么 odom到map之间旋转和平移则为
在这里插入图片描述

下面来看ALOAM中代码是如何实现的

代码解析

在前面通过ceres的优化得到了 当前帧到地图的位姿变换。该位姿变换存在 parameters 变量中。

这个parameters是一个double 的7维数组
在这里插入图片描述
前4位是旋转四元数,后三位是平移向量

然后程序则调用了

            //更新odom到map之间的位姿变换
            transformUpdate();

这个就是更新odom到map之间的位姿变换的函数。

里面的内容是:

//更新odom到map之间的位姿变换
void transformUpdate()
{
   
    q_wmap_wodom = q_w_curr * q_wodom_curr.inverse();
    t_wmap_wodom = t_w_curr - q_wmap_wodom * t_wodom_curr;
}

其中

  • q_wmap_wodom 就是 odom到map 的旋转 四元数
  • t_wmap_wodom 就是 odom到map 的平移

q_wodom_curr 是前端里程计发来的 curr到odom的 旋转四元数
t_wodom_curr 是前端里程计发来的 curr到odom的 平移

  • q_w_curr 是Ceres优化的 curr到map的旋转四元数
  • t_w_curr 是Ceres优化的 curr到map的平移

在整个程序中并没有发现q_w_curr 和 t_w_curr 被赋值的地方,尤其是ceres计算完后并没给这两个变量赋值。

那么这两个变量是如何被赋值的呢?
在它俩声明的地方:
在这里插入图片描述
是通过eigen的map声明的
当ceres 更新 parameters之后 会通过 eigen的map 实时更新q_w_curr和t_w_curr 不需要自己再去转换

这里简单介绍下 Eigen 的Map 类:
Eigen中定义了一系列的vector和matrix,相比copy数据,更一般的方式是复用数据的内存,将它们转变为Eigen类型。Map类很好地实现了这个功能。

简单理解Map就是将原始“连续内存存储”的数据,以矩阵形式重新组织。在使用Map时就需要原始数据,Map后的数据的维度形式,Map时使用的Stride设定。所谓Stride,既指矩阵中沿着矩阵列或行方向移动一个位置,内存中需要移动的位置数。这个需要移动的内存位置数与矩阵采用的存储方式有关(列或行主导)。

Eigen::Map原型

template<typename PlainObjectType, int MapOptions, typename StrideType> 
class Map: public MapBase<Map<PlainObjectType, MapOptions, StrideType> >
  • PlainObjectType :映射数据的等价矩阵类型
  • MapOptions:指定指针对齐方式,默认是未对齐的
  • StrideType:指定步长

这个类的作用就是让非Eigen数据结构变成Eigenj矩阵或者向量时,减少在复制过程中的开销,Eigen官网描述这样使用没有开销。

构造函数有以下

Map (PointerArgType dataPtr, const StrideType &stride=StrideType())
Map (PointerArgType dataPtr, Index size, const StrideType &stride=StrideType())
Map (PointerArgType dataPtr, Index rows, Index cols, const StrideType &stride=StrideType())

举个最简单的例子

    int array[9];
    for (int i = 0; i < 9; ++i)
        array[i] = i;
    std::cout << Eigen::Map<Eigen::Matrix3i>(array) << std::endl;

输出为:
0 3 6
1 4 7
2 5 8
再举一个和ALOAM使用情况一样的例子,将一个数组元素转换成Eigen数据结构

int data[] = {
   1,2,3,4,5,6,7,8,9};
Map<RowVectorXi> v(data,4);
cout << "The mapped vector v is: " << v << "\n";
new (&v) Map<RowVectorXi>(data+4,5);
cout << "Now v is: " << v << "\n

输出为:
The mapped vector v is: 1 2 3 4
Now v is: 5 6 7 8 9

看了这几个例子,就明白,在Ceres优化完成后,这两个变量(q_w_curr ,t_w_curr )就被更新值了。

  • q_w_curr 是Ceres优化的 curr到map的旋转四元数
  • t_w_curr 是Ceres优化的 curr到map的平移

transformUpdate() 函数中计算的公式就是上面推导的:

    q_wmap_wodom = q_w_curr * q_wodom_curr.inverse();
    t_wmap_wodom = t_w_curr - q_wmap_wodom * t_wodom_curr;

在这里插入图片描述

在后面后端会把 q_w_curr,t_w_curr做为里程计更新发布出来

            nav_msgs::Odometry odomAftMapped;
            odomAftMapped.header.frame_id = "/camera_init";
            odomAftMapped.child_frame_id = "/aft_mapped";
            odomAftMapped.header.stamp = ros::Time().fromSec(timeLaserOdometry);
            odomAftMapped.pose.pose.orientation.x = q_w_curr.x();
            odomAftMapped.pose.pose.orientation.y = q_w_curr.y();
            odomAftMapped.pose.pose.orientation.z = q_w_curr.z();
            odomAftMapped.pose.pose.orientation.w = q_w_curr.w();
            odomAftMapped.pose.pose.position.x = t_w_curr.x();
            odomAftMapped.pose.pose.position.y = t_w_curr.y();
            odomAftMapped.pose.pose.position.z = t_w_curr.z();
            pubOdomAftMapped.publish(odomAftMapped);

在这里插入图片描述
可以在rviz中添加一个odometry的选项,选择topic为/aft_mapped_to_init来显示。

相关文章
|
前端开发 定位技术 索引
3D激光SLAM:ALOAM---后端 lasermapping构建角点约束与面点约束
后端的构建约束问题和前端不一样。原因就是前端从上一帧上去找,而后端是在局部地图上找,点要多很多,并且没有了线束信息,所以原理上不一样了。 **线特征的提取** 通过kdtree在局部地图中找到5个最近的线特征,为了判断他们是否符合线特征的特性,需要对5个点构成的协方差矩阵进行特征值分解,当上述5个点在一条直线上时,他们只有一个主方向,也就是特征值是一个大特征值,以及两个小特征值,大特征值对应的特征向量就是对应直线的方向向量。 **面特征的提取** 通过kdtree在地图中找到最近的面特征也是5个, 理论上也可以通过特种值分解的方式,最小的特征值对应的特征向量就是平面的法向量, 不过代码里选
3D激光SLAM:ALOAM---后端 lasermapping构建角点约束与面点约束
|
前端开发 数据可视化 定位技术
3D激光slam:ALOAM---后端lasermapping最终篇地图更新及消息发布
本篇为ALOAM后端的最终篇,地图更新及消息发布。 **地图更新原因:** - 当地图调整之后,栅格有些空着的,需要进行填充 - 保障地图的实时更新 - 当前帧的点云加到地图中去,下帧会有更多的匹配点
3D激光slam:ALOAM---后端lasermapping最终篇地图更新及消息发布
|
前端开发 算法 数据处理
激光SLAM:ALOAM---后端lasermapping数据处理低延时性保障操作
ALOAM方法实现了低的漂移,并且计算的复杂度低,实时性很好.并且不需要高精度的lidar和惯导 这个方法的核心思想就是把SLAM问题进行了拆分,通过两个算法来进行.一个是执行高频率的前端里程计但是低精度的运动估计(定位),另一个算法在比定位低一个数量级的频率执行后端建图(建图和校正里程计).
激光SLAM:ALOAM---后端lasermapping数据处理低延时性保障操作
|
编解码 算法 前端开发
激光SLAM:ALOAM---后端laserMapping代码结构与数据处理分析
ALOAM方法实现了低的漂移,并且计算的复杂度低,实时性很好.并且不需要高精度的lidar和惯导 这个方法的核心思想就是把SLAM问题进行了拆分,通过两个算法来进行.一个是执行高频率的**前端里程计**但是低精度的运动估计(定位),另一个算法在比定位低一个数量级的频率执行**后端建图**(建图和校正里程计). 这个两个算法都需要提特征点,就是经典的角点和面点,然后进行配准.在前端的那个算法中也就是里程计算法,特征点的提取会用到快速计算的方法.在建图的后端算法中,相互关联的特征点是通过特征值和特征向量来获得的.
激光SLAM:ALOAM---后端laserMapping代码结构与数据处理分析
|
18天前
|
存储 缓存 负载均衡
后端开发中的性能优化策略
本文将探讨几种常见的后端性能优化策略,包括代码层面的优化、数据库查询优化、缓存机制的应用以及负载均衡的实现。通过这些方法,开发者可以显著提升系统的响应速度和处理能力,从而提供更好的用户体验。
45 4
|
9天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
38 3
|
24天前
|
存储 前端开发 Java
深入理解后端开发:从基础到高级
本文将带你走进后端开发的神秘世界,从基础概念到高级应用,一步步揭示后端开发的全貌。我们将通过代码示例,让你更好地理解和掌握后端开发的核心技能。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的信息和启示。
|
27天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
23天前
|
运维 监控 Java
后端开发中的微服务架构实践与挑战####
在数字化转型加速的今天,微服务架构凭借其高度的灵活性、可扩展性和可维护性,成为众多企业后端系统构建的首选方案。本文深入探讨了微服务架构的核心概念、实施步骤、关键技术考量以及面临的主要挑战,旨在为开发者提供一份实用的实践指南。通过案例分析,揭示微服务在实际项目中的应用效果,并针对常见问题提出解决策略,帮助读者更好地理解和应对微服务架构带来的复杂性与机遇。 ####
|
22天前
|
消息中间件 运维 安全
后端开发中的微服务架构实践与挑战####
在数字化转型的浪潮中,微服务架构凭借其高度的灵活性和可扩展性,成为众多企业重构后端系统的首选方案。本文将深入探讨微服务的核心概念、设计原则、关键技术选型及在实际项目实施过程中面临的挑战与解决方案,旨在为开发者提供一套实用的微服务架构落地指南。我们将从理论框架出发,逐步深入至技术细节,最终通过案例分析,揭示如何在复杂业务场景下有效应用微服务,提升系统的整体性能与稳定性。 ####
34 1

热门文章

最新文章