5.如何利用ORBSLAM3生成可用于机器人/无人机导航的二维/三维栅格地图--以octomap为例

1 octomap的安装及官方文档

        这里我们用ROS自带的安装方式即可:

sudo apt install ros-melodic-octomap-msgs ros-melodic-octomap-ros ros-melodic-
octomap-rviz-plugins ros-melodic-octomap-server

        如上图就是安装成功了:

        如果安装失败了,尝试用小鱼ROS换一下源再去安装:

        一些官方的文档如下,大家感兴趣可以学习一下:https://octomap.github.io/octomap/doc/index.html#gettingstarted_secicon-default.png?t=N7T8https://octomap.github.io/octomap/doc/index.html#gettingstarted_sec

2 如何利用ORBSLAM3生成的地图点通过octomap构造可以用来导航的栅格地图

2.1 octomap节点的编写

        在我们装了octomap后,我们建立一个launch文件,这里都是固定的,我就来给大家解释一下文件的各个参数的含义吧。

        我们建立一个slam.launch文件:

<launch><!-- Octomap Server Node --><node pkg="octomap_server" type="octomap_server_node" name="octomap_server"><param name="resolution" value="0.05" /><param name="frame_id" type="string" value="/orb_cam_link" /><param name="sensor_model/max_range" value="5.0" /><remap from="cloud_in" to="/ORB_SLAM3/Point_Clouds" /><param name="sensor_model/max_range" value="5000.0" /><param name="latch" value="true" /><param name="pointcloud_min_z" type="double" value="-1.5" /><param name="pointcloud_max_z" type="double" value="10" /><param name="occupancy_min_z" type="double" value="0.1" /><param name="occupancy_max_z" type="double" value="2" /><param name="height_map" type="bool" value="False" /><param name="colored_map" value="true" /></node><node pkg="tf" type="static_transform_publisher" name="orb_cam_link" args="0 0 0.15 0 0 0 /orb_cam_link /pointCloud 70" /><!-- rviz --><node pkg="rviz" type="rviz" name="rviz" args="-d $(find akm_pnc)/rviz/grid.rviz" />
</launch>

        建立一个Octomap Server Node节点。

        这个参数文件是一个ROS launch文件,它定义了启动和配置了几个节点和参数,主要是针对 Octomap Server、静态 TF 变换发布器和 RViz 可视化工具的配置。

让我解释其中的一些关键部分:

1. **Octomap Server Node**:
    - `pkg="octomap_server"` 和 `type="octomap_server_node"` 指定了要运行的节点以及其所在的软件包。
    - `name="octomap_server"` 定义了节点的名称。
    - `param` 标签下的各个 `name` 参数设置了 Octomap Server 的一些参数:
        - `resolution` 设置了地图分辨率为 0.05。
        - `frame_id` 设置了地图的坐标系为 `/orb_cam_link`。
        - `sensor_model/max_range` 设置了传感器模型的最大范围为 5.0。
        - `latch` 设为 `true`,意味着参数会被持久化,即在重新加载时保留先前设置的参数值。
        - 其他参数如 `pointcloud_min_z`、`pointcloud_max_z`、`occupancy_min_z`、`occupancy_max_z` 用于设置点云和占据地图的高度范围等参数。
        - `colored_map` 设置了地图是否包含颜色信息。

2. **TF 静态变换发布器**:
    - `node` 标签下定义了一个 `static_transform_publisher` 节点,用于发布静态的 TF 变换。
    - `name="orb_cam_link"` 定义了发布节点的名称。
    - `args` 包含了发布的静态变换的参数:位置 (0, 0, 0.15)、旋转 (0, 0, 0) 以及目标坐标系和源坐标系的名称 `/orb_cam_link` 和 `/pointCloud`。
 
3. **RViz**:
    - 最后一个节点启动了 RViz 工具,指定了加载一个配置文件 `grid.rviz`。

