pcl_ros讀取bag鐳射雷達點雲的實現
以下博文除了註釋以外的部分均來自AdamShan大佬,本人只是對內容作了註釋,還不一定對,只為自己學習,如有補充和錯誤,敬請提出,額,還有希望原文大佬看不見。
作者:AdamShan
來源:CSDN
原文:https://blog.csdn.net/AdamShan/article/details/82901295
1.編寫include/pcl_test_core.h
#pragma once #include <ros/ros.h> //匯入ROS系統包含核心公共標頭檔案 #include <pcl_conversions/pcl_conversions.h> #include <pcl/point_types.h> //點型別標頭檔案 #include <pcl/conversions.h> #include <pcl_ros/transforms.h> #include <pcl/filters/voxel_grid.h> #include <sensor_msgs/PointCloud2.h> //這些 .h檔案都是一系列模板檔案,類似於python中的numpy和matplotlib等庫檔案,可以直接呼叫,簡化程式設計。但具體每個庫是幹什麼的,沒查到。 class PclTestCore { private: ros::Subscriber sub_point_cloud_; //為接收點雲資訊建立了一個訂閱節點 ros::Publisher pub_filtered_points_; //建立了一個釋出濾波的節點 void point_cb(const sensor_msgs::PointCloud2ConstPtr& in_cloud); //void point_cb是宣告一個函式,這裡面設定了一個數據型別為sensor_msgs::PointCloud2ConstPtr& in_cloud形參,const在這裡修飾函式中的引數。將點雲格式sensor_mgs/pointcloud2轉換為pcl/pointcloud public: PclTestCore(ros::NodeHandle &nh); ~PclTestCore(); void Spin(); }; //1、public修飾的成員變數 //在程式的任何地方都可以被訪問,就是公共變數的意思,不需要通過成員函式就可以由類的例項直接訪問 //2、private修飾的成員變數 //只有類內可直接訪問,私有的,類的例項要通過成員函式才可以訪問,這個可以起到資訊隱藏
標頭檔案定義了 類 PclTestCore 分為private和public。private中用ros建立了兩個節點,為接受點雲資訊建立了訂閱節點(輸入),為濾波後的點雲建立了釋出節點(結果)。聲明瞭一個數據型別
2.編寫pcl_test_node.cpp
#include "pcl_test_core.h" int main(int argc, char **argv) //main函式,節點入口 { ros::init(argc, argv, "pcl_test"); //初始化節點,第三個引數 node_name,節點引數 ros::NodeHandle nh; //nh每個節點都對應一個控制代碼,例項化節點? PclTestCore core(nh); // 沒查到,反正與後續的節點啟動有關吧 return 0; }
這是main()函式,是節點的入口。
ros::init() 初始化節點,pcl_test是節點名稱
ros::NodeHandle nh("/my_node_handle_namespace");
nh代表控制代碼的意思,每一個node有一個控制代碼。例項化節點?
3.編寫pcl_test_core.cpp
#include "pcl_test_core.h" PclTestCore::PclTestCore(ros::NodeHandle &nh){ sub_point_cloud_ = nh.subscribe("/velodyne_points",10, &PclTestCore::point_cb, this); //這裡的sub_point_cloud在pcl_test_core.h中的prviate pub_filtered_points_ = nh.advertise<sensor_msgs::PointCloud2>("/filtered_points", 10); ros::spin(); //回撥函式 } PclTestCore::~PclTestCore(){} void PclTestCore::Spin(){ } //可以看出以上三步呼應pcl_test_node.cpp,yeah!!! void PclTestCore::point_cb(const sensor_msgs::PointCloud2ConstPtr & in_cloud_ptr){ //定義了兩個點雲指標,宣告儲存原始資料與濾波後的資料的點雲的格式 pcl::PointCloud<pcl::PointXYZI>::Ptr current_pc_ptr(new pcl::PointCloud<pcl::PointXYZI>); //pcl::PointCloud<pcl::PointXYZ>::Ptr (在這斷開的) cloud_Ptr(new pcl::PointCloud<pcl::PointXYZ>); //指的是pcl中指標和非指標的轉換。其中new pcl::PointCloud<pcl::PointXYZ>為原始點雲的資料格式。 //在函式返回指標時,經常會出現不知道的錯誤,不用返回指標,直接得到PointXYZ,再將其轉化為Ptr。 pcl::PointCloud<pcl::PointXYZI>::Ptr filtered_pc_ptr(new pcl::PointCloud<pcl::PointXYZI>); //new pcl::PointCloud<pcl::PointXYZI>,儲存濾波後的資料格式。 pcl::fromROSMsg(*in_cloud_ptr, *current_pc_ptr); // ros轉化為PCL中的點雲的資料格式,sensor_msgs::PointCloud2轉pcl::PointCloud<pcl::PointXYZ> pcl::VoxelGrid<pcl::PointXYZI> vg; //例項化濾波,vg為voxelgrid的縮寫,前面全部的代替,為後面程式設計提供方便,相當於import numpy as np np.xxx vg.setInputCloud(current_pc_ptr); //設定輸入的濾波 vg.setLeafSize(0.2f, 0.2f, 0.2f); //設定體素網格大小 vg.filter(*filtered_pc_ptr); //儲存濾波後的點雲 //再將濾波後的點雲轉換為ros下的資料格式釋出出去。 sensor_msgs::PointCloud2 pub_pc; //宣告輸出的點雲格式。 pcl::toROSMsg(*filtered_pc_ptr, pub_pc);//將pcl點雲格式轉換為ros下的點雲格式,pcl::PointCloud<pcl::PointXYZ>轉sensor_msgs::PointCloud2。第一個引數是濾波後的pcl xyz格式點雲,第二個引數是抓換後的ros pointcloud2格式,之後釋出就釋出該點雲。 pub_pc.header = in_cloud_ptr->header; //在此將in_cloude_ptr的索引賦給pub_pc.header???這個沒查到。 pub_filtered_points_.publish(pub_pc); // pub_filtered_points_為之前建立的釋出節點,在此為該node賦值。 } //從這裡以下參考sitwangmin博主,感謝! //作者:sitwangmin //來源:CSDN //原文:https://blog.csdn.net/u010284636/article/details/79214841 //ROS轉PCL資料格式 //sensor_msgs::PointCloud2轉pcl::PCLPointCloud2 //pcl_conversions::toPCL(sensor_msgs::PointCloud2, pcl::PCLPointCloud2) //sensor_msgs::PointCloud2轉pcl::PointCloud<pcl::PointXYZ> //pcl::fromROSMsg (sensor_msgs::PointCloud2, pcl::PointCloud<pcl::PointXYZ>); //PCL轉ROS資料 //pcl::PCLPointCloud2轉sensor_msgs::PointCloud2 //pcl_conversions::fromPCL(pcl::PCLPointCloud2, sensor_msgs::PointCloud2); //pcl::PointCloud<pcl::PointXYZ>轉sensor_msgs::PointCloud2 //pcl::toROSMsg (pcl::PointCloud<pcl::PointXYZ>,sensor_msgs::PointCloud2); //PCL中資料互轉 //pcl::PCLPointCloud2轉pcl::PointCloud <pcl::PointXYZ> //pcl::fromPCLPointCloud2(pcl::PCLPointCloud2,pcl::PointCloud<pcl::PointXYZ>); //pcl::PointCloud<pcl::PointXYZ>轉pcl::PCLPointCloud2 //pcl::toPCLPointCloud2(pcl::PointCloud<pcl::PointXYZ>, pcl::PCLPointCloud2);
!!!我的天啊,終於把上面三個檔案捋了一遍,但是仍然有好多無法理解。還有很多問題沒有解決。
4.寫一個launch檔案pcl_test.launch來啟動這個節點:
<launch>
<node pkg="pcl_test" type="pcl_test_node" name="pcl_test_node" output="screen"/>
</launch>
//pkg 包名稱 type是什麼?貌似和name是一個東東。
5.雜七雜八
1)回到workspace 目錄,使用catkin_make 編譯:
catkin_make
2)啟動這個節點:
roslaunch pcl_test pcl_test.launch
3)新建終端,並執行我們的測試bag(測試bag下載連結:https://pan.baidu.com/s/1HOhs9StXUmZ_5sCALgKG3w)
rosbag play --clock test.bag
注意這裡,輸入這行命令一定是在bag所在位置,不然會報錯。
4)開啟第三個終端,啟動Rviz:
rosrun rviz rviz
5)配置Rviz的Frame為velodyne,並且載入原始點雲和過濾以後的點雲的display。
在frame中輸入velodyne,在add中的topic裡面新增原始點雲和過濾後的點雲。
原始點雲:
降取樣之後的點雲(即我們的節點的輸出):