在ROS中将点云(PointCloud2)生成Octomap,rviz可视化显示

news2024/11/19 20:42:56

一个python文件作为publisher,发布点云数据。一个C++项目接收点云数据,引用octomap库,将点云生成octomap的tree,在将tree通过topic发布出去,rviz订阅octomap tree的topic进行可视化显示。

首先创建一个python的点云发布节点,用pycharm开发,在Project Structure中加入ros的package:在C++和Python的项目中使用ROS-CSDN博客

import rospy
from sensor_msgs.msg import PointCloud2
from sensor_msgs import point_cloud2
import numpy as np

# 初始化ROS节点
rospy.init_node('pointcloud_publisher', anonymous=True)

# 创建ROS Publisher
pub = rospy.Publisher('your_pointcloud_topic', PointCloud2, queue_size=10)

rate = rospy.Rate(1)  # 设置发布频率为1Hz,你可以根据需要调整

while not rospy.is_shutdown():
    # 创建一个NumPy数组,包含点云数据
    point_cloud_data = np.array([
        [1.0, 2.0, 0.0],  # 三个坐标 (x, y, z) 和一个强度值
        [2.0, 3.0, 0.0],
        [3.0, 4.0, 0.0],
        # 添加更多点云数据行
    ])
    # 创建Pointcloud2消息
    header = rospy.Header()
    header.stamp = rospy.Time.now()
    header.frame_id = 'your_frame_id'  # 设置帧ID
    cloud_msg = point_cloud2.create_cloud_xyz32(header, point_cloud_data)

    pub.publish(cloud_msg)

    print(cloud_msg.header.stamp.to_sec())

    rate.sleep()

接下来创建一个C++项目,即创建工作空间文件夹,工作空间中包括:include,src,build文件夹,以及CMakeLists.txt,src中创建main.cpp。C++项目包括三个功能,一是订阅点云topic,二是将点云转成octomap的tree,三是将tree发布,让rviz可视化。实现这三个功能,需要做如下的准备:

订阅点云topic功能的准备:

安装pcl

sudo apt install libpcl-dev

再安装pcl_msgs(不知道为什么pcl_msgs不在pcl包里),中间的melodic替换为自己的ros版本。

sudo apt-get install ros-melodic-pcl-msgs

再继续把https://github.com/ros-perception/perception_pcl/blob/melodic-devel/pcl_conversions/include/pcl_conversions/pcl_conversions.h

这个pcl_conversions.h文件放到自己项目的include文件夹中, 后面回用到这个头文件里的一个函数 fromROSMsg,函数 fromROSMsg依赖pcl_msgs,其功能是将ros topic的sensor_msgs::PointCloud2::ConstPtr 数据转化为 pcl::PointCloud<pcl::PointXYZ> 数据。

点云生成octomap的准备:

安装octomap

git clone https://github.com/OctoMap/octomap.git
cd octomap
mkdir build
cd build
cmake ..
make
sudo make install

通过topic发布octomap tree的准备:

下载octomap_msgs项目:https://github.com/OctoMap/octomap_msgs/tree/melodic-devel

 这里要选择自己的ros版本,noetic可以用melodic。(不知道为什么octomap_msgs不继承进octomap)

 下载之后通过cmake编译

cd octomap_msgs
mkdir build
cd build
cmake ..
make

在octomap_msgs/build/devel/share/octomap_msgs/cmake中,有octomap_msgsConfig.cmake,在自己项目的要使用octomap_msgs时,CMakeLists.txt中set这个Config.cmake为 octomap_msgs_DIR,使得cmake在find_packege时,能够找到octomap_msgs。

到这里,准备工作都完成了。

C++代码以及CMakeLists.txt内容:

main.cpp这样写

#include "ros/ros.h"
#include "sensor_msgs/PointCloud2.h"

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

#include <octomap/octomap.h>
#include <octomap/Pointcloud.h>
#include <octomap/ColorOcTree.h>
#include <octomap_msgs/Octomap.h>

