(02)Cartographer源码无死角解析-(55) 2D后端优化→ComputeLocalToGlobalTransform()

news2024/11/24 5:35:41

讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下:
(02)Cartographer源码无死角解析- (00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/127350885
 
文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX官方认证
 

一、前言

现在开始,以PoseGraph2D::AddNode()为线索,进行展开,对 PoseGraph2D 中所有函数进行细节分析。关于 PoseGraph2D::AddNode() 的大致流程在上一篇博客中有纤细讲解,其包含了如下代码:

 // local系下的位姿变换到global系下
  const transform::Rigid3d optimized_pose(
      GetLocalToGlobalTransform(trajectory_id) * constant_data->local_pose);

代码功能是将local系下的位姿变换到global系下,很容易看出,其核心部分就是关于 GetLocalToGlobalTransform(trajectory_id) 函数的调用。从命名来看,该函数的作用就是传入一个 trajectory_id,获得其轨迹对应的一个变换矩阵,如果左乘该矩阵,可以将local系下的位姿变换至Global系,这里记该矩阵为 R l o c a l g l o b a l \mathbf R_{local}^{global} Rlocalglobal,在local系下的位姿 constant_data->local_pose 为 R o b o t l o c a l t r a c k i n g \mathbf {Robot}_{local}^{tracking} Robotlocaltracking,以及global系下机器人位姿记为 R o b o t t r a c k i n g g l o b a l \mathbf {Robot}_{tracking}^{global} Robottrackingglobal ,那么等价于上述代码数学公式:
R o b o t t r a c k i n g g l o b a l = R l o c a l g l o b a l ∗ R o b o t t r a c k i n g l o c a l (01) \color{Green} \tag{01} \mathbf {Robot}_{tracking}^{global}=\mathbf R_{local}^{global}*\mathbf {Robot}_{tracking}^{local} Robottrackingglobal=RlocalglobalRobottrackinglocal(01)

二、ComputeLocalToGlobalTransform

顺着上面的思路,GetLocalToGlobalTransform(trajectory_id) 函数同样在pose_graph_2d.cc中实现,代码如下所示:

// 计算 global frame 指向 local frame 的坐标变换
transform::Rigid3d PoseGraph2D::GetLocalToGlobalTransform(
    const int trajectory_id) const {
  // 可能同时间有多个线程调用这同一个函数, 所以要加锁
  absl::MutexLock locker(&mutex_);
  return ComputeLocalToGlobalTransform(data_.global_submap_poses_2d,
                                       trajectory_id);
}

其代码还是比较简单的,就是上锁然后调用 PoseGraph2D::ComputeLocalToGlobalTransform() 函数,该函数接受两个参数,第一个参数 data_.global_submap_poses_2d 声明如下:

  // Global submap poses currently used for displaying data.
  // submap 在 global 坐标系下的坐标
  MapById<SubmapId, optimization::SubmapSpec2D> global_submap_poses_2d;
  MapById<SubmapId, optimization::SubmapSpec3D> global_submap_poses_3d;

总的来说 global_submap_poses_2d 存储了所有2D子图在global系下的位姿,如果对 MapById 不好理解,暂时把其看作一个map或者说字典,其中key为SubmapId,value是该对应子图global下位姿。总的来说,data_.global_submap_poses_2d 包含了所有子图在 global 系下的位姿。

ComputeLocalToGlobalTransform() 函数接收第二个实参是 trajectory_id,从命名来看,可以知道,该函数主要功能就是计算local系坐标到global系坐标的变变换矩阵 R l o c a l g l o b a l \mathbf R_{local}^{global} Rlocalglobal,那么其是如何计算的呢?

( 01 ) \color{blue}(01) (01) 形参global_submap_poses中包含了所有子图在global系下的位姿,key为SubmapId类型,其存在成员变量SubmapId::trajectory_id与SubmapId::submap_index。总来说,global_submap_poses 中包含所有轨迹的所有子图位姿。所以通过key获取子图位姿时,需要指定轨迹id,以及子图索引。

( 2 ) \color{blue}(2) (2) 原来中首先根据 trajectory_id 从 global_submap_poses 获得其轨迹所有子图的起始迭代器begin_it,以及末尾迭代器end_it。

( 3 ) \color{blue}(3) (3)如果begin_i=end_it,说明该轨迹还没有任何子图,则返回轨迹在global系下的初始位姿,作为子图位姿。需要注意的是,初始位姿可以设定,也可以不设定,所以源码中先调用 data_.initial_trajectory_poses.find(trajectory_id)函数,根据trajectory_id查询初始位姿。如果找到,说明其进行了设置,调用 GetInterpolatedGlobalTrajectoryPose() 函数,使用插值的方式返回初始位姿(x轴为时间轴)。如果没有查询到,则说明没有设置,直接放回单位旋转矩阵及0平移。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VScode+cuda编程:常见环境问题

VScodecuda&#xff1a;常见环境配置问题1、VScode终端问题(PS)2、编译问题(CUDA版本过低)3、nvcc编译问题(arch架构)1、VScode终端问题(PS) 问题描述&#xff1a; 在VScode下打开终端执行nvcc指令&#xff0c;发现执行不了&#xff0c;但是在外部终端powershell和cmd都可以。…

波奇学c语言:代码的编译和链接

test.c&#xff08;源文件&#xff09;->编译->test.obj&#xff08;目标文件&#xff09;->链接->test.exe&#xff08;可执行文件&#xff09;编译1.预编译&#xff08;预处理&#xff09;&#xff1a;text.c->text.i使用gcc -E test.c 进行停止预处理指令&am…

Java修饰符和运算符,超详细整理,适合新手入门

目录 一、访问控制修饰符 1、访问权限 二、运算符 1、算术运算符 2、关系运算符 3、逻辑运算符 4、赋值运算符 5、三元运算符 一、访问控制修饰符 Java 支持 4 种不同的访问权限&#xff1a; private 私有的 protected 受保护的 public 公共的 default 默认 1、…

【手写 Vuex 源码】第九篇 - Vuex 响应式数据和缓存的实现

一&#xff0c;前言 上一篇&#xff0c;主要介绍了 Vuex 的 State 状态安装&#xff0c;主要涉及以下几个点&#xff1a; State 状态的安装逻辑&#xff1b;两个核心问题的思路&#xff1b;代码实现以及执行情况分析&#xff1b; 本篇&#xff0c;继续介绍 Vuex 模块相关概念…

计算机组成原理(五)

3.理解主存储器与CPU的连接原理&#xff1b;   主存通过数据总线、地址总线和控制总线与CPU连接&#xff1b;   数据总线的位数与工作频率的乘积正比于数据传输率&#xff1b;   地址总线的位数决定了可寻址的最大内存空间&#xff1b;   控制总线&#xff08;读/写&am…

excel操作实例:如何制作一个学习计划阶段图表

预则立不预则废。不管是为了避免被裁员的窘迫&#xff0c;还是为了获得更高的薪水&#xff0c;都有必要在2023年尽快学精Excel&#xff0c;成为行业高手。教程把要成为Excel高手的几道坎&#xff0c;也是要攻克的目标做成图表&#xff0c;希望大家的努力更有效。要变成Excel高手…

Redis 缓存穿透、缓存击穿和缓存雪崩

Redis 缓存穿透和缓存雪崩 缓存穿透和缓存雪崩这两个概念和知识点我们一定要掌握&#xff0c;因为我们工作中经常会遇到缓存穿透和缓存雪崩的情况。 Redis 缓存穿透&#xff08;查不到&#xff09; 缓存穿透是指客户端请求一个缓存和数据库中都不存在的 key。由于缓存中不存在…

【遇见青山】项目难点:集群下的分布式锁问题

【遇见青山】项目难点&#xff1a;集群下的分布式锁问题1.问题简介2.分布式锁分析3.基于Redis实现分布式锁1.0版本4.基于Redis实现分布式锁2.0版本&#xff0c;解决锁误删问题5.基于Redis实现分布式锁3.0版本&#xff0c;解决锁的原子性问题1.问题简介 在《【遇见青山】项目难…

Sliver取代Cobalt Strike成黑客渗透工具“新宠”

8月25日消息&#xff0c;攻击者逐渐弃用Cobalt Strike渗透测试套件&#xff0c;转而使用不太知名的类似框架。开源跨平台工具Sliver正取代Brute Ratel成为受攻击者青睐的武器。 在过去的几年里&#xff0c;Cobal Strike被各类攻击者滥用&#xff08;包括勒索软件操作&#xff…

行为型模式 - 模板方法模式Template Method

学习而来&#xff0c;代码是自己敲的。也有些自己的理解在里边&#xff0c;有问题希望大家指出。 模式的定义与特点 模板方法&#xff08;Template Method&#xff09;&#xff0c;模式的定义如下&#xff1a;定义一个操作中的算法骨架&#xff0c;而将算法的一些步骤延迟到子类…

JavaSE XML解析技术的使用详解

文章目录XML解析技术XML解析技术介绍Dom4j解析XML文件Dom4j解析各个节点Dom4j解析案例实战XML解析技术 XML解析技术介绍 XML的数据作用是什么? 最终需要怎样处理? 作用: 存储数据、做配置信息、进行数据传输。 最终需要被程序进行读取&#xff0c;解析里面的信息。 XML解析…

【路径规划】基于A*算法和Dijkstra算法的路径规划(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Python蓝桥杯训练:基本数据结构 [链表]

Python蓝桥杯训练&#xff1a;基本数据结构 [链表] 文章目录Python蓝桥杯训练&#xff1a;基本数据结构 [链表]一、链表理论基础知识二、有关链表的一些常见操作三、力扣上面一些有关链表的题目练习1、[移除链表元素](https://leetcode.cn/problems/remove-linked-list-element…

TCP报头详解及TCP十种核心机制(一)

目录 前言&#xff1a; TCP报头 TCP核心机制 一、确认应答 二、超时重传 小结&#xff1a; 前言&#xff1a; 这篇文章详细介绍了TCP报头中的一些核心数据&#xff0c;及两种TCP核心机制。其他的一些机制会在后面文章中详细介绍。 TCP报头 解释&#xff1a; 1&#xff…

电商仓储与配送云仓是什么?

仓库是整个供给链的关键局部。它们是产品暂停和触摸的点&#xff0c;耗费空间和时间(工时)。空间和时间反过来也是费用。经过开发数学和计算机模型来微调仓库的规划和操作&#xff0c;经理能够显著降低与产品分销相关的劳动力本钱&#xff0c;进步仓库空间应用率&#xff0c;并…

docker/docker-compose 安装mysql5.7

目录使用docker安装mysql5.7docker普通安装docker生产环境安装使用docker-compose 安装注意注意一:docker-compose权限问题注意二:docker pull 找不到镜像使用docker安装mysql5.7 docker普通安装 docker pull mysql:5.7 # 启动容器 docker run -p 3306:3306 --name mysql -e …

数组和对象的拷贝(复制)

复制必须要产生新的对象。以下代码不是复制。 const arr ["孙悟空", "猪八戒", "沙和尚"]const arr2 arr // 不是复制&#xff0c;只是将arr的值赋给arr2&#xff0c;他们指的还是一个对象console.log(arr) // 二者输出一样 console.log(…

数楼梯(加强版)

数楼梯(加强版) 题目背景: 小明一天放学回家,看到从1楼到2楼共有n个台阶,因为好奇,他想尝试一下总共有几种方案到二楼?他可以1步,2步,3步的跳,不能跳3步以上. 他试了很多次都没有解决这个问题,于是请求聪明的你帮忙解决这个问题. 题目描述: 1楼到2楼楼梯有n级台阶。小明每…

Learning C++ No.8【内存管理】

引言&#xff1a; 北京时间&#xff1a;2023/2/12/18:04&#xff0c;昨天下午到达学校&#xff0c;摆烂到现在&#xff0c;该睡睡&#xff0c;该吃吃&#xff0c;该玩玩&#xff0c;在一顿操作之下&#xff0c;目前作息调整好了一些&#xff0c;在此记录&#xff0c;2月11&…

C++基础(6) - 复合类型(下)

文章目录指针1、指针概述1.1 存储器和存储地址空间1.2 内存地址1.3 指针和指针变量2、声明和初始化指针变量2.1 指针变量的声明2.2 指针变量的初始化3、使用指针变量3.1 解除引用3.2 野指针和空指针4、指针的宽度和跨度4.1 自身类型和指向类型4.2 指针变量所取内容的宽度4.3 指…