2D 激光 SLAM-Cartographer 实战

源码

https://github.com/cartographer-project/cartographer
https://github.com/cartographer-project/cartographer_ros
课 程 下 的 注 释 版 代 码 :
https://github.com/xiangli0608/cartographer_detailed_comments_ws
备用地址:
https://gitee.com/LauZanMo/cartographer
https://gitee.com/xiaojake/cartographer_ros
论文地址:https://ieeexplore.ieee.org/document/7487258
cartographer 整体可以分为三个部分:
一是 input sensor data,也就是读取单线激光雷达的 scan、轮速计的输入以及 IMU,
二是 Local SLAM 部分,也被称为前端。 该部分的主要任务是建立维护子地图(Submaps),
但 问 题 是 该 部 分 建 图 误 差 会 随 着 时 间 累 积 。 该 部 分 相 关 的 参 数 定 义 在
/src/cartographer/configuration_files/trajectory_builder_2d.lua
/src/cartographer/configuration_files/trajectory_builder_3d.lua 中。
三是 Global SLAM 部分,也称为后端. 该部分的主要任务是进行 Loop Closure。闭环检测本
质上也是一个优化问题,文中将其表达成了 pixel-accurate match 的形式,采用 Branch-and
Bound Approach (BBA)的方法来解决。具体使用 Branch-and-Bound 方法,可以参见论
Real-Time Loop Closure in 2D LIDAR
SLAM(https://ieeexplore.ieee.org/document/7487258)。如果是 3D 情况下,该部分还负责根
据 IMU 数据找出重力的方向。
可以看出,从传感器出发,Laser 的数据经过两个滤波器后进行 Scan Matching,用来构建子
图 submap, 而新的 Laser Scan 进来后也会插入到已经维护着的子图的适当位置。如何决定
插入的最优位姿,就是通过 Ceres Scan Matching 来实现的。估计出来的最优位姿也会与里
程计和 IMU 数据融合,用来估计下一时刻的位姿。
总体而言,Local Slam 部分负责生成较好的子图,而 Global Slam 部分进行全局优化,将不
同的子图以最匹配的位姿连接在一起。

Cartographer 安装编译与 demo 运行

#下载 https://github.com/abseil/abseil-cpp
cd abseil-cpp
mkdir build && cd build
cmake ..
make
sudo make install
# 安装 abseil 的动态库:可以将之前的 build 文件夹删掉,重新建立 build 文
件夹
mkdir build && cd build
cmake .. -DBUILD_SHARED_LIBS=ON
make
sudo make install
#安装其他依赖
sudo apt-get update
sudo apt-get install -y python-wstool python-rosdep ninja-build
sudo apt-get install cmake
sudo apt-get install build-essential
sudo apt-get install libgoogle-glog-dev
sudo apt-get install libatlas-base-dev
# 创建 cartographer_ws 工作空间,并将以下三个链接都拷到 src 文件夹里:
# https://github.com/cartographer-project/cartographer
# https://github.com/cartographer-project/cartographer_ros
# https://github.com/ceres-solver/ceres-solver
#编译 ceres
cd ceres-solver
mkdir ceres-bin
cd ceres-bin
cmake ..
make
make test
sudo make install
#安装 protobuf3 https://github.com/protocolbuffers/protobuf/releases
cd protobuf
mkdir build
cd build
cmake -G Ninja \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
cvlife.net -DCMAKE_BUILD_TYPE=Release \
-Dprotobuf_BUILD_TESTS=OFF \
../cmake
ninja
sudo ninja install
#构建 cartographer 工作空间
mkdir -p cartographer_ws/src
cd cartographer_ws/src
catkin_init_workspace
#cartographer 编译
cd cartographer_ws
rosdep update
rosdep install --from-paths src --ignore-src --
rosdistro=${ROS_DISTRO} -y
#Build and install.这一步会花费很长的时间,耐心等待
catkin_make_isolated --install --use-ninja
source install_isolated/setup.bash
#运行测试
wget -P ~/Downloads https://storage.googleapis.com/cartographer
public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag
roslaunch cartographer_ros demo_backpack_2d.launch
bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag

Cartographer 保存轨迹

#保存轨迹
#思路:在使用 cartographer 建图的过程中,找到 cartographer 提供的
“/trajectory_query” 服务(可以用“rosrun rqt_service_caller
rqt_service_caller”命令),请求后会得到当前轨迹每一帧的位姿。在源码
中找到这部分内容,将其保存为 txt 文件即可。
#方法:源码 node.cc 中,修改 HandleTrajectoryQuery 函数:
bool Node::HandleTrajectoryQuery(
::cartographer_ros_msgs::TrajectoryQuery::Request& request,
::cartographer_ros_msgs::TrajectoryQuery::Response& response) {
cvlife.net absl::MutexLock lock(&mutex_);
response.status = TrajectoryStateToStatus(
request.trajectory_id,
{TrajectoryState::ACTIVE, TrajectoryState::FINISHED,
TrajectoryState::FROZEN} /* valid states */);
if (response.status.code != cartographer_ros_msgs::StatusCode::OK)
{
LOG(ERROR) << "Can't query trajectory from pose graph: "
<< response.status.message;
return true;
}
map_builder_bridge_.HandleTrajectoryQuery(request, response);
// 保存轨迹为 txt 文件
std::cout << "receiving" << std::endl;
std::string txt_filename = "/home/xxx/xxx.txt";
std::ofstream outf(txt_filename, std::ios::app);
for (int i = 0; i < response.trajectory.size(); i++){
int32_t sec = response.trajectory[i].header.stamp.sec;
int32_t nsec = response.trajectory[i].header.stamp.nsec;
double x = response.trajectory[i].pose.position.x;
double y = response.trajectory[i].pose.position.y;
double z = response.trajectory[i].pose.position.z;
outf << std::setprecision(20) << sec << "." << nsec << " " << x
<< " " << y << " " << z << std::endl;
}
return true;
}
rosrun rqt_service_caller rqt_service_caller
#选择/trajectory query 即可
#评估
evo_ape tum gt.txt result.txt -vap
#通常使用绝对轨迹误差的 RMSE 来衡量算法的定位精度
#保存 pgm 珊格地图
rosrun map_server map_saver
传感器实测方法及常见问题
参考 https://blog.csdn.net/weixin_44314245/article/details/110881565
https://blog.csdn.net/Darcy_MFFL/article/details/112433149
https://blog.csdn.net/weixin_42576673/article/details/107280930

Cartographer 工程化建议

rplidar 适配 cartographer 的方式:
1.修改 cartgrapher_ros/cartprapher_files 下的 revo_lds.lua 文件,把下面的两个配置选项替换
成“laser”
tracking_frame = "laser",
published_frame = "laser"
2.修改 cartographer_ros 下的 demo_revo_lds.launch 文件
<launch>
<param name="/use_sim_time" value="flase" />
<!-- 首先是 rplidar 节点:因此必须保证是安装了 rplidar_ros -->
<node pkg="rplidar_ros" type="rplidarNode" name="rplidarNode"
output="screen">
<param name="serial_port" type="string"
value="/dev/ttyUSB0"/>
<param name="serial_baudrate" type="int" value="265000"/>
<param name="frame_id" type="string" value="laser"/>
<param name="inverted" type="bool" value="false"/>
<param name="angle_compensate" type="bool" value="true"/>
</node>
<!-- 然后是 cartographer 节点:他在这里调用了 revo_lds.lua 文件,这个文
件我修改了 首先把 “map”改成了“/map” -->
<node name="cartographer_node" pkg="cartographer_ros"
type="cartographer_node" args="
-configuration_directory $(find
cartographer_ros)/configuration_files
-configuration_basename revo_lds.lua"
output="screen">
<remap from="scan" to="scan" />
</node>
<node name="rviz" pkg="rviz" type="rviz" required="true"
args="-d $(find
cartographer_ros)/configuration_files/demo_2d.rviz" />"
</launch>
3.进入工作空间重新编译
catkin_make_isolated --install --use-ninja
4.启动
roslaunch cartographer_ros demo_revo_lds.launch
注释版的
cartographer
源 码 地 址 :
https://github.com/xiangli0608/cartographer_detailed_comments_ws

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

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