#include "pcl_conversions.h"

#include "/home/username/Downloads/octomap_msgs/include/octomap_msgs/conversions.h"


// Create an Octomap message
octomap_msgs::Octomap octomap_msg;

class MapGenerator{
public:
   MapGenerator(){
      tree = new octomap::OcTree(0.1);
   };
   ~MapGenerator(){};

   void PointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& msg);

   octomap::OcTree* tree;
};

void print_query_info(octomap::point3d query, octomap::OcTreeNode* node) {
   if (node != NULL) {
      std::cout << "occupancy probability at " << query << ":\t " << node->getOccupancy() << std::endl;
   }
   else 
      std::cout << "occupancy probability at " << query << ":\t is unknown" << std::endl;    
}


int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "pointcloud_subscriber");
    // 创建ROS节点句柄
    ros::NodeHandle nh;

    MapGenerator mg;

    // 创建Subscriber来订阅PointCloud2消息
    ros::Subscriber sub = nh.subscribe<sensor_msgs::PointCloud2>("your_pointcloud_topic", 10, boost::bind(&MapGenerator::PointCloudCallback, &mg, _1));

    // Create a publisher for the Octomap topic
    ros::Publisher octomap_pub = nh.advertise<octomap_msgs::Octomap>("octomap_tree", 1);

    // Publish the Octomap
    ros::Rate loop_rate(1);  // Adjust the publishing rate as needed
    while (ros::ok()) {
      octomap_pub.publish(octomap_msg);
      ros::spinOnce();
      loop_rate.sleep();
    }

    return 0;
}

// 回调函数,用于处理接收到的PointCloud2消息
void MapGenerator::PointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& msg)
{
   pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
   pcl::fromROSMsg(*msg, pcl_cloud);

   for (const auto& point : pcl_cloud) {
      // Extract XYZ coordinates and RGB color from the point
      float x = point.x;
      float y = point.y;
      float z = point.z;

      // Convert color to octomap::ColorOcTreeNode
      octomap::point3d octomap_point(x, y, z);

      // Insert the node into the octomap
      tree->updateNode(octomap_point, true);
   }

   // octomap::point3d query = octomap::point3d(1., 2., 0.);
   // octomap::OcTreeNode* result = tree->search(query);
   // print_query_info(query, result);

   
   // Also publish as an octomap msg for visualization
   octomap_msgs::fullMapToMsg(*tree, octomap_msg);
   
   // 在这里可以对OctoMap进行其他操作,如保存地图数据
   // tree.writeBinary("your_octomap.ot");

   ROS_INFO("OctoMap created and saved.");
}

CMakeLists.txt这样写

cmake_minimum_required(VERSION 2.8)

project(my_map)

set(CMAKE_BUILD_TYPE "Debug")

find_package(catkin REQUIRED COMPONENTS
  roscpp
  sensor_msgs
  std_msgs
  pcl_msgs
)
find_package(octomap REQUIRED)

find_package(PCL REQUIRED)

set(octomap_msgs_DIR /home/username/Downloads/octomap_msgs/build/devel/share/octomap_msgs/cmake/octomap_msgsConfig.cmake)
find_package(octomap_msgs REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

include_directories(
./include
${catkin_INCLUDE_DIRS}
${OCTOMAP_INCLUDE_DIRS}
)

set(SRC_LIST
./src/main.cpp)

add_executable(main ${SRC_LIST})

target_link_libraries( main 
${catkin_LIBRARIES}
${OCTOMAP_LIBRARIES}
${PCL_LIBRARIES}
)

因为是使用vscode开发,c_cpp_properties.json这样写,不用vscode就不需要了。

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/你的ros版本/include/",
                "/usr/include/eigen3",
                "/usr/include/pcl-1.10/"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c17",
            "cppStandard": "gnu++14",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}

代码和CMakeLists解释:

回调函数中的

pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
pcl::fromROSMsg(*msg, pcl_cloud);

