cartographer全局重定位的实现

ops/2025/1/15 5:51:58/

cartographer全局重定位的实现

  • 1.简介
    • 核心流程
    • 链接代码:

1.简介

本博客主要介绍cartographer全局重定位的实现,目前已经测试能够实现在6米180度范围内的全局重定位。

核心流程

这个重定位函数的流程,然后逐个部分给出实现代码。

1.创建线程池;
2.点云过一次体素滤波;
3.为每一个 Submap 创建 FastCorrelativeScanMatcher 匹配器,在线程池中执行,并等待所有匹配器创建完成;
4.遍历每一个匹配器,调用 MatchFullSubmap 方法,记录匹配结果和分数,在线程池中执行,并等待所有匹配完成;
5.找出匹配得分最高的位姿,创建 CeresScanMatcher2D 匹配器再次匹配得到准确的位姿。

实现代码如下:

bool PoseGraph2D::PerformGlobalLocalization(cartographer::sensor::PointCloud laser_point_cloud,float cutoff, transform::Rigid2d* best_pose_estimate, float* best_score)
{auto my_thread_pool = std::make_unique<common::ThreadPool>(std::thread::hardware_concurrency());assert(my_thread_pool != nullptr);LOG(INFO) << "laser_point_cloud.points_.size()1 : " << laser_point_cloud.points().size();const cartographer::sensor::PointCloud filtered_point_cloud = cartographer::sensor::VoxelFilter(laser_point_cloud, 0.05);  // const cartographer::sensor::PointCloud filtered_point_cloud = match_point_cloud_;if (filtered_point_cloud.empty()) {LOG(ERROR) << "Filtered point cloud is empty!";return false;}LOG(INFO) << "filtered_point_cloud.points_.size() : " << filtered_point_cloud.points().size();LOG(INFO) << "cutoff : " << cutoff;int32_t submap_size = static_cast<int>(data_.submap_data.size());absl::BlockingCounter created_counter{submap_size};std::vector<std::shared_ptr<scan_matching::FastCorrelativeScanMatcher2D>> matchers(submap_size);std::vector<const cartographer::mapping::Grid2D*> submaps(submap_size);LOG(INFO) << "Submap size: " << submap_size;size_t index = 0;for (const auto& submap_id_data : data_.submap_data) {if (submap_id_data.id.trajectory_id != 0) {created_counter.DecrementCount();continue;}auto task = absl::make_unique<common::Task>();task->SetWorkItem([this, &matchers, &created_counter, index, submap_id = submap_id_data.id, &submaps] {try {const auto& submap_data = data_.submap_data.at(submap_id);if (!submap_data.submap) {LOG(ERROR) << "Submap is null for index " << index;throw std::runtime_error("Submap is null");}submaps[index] = static_cast<const Submap2D*>(submap_data.submap.get())->grid();matchers[index] = std::make_unique<scan_matching::FastCorrelativeScanMatcher2D>(*submaps[index],options_.constraint_builder_options().fast_correlative_scan_matcher_options());LOG(INFO) << "Task completed for index: " << index;} catch (const std::exception& e) {LOG(ERROR) << "Error in task for index " << index << ": " << e.what();}created_counter.DecrementCount();});my_thread_pool->Schedule(std::move(task));index++;}LOG(INFO) << "Total submaps processed: " << index;created_counter.Wait();LOG(INFO) << "PoseGraph2D::PerformGlobalLocalization 728.";size_t matcher_size = index;std::vector<float> score_set(matcher_size, -std::numeric_limits<float>::infinity());std::vector<transform::Rigid2d> pose_set(matcher_size);    absl::BlockingCounter matched_counter{matcher_size};std::atomic_bool has_matched{false};    for (size_t i = 0; i < matcher_size; i++) {auto task = absl::make_unique<common::Task>();task->SetWorkItem([i, &filtered_point_cloud, &matchers, &score_set, &pose_set, cutoff, &matched_counter, &has_matched] {if (!matchers[i]) {LOG(ERROR) << "Matcher is null at index " << i;matched_counter.DecrementCount();return;}float score = -1;transform::Rigid2d pose_estimate = transform::Rigid2d::Identity();LOG(INFO) << "Processing2 matcher index: " << i;try {if (matchers[i]->MatchFullSubmap(filtered_point_cloud, cutoff, &score, &pose_estimate)) {score_set[i] = score;pose_set[i] = pose_estimate;has_matched = true;} else {LOG(INFO) << "match failed. ";}} catch (const std::exception& e) {LOG(ERROR) << "Exception in MatchFullSubmap at index " << i << ": " << e.what();}matched_counter.DecrementCount();});my_thread_pool->Schedule(std::move(task));}matched_counter.Wait();if (!has_matched) {LOG(ERROR) << "No matches found!";return false;}int max_position = std::distance(score_set.begin(), std::max_element(score_set.begin(), score_set.end()));*best_score = score_set[max_position];*best_pose_estimate = pose_set[max_position];auto csm = std::make_unique<scan_matching::CeresScanMatcher2D>(options_.constraint_builder_options().ceres_scan_matcher_options());ceres::Solver::Summary unused_summary;try {csm->Match(best_pose_estimate->translation(), *best_pose_estimate,filtered_point_cloud, *submaps[max_position],best_pose_estimate, &unused_summary);} catch (const std::exception& e) {LOG(ERROR) << "CeresScanMatcher2D failed: " << e.what();return false;}LOG(INFO) << "PoseGraph2D::PerformGlobalLocalization end.";return true;
}