总体而言,这个 launch 文件配置了 Octomap Server 用于构建地图,并设置了一些传感器模型、地图分辨率以及静态 TF 变换的发布,最后启动了 RViz 工具以可视化地图和其他相关数据。

        这里需要注意的!!非常重要的参数有两个!!

        第一个是:to后面要放入自己的点云话题

        <remap from="cloud_in" to="/ORB_SLAM3/Point_Clouds" />

        第二个是frame_id:看一下ROS官方给的说明(“地图将被发布的静态全局坐标系。在动态构建地图时,需要从传感器数据到该坐标系的变换信息可用。”,也就是说,地图会被发布到一个固定的全局坐标系中。在创建地图的过程中,需要能够获得传感器数据与这个全局坐标系之间的转换信息。)

octomap_server - ROS Wikiicon-default.png?t=N7T8http://wiki.ros.org/octomap_server

        <param name="frame_id" type="string" value="/orb_cam_link" />

        下面我们来看ORB-SLAM3的部分怎么修改吧!

2.2 ORB-SLAM3发布栅格地图数据

2.2.1 理解坐标系/orb_cam_link、/odom

        我们控制仿真程序向前走。

        这是初始的状态:

        目前的坐标系为orb_cam_link。我们控制仿真程序向前走一段距离。

        我们发现,栅格地图生成了一部分。有尾部的绿线是我们的轨迹。它的话题为/RGBD/Path

        但是我们如果换成坐标系为odom呢??一直在原点不动了。

        因此,我们估计到的Tcw其实就是orb_cam_link到odom坐标系的变换矩阵。

        这里的track_point和all_point是追踪的地图点和所有的地图点,如上图彩色的部分和白色的部分。