是在include文件夹中,下载的那个头文件里。

回调函数中

octomap_msgs::fullMapToMsg(*tree, octomap_msg);

这句话是将tree通过topic发布,这个函数在我们下载并编译的octomap_msgs中,为了使用它,在CMakeLists中需要包含如下代码,并且在main.cpp的开头include它的头文件。

set(octomap_msgs_DIR /home/username/Downloads/octomap_msgs/build/devel/share/octomap_msgs/cmake/octomap_msgsConfig.cmake)
find_package(octomap_msgs REQUIRED)

然后就可以编译运行了。

在ubuntu中使用vscode进行C++开发的方法,参考:Ubuntu使用cmake和vscode开发自己的项目,引用自己的头文件和openCV-CSDN博客

 最后一步通过rviz可视化,只要安装一个插件就可以

sudo apt-get install ros-kinetic-octomap-rviz-plugins

kinetic换成你的ubuntu版本。

rosrun rviz rviz

Add OccupancyMap

也可以用octovis进行可视化

sudo apt-get install ros-noetic-octovis
octovis your_octomap.ot

完成!

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

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

相关文章

使用MFC创建一个SaleSystem

目录 1、项目的创建&#xff1a; 2、项目的配置&#xff1a; 3、设置窗口属性&#xff1a; &#xff08;1&#xff09;、设置图标 1&#xff09;、添加导入资源 2&#xff09;、代码初始化图标 &#xff08;2&#xff09;、设置标题 &#xff08;3&#xff09;、设置窗口…

【文献copilot】调用文心一言api对论文逐段总结

文献copilot&#xff1a;调用文心一言api对论文逐段总结 当我读文献的时候&#xff0c;感觉读得太慢了&#xff0c;看翻译软件翻译的又觉得翻译的不好。于是我就写了个程序辅助我读文献&#xff0c;它可以逐段总结&#xff0c;输出格式是&#xff1a;原文一句话总结分段总结&a…

Kafka与MySQL的组合使用

根据上面给出的student表&#xff0c;编写Python程序完成如下操作&#xff1a; &#xff08;1&#xff09;读取student表的数据内容&#xff0c;将其转为JSON格式&#xff0c;发送给Kafka&#xff1b; 创建Student表的SQL语句如下&#xff1a; create table student( sno ch…

基于深度学习网络的蔬菜水果种类识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1数据集准备 4.2构建深度学习模型 4.3模型训练 4.4模型评估 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 clc; clear; close all; wa…

【C++】C++学习(模板+排序+测时)

本文主要记录使用模板函数来编写排序算法&#xff0c;并计算运行时间。 模板函数&#xff08;Template Function&#xff09;是一种通用函数&#xff0c;可以在其定义时不指定具体的参数类型&#xff0c;在调用时再根据需要指定具体类型。模板函数可以接受不同类型的参数&…

057:mapboxGL中layout,paint等属性的函数表达说明

第057个 点击查看专栏目录 本篇文章是mapbox的layer中layout,paint等属性的函数表达 mapbox中 Function 是什么 函数 Function 可以作为其 layout布局类属性和 paint 绘制类属性的属性值。在使用 Function 作为属性值时,实际上是一个对象。 layers的3种函数类型 Function …

error: unable to read askpass response from

报错信息 解决方法&#xff1a; 中文&#xff1a;文件-->设置-->版本控制-->Git-->勾选使用凭证帮助程序 英文&#xff1a;File -> Settings -> Version Control -> Git / Check "User credential Helper" 因为我的webstrom是中文版的&#…

Simulink 最基础教程(四)模型参数与全局变量

4.1模型参数 上面介绍常用模块的时候&#xff0c;都是找到模块&#xff0c;双击模块&#xff0c;设置参数。这些参数都是模块参数。与之相对的&#xff0c;是模型参数。一些说明&#xff1a; 1&#xff09;模型参数和模块参数并不是隶属关系&#xff0c;而是配合关系。当模型参…