相关文章

复分析——第8章——共形映射(E.M. Stein R. Shakarchi)

第8章 共形映射(Conformal Mappings) The results I found for polygons can be extended under very general assumptions. I have undertaken this research because it is a step towards a deeper understanding of the mapping problem, for which not much has hap…

C++视觉开发 二.OpenCV基础

目录 本章记录OpenCV开发中的基本操作语法 一.基础 1.读取图像 2.显示图像 3.保存图像 二.图像 1.像素处理 2.彩色图像 三.滤波 1.高斯滤波&#xff08;Gaussian Blur&#xff09; 功能&#xff1a; 高斯滤波是一种常用的线性平滑滤波器&#xff0c;用于降低图像噪声…

绕过HTTP401和403响应限制工具

目录 介绍 开发语言 特征 动态 安装使用 参数 示例用法 工具地址 介绍 一种旨在自动化各种技术的工具,以绕过HTTP 401和403响应代码并访问系统中未授权的区域。此代码是为安全爱好者和专业人士只。使用它在您自己的风险。 开发语言 Python3 特征 探测HTTP 401和403…

关于嵌入式变量存储位置的思考

嵌入式软件中的变量存储比较灵活&#xff0c;可以将变量存储在内核中&#xff0c;此时变量的访问最快&#xff1b;也可以将变量存储在ram中&#xff0c;此时变量的访问速度次之&#xff1b;最后可以将变量存储于flash中&#xff0c;此时变量的访问速度最快。&#xff08;不考虑…