2.2.2 稠密建图代码详解 如何发送全部稠密点云给octomap

        <remap from="cloud_in" to="/ORB_SLAM3/Point_Clouds" />

        这里我们接收/ORB_SLAM3/Point_Clouds类型的点云进行稠密重建,那么需要稠密点云进行输入。

        我们在稠密建图的线程中新添加一个话题:

        pclPoint_pub = n.advertise<sensor_msgs::PointCloud2>("/ORB_SLAM3/Point_Clouds",1000000);pclPoint_local_pub = n.advertise<sensor_msgs::PointCloud2>("/ORB_SLAM3/Point_local_Clouds",1000000);

        我们把所有帧的稠密点云赋予给octomap:

    /*** @brief 根据关键帧生成点云* @param kf* @param imRGB* @param imD* @param pose* @return*/pcl::PointCloud< PointCloudMapping::PointT >::Ptr PointCloudMapping::generatePointCloud(KeyFrame *kf,const cv::Mat& imRGB, const cv::Mat& imD, const cv::Mat& pose){std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();PointCloud::Ptr current(new PointCloud);PointCloud::Ptr loop_points(new PointCloud);for(size_t v = 0; v < imRGB.rows ; v+=3){for(size_t u = 0; u < imRGB.cols ; u+=3){cv::Point2i pt(u,v);bool isDynamic = false;float d = imD.ptr<float>(v)[u];if(d < 0.1 || d>15)continue;PointT p;p.z = d;p.x = ( u - mCx) * p.z / mFx;p.y = ( v - mCy) * p.z / mFy;p.b = imRGB.ptr<uchar>(v)[u*3];p.g = imRGB.ptr<uchar>(v)[u*3+1];p.r = imRGB.ptr<uchar>(v)[u*3+2];current->points.push_back(p);loop_points->points.push_back(p);}}Eigen::Isometry3d T = Converter::toSE3Quat( pose );PointCloud::Ptr tmp(new PointCloud);// tmp为转换到世界坐标系下的点云pcl::transformPointCloud(*current, *tmp, T.inverse().matrix());// depth filter and statistical removal,离群点剔除statistical_filter.setInputCloud(tmp);statistical_filter.filter(*current);(*mPointCloud) += *current;pcl::transformPointCloud(*mPointCloud, *tmp, T.inverse().matrix());// 加入新的点云后,对整个点云进行体素滤波voxel.setInputCloud(mPointCloud);voxel.filter(*tmp);mPointCloud->swap(*tmp);mPointCloud->is_dense = false;return loop_points;}
    /*** @brief 显示点云*/void PointCloudMapping::NormalshowPointCloud(){0.PointCloude数据结构中含有什么// typedef pcl::PointXYZRGBA PointT;// typedef pcl::PointCloud<PointT> PointCloud;// PointCloud::Ptr pcE;// Eigen::Isometry3d T;// int pcID;PointCloude pointcloude;ros::NodeHandle n;pclPoint_pub = n.advertise<sensor_msgs::PointCloud2>("/ORB_SLAM3/Point_Clouds",1000000);pclPoint_local_pub = n.advertise<sensor_msgs::PointCloud2>("/ORB_SLAM3/Point_local_Clouds",1000000);ros::Rate r(5);/// 一直在执行while(true){KeyFrame* kf;cv::Mat colorImg, depthImg;{std::unique_lock<std::mutex> locker(mKeyFrameMtx);1.如果没有关键帧(还没有进入追踪线程,等待关键帧的加入)while(mvKeyFrames.empty() && !mbShutdown){mKeyFrameUpdatedCond.wait(locker);}{unique_lock<mutex> lck( keyframeMutex );}2.更新点云(这里代码逻辑有问题)if(lastKeyframeSize  == LoopKfId)updatecloud();if (!(mvDepthImgs.size() == mvColorImgs.size() && mvKeyFrames.size() == mvColorImgs.size())) {std::cout << RED << "这是不应该出现的情况!" << std::endl;continue;}if (mbShutdown && mvColorImgs.empty() && mvDepthImgs.empty() && mvKeyFrames.empty()) {break;}3.取出我们应该去处理的数据kf = mvKeyFrames.front();colorImg = mvColorImgs.front();depthImg = mvDepthImgs.front();mvKeyFrames.pop();mvColorImgs.pop();mvDepthImgs.pop();}if (mCx==0 || mCy==0 || mFx==0 || mFy==0){mCx = kf->cx;mCy = kf->cy;mFx = kf->fx;mFy = kf->fy;}{std::unique_lock<std::mutex> locker(mPointCloudMtx);4.获得关键帧的位姿cv::Mat mTcw_Mat = kf->GetPoseMat();5.pcE中存放点云数据,已经被转化到世界坐标系下了pointcloude.pcE=generatePointCloud(kf,colorImg, depthImg, mTcw_Mat);6.存放关键帧的IDpointcloude.pcID = kf->mnId;7.存放关键帧的位姿pointcloude.T = ORB_SLAM3::Converter::toSE3Quat(mTcw_Mat);pointcloud.push_back(pointcloude);if(pointcloude.pcE->empty())continue;8.这帧的点云pcl_cloud_local_kf = *pointcloude.pcE;9.所有的点云pcl_cloud_kf = *mPointCloud;10.转换到ROS坐标系下Cloud_transform(pcl_cloud_local_kf,pcl_local_filter);Cloud_transform(pcl_cloud_kf,pcl_filter);11.转化为ROS格式的点云pcl::toROSMsg(pcl_local_filter, pcl_local_point);// TODO 发布给octomappcl::toROSMsg(pcl_filter, pcl_point);12.pclPoint_pub (/ORB_SLAM3/Point_Clouds)pcl_local_point.header.frame_id = "/pointCloud_local";pcl_point.header.frame_id = "/pointCloud";pclPoint_local_pub.publish(pcl_local_point);// TODO 发布给octomappclPoint_pub.publish(pcl_point);std::cout << YELLOW << "show point cloud, size=" << mPointCloud->points.size() << std::endl;lastKeyframeSize++;}}{if(!mPointCloud->empty()){// 存储点云string save_path = "./VSLAMRGBD.pcd";pcl::io::savePCDFile(save_path, *mPointCloud);cout << GREEN << "save pcd files to :  " << save_path << endl;}}mbFinish = true;}

        自适应场景跑,雷达也是一样,建立好了栅格地图:

        我们调用命令去保存:

rosrun map_server map_saver map:=/projected_map

        在主目录下就可以看到我们的导航地图啦!

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

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

相关文章

福德植保无人机:农业科技的未来已来

一、引言 随着科技的不断进步&#xff0c;无人机技术已经深入到各个领域。而在农业领域&#xff0c;福德植保无人机更是引领了科技潮流&#xff0c;为农业生产带来了革命性的改变。今天&#xff0c;让我们一起来了解福德植保无人机的魅力所在。 二、福德植保无人机的优势 高效作…

VSCODE 在新窗口中打开

使用VS习惯了&#xff0c;经常在新窗口中打开查看 但是VSCODE&#xff0c;无法拖动标签到一个新窗口中&#xff0c;一直以为没这个功能 后来发现 使用快捷健 ctlk,o 可以将标签页在新窗口中打开&#xff0c;虽然不如vsstudio方便&#xff0c;不过也可实现在新窗口打开的功能…

iOS NSDate的常用API

目录 一、创建日期 1.获取当前时间 2.当前时间指定秒数之后/前的时间 3.指定日期之后/后的时间 4.2001年之后/前指定秒数的时间 5.1970年之后/后指定秒数的时间 二、初始化日期 1.init 2.时间间指定秒数的时间 3.指定时间指定秒数之前/后的时间 4.2001年指定秒数之后…

高速USB转以太网芯片CH397各系统使用指南

简介 CH397是一款USB2.0高速转以太网芯片&#xff0c;支持10M/100M网络的以太网MACPHY&#xff0c;内置青稞RISC-V 处理器、符合IEEE802.3 和IEEE802.3az-2010 协议规范。支持Windows/ Linux /macOS /iOS /Android 等多平台各系统&#xff0c;适配各类台式电脑、笔记本电脑、平…

mobaxterm 下载、安装、使用

下载 官网 MobaXterm free Xserver and tabbed SSH client for Windows 下载页面 MobaXterm Xserver with SSH, telnet, RDP, VNC and X11 - Download 点击下载 安装 双击安装 勾选协议 修改安装路径 &#xff0c;等待安装完成 使用 启动 新建连接 输入主机用户名和密…

算法基础之表达式求值

算法基础之表达式求值 中序表达式求值 用栈 将字符和数字分别用栈存储 由下往上计算 左子树算完再算右子树 判断方法&#xff1a;当前符号优先级<前一个符号优先级 则左右子树已遍历完 #include<iostream>#include<cstring>#include<stack>#include&l…

7.浮点数转为整数【2023.11.29】

1.问题描述 给出一个浮点数&#xff0c;请将这个浮点数转换成整数。 2.解决思路 输入一个浮点数。 输出程序将浮点数转换为整数并输出。 3.代码实现 numfloat(input("请输入一个浮点数")) num1int(num) print(num1)4.运行结果

pip安装python包(pytorch)时遇到超时现象的通用解决方案

最近在使用服务器配置pytorch环境的时候&#xff0c;遇到了极为恼火的事情&#xff0c;使用pytorch官方的命令来下载GPU版本的pytorch总会是不是下载到一半就会崩溃&#xff0c;然而pip下载并不会断点续传&#xff08;什么时候能出这个功能啊喂&#xff01;&#xff09;。每次下…

可逆图像去噪——InvDN模型推理测试

性能&#xff1a;InvDN的去噪性能优于多数现有的竞争模型&#xff0c;在SIDD数据集上实现了新的先进的结果&#xff0c;同时享受更少的运行时间。这表明该方法在处理真实噪声问题上具有很高的效率和准确性。 模型大小&#xff1a;此外&#xff0c;InvDN的大小远小于DANet&…

功能全面又强大的同步备份软件,你找到了吗?

随着企业规模的不断扩大&#xff0c;许多企业都会拥有自己的数据中心。因此每日员工都需要在服务器与服务中心之间调取文件&#xff0c;同时还需要对每日新增的业务数据进行实时同步。如果量比较小&#xff0c;一般问题不大&#xff1b;一旦数据比较大&#xff0c;量也比较大&a…

宋仕强论道之华强北自组织和激励模式(十四)

宋仕强论道之华强北自组织和激励模式&#xff08;十四&#xff09;: 为什么一个小小深圳市华强北我宋仕强就讲这么久呢&#xff0c;听说玄奘大和尚刚出道时在洛阳的白马寺讲经&#xff0c;一个“悟”字就讲了三个月。一个事物有他的复杂性和多样性&#xff0c;从自然科学和社会…

Maven 进阶学习指南---setting详解

前言 当我们在开发项目时&#xff0c;有时需要用到外部依赖组件&#xff0c;例如当我们需要 Json 序列化的时候需要用到 FastJson 组件&#xff0c;我们可以通过下载对应 jar 包加载到项目中。但当一个大的项目同时需要依赖各种各样的外部服务&#xff0c;就存在着配置繁琐、依…

【Qt之QSqlRelationalTableModel】描述及使用

描述 QSqlRelationalDelegate链接: https://blog.csdn.net/MrHHHHHH/article/details/134690139 QSqlRelationalTableModel类为单个数据库表提供了一个可编辑的数据模型&#xff0c;并支持外键。 QSqlRelationalTableModel的行为类似于QSqlTableModel&#xff0c;但允许将列设…

Java系列-new Object的过程

从《深入理解Java虚拟机》里面的第七章看到了一些&#xff0c;先简单记录一下&#xff0c;好多不懂的。 类从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期包括&#xff1a;加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证…

【海思SS528 | VDEC】MPP媒体处理软件V5.0 | 视频解码模块——学习笔记

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

Retrofit+OkHttp打印Request 请求地址参数

在移动端开发时&#xff0c;我们常常需要像web端一样可以方便地查看我们向服务器发送请求的报文详细日志&#xff08;如请求地址&#xff0c;请求参数&#xff0c;请求类型&#xff0c;服务器响应的耗时时间&#xff0c;请求返回的结果等等&#xff09;。 使用Retrofit时&…

CSS3样式详解之圆角、阴影及变形

目录 前言一、圆角样式&#xff08;border-radius&#xff09;二、元素阴影&#xff08;box-shadow&#xff09;三、过渡动画样式&#xff08;transition&#xff09;1. transition-property(用于设置属性名称)2. transition-duration&#xff08;设置时间&#xff09;3. trans…

【web安全】CSRF漏洞攻击与防御

前言 总结&#xff0c;仅供学习。 csrf的理解 我们了解一个网站有修改信息&#xff0c;密码&#xff0c;添加删除管理&#xff0c;支付转账的功能之后。 通过抓包抓取对方修改操作的数据包样式&#xff0c; 然后在自己网站搭建一个指令。 当别人来访时&#xff0c; 如果…

linux用户管理_用户和组

2 用户管理 2.1 用户和组的基本概念和作用 2.1.1 账户实质 账户实质就是一个用户在系统上的标识&#xff0c;系统依据账户ID来区分每个用户的文件、进程、任务&#xff0c;给每个用户提供特定的工作关键&#xff08;如用户的工作目录、SHELL版本以及环境配置等&#xff09;&…

字符串函数精讲1

又是好几天没有更新了&#xff0c;最近有些忙&#xff0c;但这并不是理由&#xff0c;还是怪我自己玩的时间多了&#xff01;但还是有在每天敲代码的&#xff01;话不多说&#xff0c;开始这一期的学习&#xff1a; strlen的使用和模拟实现 • 字符串以 \0 作为结束标志&#…