起重机控制电路接线 - 基础与进阶(修订中...)

1.基础篇 起重机电气接线 - 理论与实践 - 知乎1.现场配电箱这是一台10吨电动葫芦的电器箱。你能看出这个起重机用到了几个电机吗&#xff1f;先看空开和继电器。 电机为了控制正反转&#xff0c;一般每个电机需要用到两个继电器。这上面有7个继电器&#xff0c;所以&#xff0…

数字图像处理实验记录四(图像的空间域增强-平滑处理)

前言&#xff1a;要是是实验报告赶工的话&#xff0c;建议总结上网抄&#xff0c;或者重构我的总结&#xff0c;仅供学习参考&#xff0c;不要照抄 文章目录 一、基础知识1&#xff0c;噪声2&#xff0c;椒盐噪声3&#xff0c;高斯噪声4&#xff0c;滤波器5&#xff0c;均值滤…

[云原生1.] Docker容器的简单介绍和基本管理

1. Docker容器的基本概述 1.1 简介 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级…

Unity之ShaderGraph如何实现无贴图水球效果

前言 我们今天来实现一个无贴图水球效果&#xff0c;如下图所示&#xff1a; 主要节点 UVSplit&#xff1a;可以获得UV在RGB三个颜色分别的分量 Remap&#xff1a;重映射节点 基于输入 In 值在输入In Min Max的 x 和 y 分量之间的线性插值&#xff0c;返回输入Out Min Max…

爬虫三大库

Requests库安装 Requests库的作用是请求网站获得网页数据 在pycharm中安装方式如下&#xff1a; 选择settings 选择Project Interpreter&#xff0c;单击号添加第三方库 BeautifulSoup库按同样方式安装。 Requests库 pycharm返回结果为<Response [200]>,说明请求网址成…

简单秒表设计仿真verilog跑表,源码/视频

名称&#xff1a;简单秒表设计仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 秒表显示最低计时为10ms&#xff0c;最大为59:99&#xff0c;超出返回00&#xff1a;00 具有复位、启动、暂停三个按键 四个数码管分别显示4个时间数字。 演示…

了解 Elasticsearch 自动生成的文档 _id:重复是一个问题吗?

Elasticsearch 中自动生成的文档 ID 当你在未指定 ID 的情况下对文档建立索引时&#xff0c;Elasticsearch 会自动为该文档生成唯一的 ID。 该 ID 是 Base64 编码的 UUID&#xff0c;由多个部分组成&#xff0c;每个部分都有特定的用途。 ID 生成过程针对索引速度和存储效率进…

互联网Java工程师面试题·Java 总结篇·第九弹

目录 75、阐述 JDBC 操作数据库的步骤。 76、Statement 和 PreparedStatement 有什么区别&#xff1f;哪个性 能更好&#xff1f; 77、使用 JDBC 操作数据库时&#xff0c;如何提升读取数据的性能&#xff1f;如何提升更新数据的性能&#xff1f; 78、在进行数据库编程时&a…

git 查看本地秘钥

第一步&#xff1a; 1&#xff0c;打开终端或者命令行窗口&#xff0c;输入一下命令&#xff1a; cd ~/.ssh进入ssh目录 2&#xff0c;查看该目录下的所有文件&#xff0c;输入以下命令: ls -al该命令将显示ssh目录下的所有文件&#xff0c;包括秘钥文件和配置文件,如果不存…

100天掌握网络安全知识点!

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

C++ Primer 第十一章 关联容器 重点解读

1 map自定义排序 #include <map> #include <iostream> #include <functional> using namespace std; int main() {function<bool(pair<int, int>, pair<int, int>)> cmp [&](pair<int, int> p1, pair<int, int> p2) -&g…

设计模式-综合应用(一)

介绍 使用jQuery做一个模拟购物车的示例 用到的设计模式 工厂模式 单例模式装饰器模式 观察者模式状态模式 模板方法模式 代理模式 UML类图