v-for中key的原理以及用法

在 Vue.js 中&#xff0c;v-for 指令用于基于源数据多次渲染元素或模板块。当使用 v-for 渲染列表时&#xff0c;为每个列表项提供一个唯一的 key 属性是非常重要的。key 的主要作用是帮助 Vue 跟踪每个节点的身份&#xff0c;从而重用和重新排序现有元素。 先来张原理图&#…

Batch文件中的文件移动指南:使用move命令的深度解析

Batch文件&#xff0c;也称为批处理脚本&#xff0c;是Windows操作系统中一种自动化执行一系列命令的脚本文件。使用Batch文件可以极大地提高工作效率&#xff0c;尤其是在需要重复执行相同命令序列的情况下。move命令是Batch文件中用于移动或重命名文件和目录的基本命令之一。…

开机弹窗缺失OpenCL.dll如何解决?分享5种靠谱的解决方法

在电脑使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“开机提示找不到OpenCL.dll”。那么&#xff0c;这个错误提示到底是怎么回事呢&#xff1f;它又对电脑有什么影响&#xff1f;我们又该如何解决这个问题并预防OpenCL.dll再次丢失呢&#xff1…

基于Ollama Python的本地多模态大模型

0&#xff0c;背景 最近测试Ollama&#xff0c;发现之前直接下载开源模型在我电脑上都跑不动的模型&#xff0c;居然也能运行了&#xff08;AMD 7840HS核显/32GB内存&#xff09;&#xff0c;突发奇想那些多模态大模型能不能基于Python接口使用&#xff0c;所以决定尝试一下。…

网页用事件监听器播放声音

一、什么是监听器&#xff1a; 在前端页面中&#xff0c;事件监听器&#xff08;Event Listener&#xff09;是一种编程机制&#xff0c;它允许开发者指定当特定事件&#xff08;如用户点击按钮、鼠标悬停、页面加载完成等&#xff09;发生时执行特定的代码块。简而言之&#x…

用Python实现的10种聚类算法汇总

前言 聚类是一种无监督学习问题。 它经常用来在输入数据的特征空间中寻找分组&#xff0c;例如基于顾客行为将消费者分组。 聚类算法有很多种&#xff0c;没有哪一种聚类算法适用于所有的问题。不过&#xff0c;有必要去探究多种聚类算法&#xff0c;以及每种算法的不同配置…

服务器上VMWare Workstation虚拟机声卡支持