链接代码:

https://github.com/zkk123456/cartographer_global_relocation.git


http://www.ppmy.cn/ops/150216.html

相关文章

DevOps实用场景:在哪些业务中应用DevOps最有效

随着科技的迅猛发展和客户需求的不断变化&#xff0c;IT初创公司在不断追求更高的效率、更快速的交付和更强的市场适应力。在这个背景下&#xff0c;DevOps成为了推动组织成功的关键策略之一。本文将帮助您了解什么是DevOps&#xff0c;哪些团队或企业最适合实施DevOps&#xf…

mybatis-spring @MapperScan走读分析

接上一篇文章&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145100531&#xff0c; 本文注解分析mybatis-spring中的MapperScan注解&#xff0c;则将容易许多。 目录 MapperScan注解定义ConfigurationClassPostProcessor扫描注册beanDefinitionorg.mybatis.s…

ansible之playbook实战

环境&#xff1a; client centos server ubuntu cat pro1.yml --- - hosts: www.test.comtasks:- name: Install Httpd Serverapt: nameapache2 statepresent- name: Configurate Httpd Servercopy: content"Iam client" dest/var/www/html/index.html- name: Start…

React方向:react中5种Dom的操作方式

1、通过原生JS获取Dom去操作 通过document.querySelector(#title)原生js的方式去拿到dom节点&#xff0c;然后去进行操作。 import {Component} from "react";class App extends Component {//定义获取Dom的函数handleGetDom(){let title document.querySelector(#t…

Notepad++上NppFTP插件的安装和使用教程

一、NppFTP插件下载 图示是已经安装好了插件。 在搜索框里面搜NppFTP&#xff0c;一般情况下&#xff0c;自带的下载地址容易下载失败。这里准备了一个下载连接&#xff1a;Release v0.29.10 ashkulz/NppFTP GitHub 这里我下载的是x86版本 下载好后在nodepad的插件里面选择打…

ASP.NET Core - 依赖注入(四)

ASP.NET Core - 依赖注入&#xff08;四&#xff09; 4. ASP.NET Core默认服务5. 依赖注入配置变形 4. ASP.NET Core默认服务 之前讲了中间件&#xff0c;实际上一个中间件要正常进行工作&#xff0c;通常需要许多的服务配合进行&#xff0c;而中间件中的服务自然也是通过 Ioc…

Java学习,集合遍历

Java遍历集合&#xff08;如List, Set, Map等&#xff09;通常有多种方法。遍历集合的方式&#xff0c;包括传统for循环、增强的for循环&#xff08;也称"for-each"循环&#xff09;、迭代器&#xff08;Iterator&#xff09;以及流&#xff08;Stream&#xff09;AP…

Mysql--运维篇--备份和恢复(逻辑备份,mysqldump,物理备份,热备份,温备份,冷备份,二进制文件备份和恢复等)

MySQL 提供了多种备份方式&#xff0c;每种方式适用于不同的场景和需求。根据备份的粒度、速度、恢复时间和对数据库的影响&#xff0c;可以选择合适的备份策略。主要备份方式有三大类&#xff1a;逻辑备份&#xff08;mysqldump&#xff09;&#xff0c;物理备份和二进制文件备…