问题&#xff1a;联想服务器没有声卡&#xff0c;Windows 服务器安装了VMWare Workstation&#xff0c;里面的Windows 11虚拟机&#xff0c;我远程桌面上来&#xff0c;没有声卡&#xff0c;但是我想做 声音方面的测试就没办法。 解决办法&#xff1a; 服务器主机上安装虚拟机…

Java 多线程编程:线程的基本概念

在现代计算中&#xff0c;多线程编程是一种常见且重要的技术。Java 提供了强大的多线程支持&#xff0c;使得开发者可以轻松地实现并发编程。本文将详细介绍 Java 中线程的基本概念&#xff0c;包括线程与进程的区别以及线程的生命周期。 线程和进程 首先&#xff0c;让我们了…

5.4符号三角形问题

#include<iostream> #include<stdio.h> using namespace std; int half; int ssum; int cnt0;//减号的个数 int n; int p[100][100]; int countt0; void BackTrack(int s) {if(cnt>half||s*(s-1)/2-cnt>half)return ;if(s>n){countt;return ;}for(int i0;…

RabbitMq教程【精细版一】

一、引言 模块之间的耦合度过高&#xff0c;导致一个模块宕机后&#xff0c;全部功能都不能用了&#xff0c;并且同步通讯的成本过高&#xff0c;用户体验差。 RabbitMQ引言 二、RabbitMQ介绍 MQ全称为Message Queue&#xff0c;消息队列是应用程序和应用程序之间的通信方法。…

在安装HDFS过程中遇见Permission denied

HDFS Shell命令权限不足问题解决 问题 想必有同学在实战Shell的时候&#xff0c;遇到了&#xff1a; Permission denied: userroot, accessWRITE, inode"/":hadoop:supergroup:drwxr-xr-x 这种类似的问题。 问题的原因就是没有权限&#xff0c;那么为什么呢&#…

功能强大的声音模拟合成软件Togu Audio Line TAL-Mod 1.9.7

Togu Audio Line TAL一个虚拟模拟合成器,具有卓越的声音和几乎无限的调制能力。其特殊的振荡器模型能够创建广泛的声音,从经典的单声道到丰富的立体声引线、效果器和焊盘。路由可以使用虚拟跳线电缆来完成。只需连接调制输出以达到调制的目的。之后,您可以调整调制强度。您不…

【SQLmap】常用命令

文章目录 实际使用案例常用命令基本命令数据库指纹识别用户信息用户权限数据库枚举数据导出密码哈希操作系统命令执行文件操作代理和网络参数指定保存恢复自动搜索注入智能模式等级设置自动注入WAF 绕过杂项帮助和支持 SQLmap 是一款开源的自动化 SQL 注入检测和利用工具&#…

时间复杂度与空间复杂度(小白向)

&#x1f916;&#x1f4bb;&#x1f468;‍&#x1f4bb;&#x1f469;‍&#x1f4bb;&#x1f31f;&#x1f680; &#x1f916;&#x1f31f; 欢迎降临张有志的未来科技实验室&#x1f916;&#x1f31f; 专栏&#xff1a;数据结构 &#x1f468;‍&#x1f4bb;&#x1f4…

你真的会udf提权???数据库权限到系统权限 内网学习 mysql的udf提权操作 ??msf你会用了吗???

我们在已经取得了数据库的账号密码过后&#xff0c;我们要进一步进行提取的操作&#xff0c;我们mysql有4钟提权的操作。 udf提权(最常用的)mof提权启动项提权反弹shell提权操作 怎么获取密码操作&#xff1a; 怎么获取密码&#xff0c;通过sql注入获取这个大家都应该知道了&a…

Python-数据分析组合可视化实例图【附完整源码】

数据分析组合可视化实例图 开篇&#xff1a;应女朋友的要求&#xff0c;于是写下了这篇详细的数据可视化代码及完整注释 一&#xff1a;柱状图、折线图横向组合网格布局 本段代码使用了pyecharts库来创建一个包含多个图表&#xff08;柱状图、折线图&#xff09;和网格布局的…