当前位置:   article > 正文

点云地图的二维投影_movebase把fastlio的点云图转为2d导航图

movebase把fastlio的点云图转为2d导航图

  通过SLAM或其他方式构建的点云地图是无法直接用于导航的,我知道的解决方案有三种:

一、将点云地图二维投影,转换为可用于导航的二维栅格地图;

二、将点云转换为Octomap八叉树地图,即可使用导航算法,比如RRT*进行三维导航;

三、将实时点云数据转换为实时激光数据,这样就可以愉快的使用ROS的move_base和acml包了。

    这里尝试使用第一种方案。

构建点云地图

    构建点云地图需要深度图和对应的位姿,这里使用高翔的<视觉SLAM14讲>的深度图和位姿。这里构建的是一个ROS功能包,代码如下:

pcl_test.cpp

  1. #include <stdio.h>
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <fstream>
  5. #include <Eigen/Core>
  6. #include <Eigen/Geometry>
  7. #include <Eigen/Dense>
  8. #include <ros/ros.h>
  9. #include <opencv2/opencv.hpp>
  10. #include <opencv2/core/core.hpp>
  11. #include <opencv2/core/eigen.hpp>
  12. #include <opencv2/imgproc/imgproc.hpp>
  13. #include <opencv2/highgui/highgui.hpp>
  14. #include <pcl/common/common_headers.h>
  15. #include <pcl/point_types.h> 
  16. #include <pcl/io/pcd_io.h> 
  17. #include <pcl/filters/voxel_grid.h>
  18. //#include <pcl/visualization/pcl_visualizer.h>
  19. //#include <pcl/visualization/cloud_viewer.h>
  20. #include <pcl/filters/statistical_outlier_removal.h>
  21. #include <pcl/point_cloud.h>
  22. #include <pcl_conversions/pcl_conversions.h>
  23. #include <pcl_ros/point_cloud.h>
  24. #include <sensor_msgs/PointCloud2.h>
  25. typedef pcl::PointXYZRGB PointT;
  26. typedef pcl::PointCloud<PointT> PointCloud;
  27. using namespace std;
  28. void PCLTest();
  29. ros::Publisher pub_pcs;
  30. ros::Publisher pub_pcr;
  31. int main(int argc, char** argv)
  32. {
  33.     ros::init(argc, argv, "pcl_test_node");//初始化节点
  34.     ros::start();//启动节点
  35.     ros::NodeHandle nh;
  36.     pub_pcs=nh.advertise<sensor_msgs::PointCloud2>("/point_cloud",1);
  37.     pub_pcr=nh.advertise<PointCloud>("/point_cloud_raw",1);
  38.     ROS_INFO_STREAM("Initing");
  39.     PCLTest();
  40.     ROS_INFO_STREAM("pcl_test节点结束");
  41.     return 0;
  42. }
  43. void PCLTest()
  44. {
  45.     vector<cv::Mat> colorImgs, depthImgs;    // 彩色图和深度图
  46.     vector<Eigen::Isometry3d> poses;         // 相机位姿
  47.     ifstream fin("./data/pose.txt");
  48.     if (!fin)
  49.     {
  50.         cerr<<"cannot find pose file"<<endl;
  51.         return;
  52.     }
  53.     
  54.     for ( int i=0; i<5; i++ )
  55.     {
  56.         boost::format fmt( "./data/%s/%d.%s" ); //图像文件格式
  57.         colorImgs.push_back( cv::imread( (fmt%"color"%(i+1)%"png").str() ));
  58.         depthImgs.push_back( cv::imread( (fmt%"depth"%(i+1)%"pgm").str(), -1 )); // 使用-1读取原始图像
  59.         double data[7= {0};
  60.         for ( int i=0; i<7; i++ )
  61.         {
  62.             fin>>data[i];
  63.         }
  64.         Eigen::Quaterniond q( data[6], data[3], data[4], data[5] );
  65.         Eigen::Isometry3d T(q);
  66.         T.pretranslate( Eigen::Vector3d( data[0], data[1], data[2] ));
  67.         poses.push_back( T );
  68.      }
  69.      // 计算点云并拼接
  70.     // 相机内参 
  71.     double cx = 325.5;
  72.     double cy = 253.5;
  73.     double fx = 518.0;
  74.     double fy = 519.0;
  75.     double depthScale = 1000.0;
  76.     cout<<"正在将图像转换为点云..."<<endl;
  77.     // 新建一个点云
  78.      PointCloud::Ptr pointCloud( new PointCloud );
  79.      //pcl::visualization::CloudViewer viewer("pcd viewer");
  80.      
  81.      for ( int i=0; i<5; i++ )
  82.      {
  83.         PointCloud::Ptr current( new PointCloud );
  84.         cout<<"转换图像中: "<<i+1<<endl;
  85.         cv::Mat color = colorImgs[i];
  86.         cv::Mat depth = depthImgs[i];
  87.         Eigen::Isometry3d T = poses[i];
  88.         for ( int v=0; v<color.rows; v++ )
  89.             for ( int u=0; u<color.cols; u++ )
  90.             {
  91.                 unsigned int d = depth.ptr<unsigned short> ( v )[u]; // 深度值
  92.                 if ( d==0 ) continue// 为0表示没有测量到
  93.                 if ( d >= 3500 ) continue// 深度太大时不稳定,去掉
  94.                 Eigen::Vector3d point;
  95.                 point[2= double(d)/depthScale;
  96.                 point[0= (u-cx)*point[2]/fx;
  97.                 point[1= (v-cy)*point[2]/fy;
  98.                 Eigen::Vector3d pointWorld = T*point;
  99.                 
  100.                 
  101.                 PointT p ;
  102.                 p.x = pointWorld[0];
  103.                 p.y = pointWorld[1];
  104.                 p.z = pointWorld[2];
  105.                 p.b = color.data[ v*color.step+u*color.channels() ];
  106.                 p.g = color.data[ v*color.step+u*color.channels()+1 ];
  107.                 p.r = color.data[ v*color.step+u*color.channels()+2 ];
  108.                 current->points.push_back( p );
  109.             }
  110.         //利用统计滤波器方法去除孤立点。
  111.         PointCloud::Ptr tmp ( new PointCloud );
  112.         pcl::StatisticalOutlierRemoval<PointT> statistical_filter;
  113.         statistical_filter.setMeanK(50);
  114.         statistical_filter.setStddevMulThresh(1.0);
  115.         statistical_filter.setInputCloud(current);
  116.         statistical_filter.filter( *tmp );
  117.         (*pointCloud) += *tmp;
  118.         //viewer.showCloud(pointCloud);
  119.         //getchar();
  120.     }
  121.     
  122.     getchar();
  123.     pointCloud->is_dense = false;
  124.     cout<<"点云共有"<<pointCloud->size()<<"个点."<<endl;
  125.         //体素滤波器(Voxel Filter)进行降采样
  126.     pcl::VoxelGrid<PointT> voxel_filter;
  127.     voxel_filter.setLeafSize( 0.010.010.01 );       //分辨率
  128.     PointCloud::Ptr tmp ( new PointCloud );
  129.     voxel_filter.setInputCloud( pointCloud );
  130.     voxel_filter.filter( *tmp );
  131.     tmp->swap(*pointCloud);
  132.     cout<<"滤波之后,点云共有"<<pointCloud->size()<<"个点."<<endl;
  133.     
  134.     
  135.     sensor_msgs::PointCloud2 pmsg;
  136.     pcl::toROSMsg(*pointCloud, pmsg);
  137.     pmsg.header.frame_id = "map";
  138.     
  139.     pub_pcs.publish(pmsg);
  140.     pub_pcr.publish(*pointCloud);
  141.     
  142.     getchar();
  143.     
  144.     pcl::io::savePCDFileBinary("map.pcd"*pointCloud );
  145. }

    PCLTest函数是构建点云的函数,首先从pose.txt中读取位姿,然后读取rgb图像和深度图像,接着将像素坐标转换为世界坐标,在存入点云中,每张图片构建的点云都进行统计滤波。构建完成点云之后,进行体素滤波。最后发布点云。这里发布两个消息:sensor_msgs::PointCloud2 和 PointCloud,其中sensor_msgs::PointCloud2类型的点云用于rviz点云可视化,而PointCloud则用于给cloud_to_map包转换为二维地图。

    需要注意的是,若想直接发布点云类型 pcl::PointCloud<PointT>的消息,需要导入头文件#include <pcl_ros/point_cloud.h>。若想将pcl::PointCloud<PointT>转换为sensor_msgs::PointCloud2,需要导入头文件

#include <pcl_conversions/pcl_conversions.h>。

    程序的最后将点云地图保存为map.pcd。我们可以使用pcl_viewer查看:

图片1.jpg

点云地图的二维投影

    这里通过cloud_to_map功能包将点云地图转换二维地图。cloud_to_map好象是北达科他大学( North Dakota State University),更具体的信息我不知道了。我这里使用的是从github:https://github.com/306327680/PointCloud-to-grid-map上下载的,但是直接使用貌似有点问题,而且这个程序为了动态调参,写的太复杂了,我将其简化了。其主程序如下:

cloud_to_map_node.cpp

  1. #include <iostream>
  2. #include <fstream>
  3. #include <stdint.h>
  4. #include <math.h>
  5. #include <ros/ros.h>
  6. #include <pcl_ros/point_cloud.h>
  7. #include <nav_msgs/OccupancyGrid.h>
  8. #include <pcl_conversions/pcl_conversions.h>
  9. #include <pcl/point_cloud.h>
  10. #include <pcl/point_types.h>
  11. #include <pcl/common/common_headers.h>
  12. #include <pcl/io/pcd_io.h>
  13. #include <pcl/point_types.h>
  14. #include <pcl/features/normal_3d.h>
  15. #include <pcl/console/parse.h>
  16. #include <pcl/filters/passthrough.h>
  17. typedef pcl::PointXYZRGB PointT;
  18. typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloud;
  19. typedef pcl::PointCloud<pcl::Normal> NormalCloud;
  20. using namespace std;
  21. /* 全局变量 */
  22. PointCloud::ConstPtr currentPC;
  23. bool newPointCloud = false;
  24. double cellResolution=0.05;
  25. double deviation = 0.785398;
  26. int buffer_size=50;//每个栅格法线垂直的阈值
  27. ros::Publisher pub;
  28. void calcSize(double *xMax, double *yMax, double *xMin, double *yMin) 
  29. {
  30.   pcl::PointXYZRGB minPt, maxPt;
  31. pcl::getMinMax3D(*currentPC, minPt, maxPt);
  32.   *xMax=maxPt.x;
  33.   *yMax=maxPt.y;
  34.   *xMin=minPt.x;
  35.   *yMin=minPt.y;
  36. }
  37. //得到栅格地图
  38. void computeGrid( std::vector<signed char> &ocGrid, double xMin, double yMin,int xCells, int yCells) 
  39. {
  40. cout<<"开始计算法线"<<endl;
  41. //计算点云的法线
  42. NormalCloud::Ptr cloud_normals(new NormalCloud);
  43. pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
  44. ne.setInputCloud(currentPC);
  45. pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>());
  46. ne.setSearchMethod(tree);
  47. ne.setRadiusSearch(0.06);
  48. ne.compute(*cloud_normals);
  49. cout<<"判断法线是否垂直"<<endl;
  50. int size=xCells*yCells;
  51. std::vector<int> countGrid(size);
  52. //判断每个点云的法向量是否垂直
  53. for (size_t i = 0; i < currentPC->size(); i++)
  54. {
  55. double x = currentPC->points[i].x;
  56. double y = currentPC->points[i].y;
  57. double z = cloud_normals->points[i].normal_z;
  58. int xc = (int) ((x - xMin) / cellResolution); //取整后默认按照cellResolution将点分配到cell
  59. int yc = (int) ((y - yMin) / cellResolution);
  60. /*
  61. 法线是单位向量,z是发现的z值,z越接近于1,表明法线越垂直。
  62. 而acos(z)使得z值越接近于1,结果越小.
  63. 即acos(z)的结果越大,z越不垂直
  64. */
  65. double normal_value = acos(fabs(z));//值域 0--phi   地面fabs(z)应该是1 acos是0,最小值
  66. if (normal_value > deviation)       //根据acos函数的递减性质,非地面点的值应该都比地面点大。可以设置deviation值,决定障碍物点的阈值
  67.   countGrid[yc * xCells + xc]++//统计一个cell中垂直方向满足条件的点数
  68. }
  69. cout<<"计算占据概率"<<endl;
  70. //根据阈值计算占据概率
  71. for (int i = 0; i < size; i++)  //size:xCells * yCells
  72. {
  73. if (countGrid[i] < buffer_size && countGrid[i]>0
  74.   ocGrid[i] = 0;
  75. else if (countGrid[i] > buffer_size
  76.   ocGrid[i] = 100;
  77. else if (countGrid[i] == 0
  78.   ocGrid[i] = 0// TODO Should be -1      
  79. }
  80. }
  81. void updateGrid(nav_msgs::OccupancyGridPtr grid, int xCells, int yCells,
  82.                                double originX, double originY, std::vector<signed char> *ocGrid) 
  83. {
  84. static int seq=0;
  85. grid->header.frame_id = "map";
  86. grid->header.seq=seq++;
  87. grid->header.stamp.sec = ros::Time::now().sec;
  88. grid->header.stamp.nsec = ros::Time::now().nsec;
  89. grid->info.map_load_time = ros::Time::now();
  90. grid->info.resolution = cellResolution;
  91. grid->info.width = xCells;
  92. grid->info.height = yCells;
  93. grid->info.origin.position.x = originX;  //minx
  94. grid->info.origin.position.y = originY;  //miny
  95. grid->info.origin.position.z = 0;
  96. grid->info.origin.orientation.w = 1;
  97. grid->info.origin.orientation.x = 0;
  98. grid->info.origin.orientation.y = 0;
  99. grid->info.origin.orientation.z = 0;
  100. grid->data = *ocGrid;
  101. }
  102. void callback(const PointCloud::ConstPtr& msg) 
  103. {
  104.   currentPC=msg;
  105.   ROS_INFO_STREAM("Convertor节点——接收到点云");
  106. /*计算点云的最大和最小值*/
  107. double xMax = 0, yMax = 0, xMin = 0, yMin = 0;
  108. calcSize(&xMax, &yMax, &xMin, &yMin); 
  109. cout<<"极值:"<<xMax<<" "<<yMax<<" "<<xMin<<" "<<yMin<<" "<<endl;
  110. /* 确定栅格地图的长和宽 */
  111. int xCells = ((int) ((xMax - xMin) / cellResolution)) + 1;
  112. int yCells = ((int) ((yMax - yMin) / cellResolution)) + 1;
  113. cout<<"地图大小:"<<xCells<<" "<<yCells<<endl;
  114. /*计算栅格地图*/
  115. std::vector<signed char> ocGrid(yCells * xCells);  //存储每个cell的值  0或者100
  116. computeGrid(ocGrid, xMin, yMin, xCells, yCells);
  117. cout<<"成功计算得到栅格地图"<<endl;
  118. //发布地图消息
  119. nav_msgs::OccupancyGridPtr grid(new nav_msgs::OccupancyGrid);
  120. updateGrid(grid, xCells, yCells, xMin, yMin, &ocGrid);
  121. pub.publish(grid);
  122. ROS_INFO_STREAM("Convertor节点——发布栅格地图");
  123. }
  124. int main(int argc, char** argv) 
  125. {
  126. setlocale(LC_ALL"");
  127. ros::init(argc, argv, "convertor_node");
  128. ros::NodeHandle nh;
  129. ros::Subscriber sub = nh.subscribe<PointCloud>("/point_cloud/raw"1, callback); 
  130. pub = nh.advertise<nav_msgs::OccupancyGrid>("/map"1);
  131. //构造占据网格消息
  132. nav_msgs::OccupancyGridPtr grid(new nav_msgs::OccupancyGrid);
  133. grid->header.seq = 1;
  134. grid->header.frame_id = "map";//父坐标系
  135. grid->info.origin.position.z = 0;
  136. grid->info.origin.orientation.w = 1;
  137. grid->info.origin.orientation.x = 0;
  138. grid->info.origin.orientation.y = 0;
  139. grid->info.origin.orientation.z = 0;
  140. ROS_INFO_STREAM("Convertor节点初始化完成");
  141. ros::Rate loop_rate(0.2);
  142. ros::Duration t(10);
  143. while (ros::ok()) 
  144. {
  145. ros::spinOnce();
  146. t.sleep();
  147. }
  148. }

    cloud_to_map订阅点云:/point_cloud_raw,发布的栅格地图:/map。而且dynamic_reconfigure功能包动态配置参数。

    在rviz接手栅格地图:

图片2.jpg

    这个程序通过判断法向量的方法获得地图,但我觉得这种方法计算量大,而是感觉效果一半。我这里提出一种更简单的方法,直接将z轴0-0.5范围内的点云投影,得到栅格地图,程序如下:

  1. #include <iostream>
  2. #include <fstream>
  3. #include <stdint.h>
  4. #include <math.h>
  5. #include <ros/ros.h>
  6. #include <pcl_ros/point_cloud.h>
  7. #include <nav_msgs/OccupancyGrid.h>
  8. #include <pcl_conversions/pcl_conversions.h>
  9. #include <pcl/point_cloud.h>
  10. #include <pcl/point_types.h>
  11. #include <pcl/common/common_headers.h>
  12. #include <pcl/io/pcd_io.h>
  13. #include <pcl/point_types.h>
  14. #include <pcl/features/normal_3d.h>
  15. #include <pcl/console/parse.h>
  16. #include <pcl/filters/passthrough.h>
  17. typedef pcl::PointXYZRGB PointT;
  18. typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloud;
  19. typedef pcl::PointCloud<pcl::Normal> NormalCloud;
  20. using namespace std;
  21. /* 全局变量 */
  22. PointCloud::ConstPtr currentPC;
  23. bool newPointCloud = false;
  24. double cellResolution=0.05;
  25. double deviation = 0.785398;
  26. int buffer_size=50;//每个栅格法线垂直的阈值
  27. ros::Publisher pub;
  28. void calcSize(double *xMax, double *yMax, double *xMin, double *yMin) 
  29. {
  30.       pcl::PointXYZRGB minPt, maxPt;
  31.     pcl::getMinMax3D(*currentPC, minPt, maxPt);
  32.       *xMax=maxPt.x;
  33.       *yMax=maxPt.y;
  34.       *xMin=minPt.x;
  35.       *yMin=minPt.y;
  36. }
  37. //得到栅格地图
  38. void computeGrid( std::vector<signed char> &ocGrid, double xMin, double yMin,int xCells, int yCells) 
  39. {
  40.     cout<<"开始计算法线"<<endl;
  41.     //计算点云的法线
  42.     NormalCloud::Ptr cloud_normals(new NormalCloud);
  43.     pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
  44.     ne.setInputCloud(currentPC);
  45.     pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>());
  46.     ne.setSearchMethod(tree);
  47.     ne.setRadiusSearch(0.06);
  48.     ne.compute(*cloud_normals);
  49.     cout<<"判断法线是否垂直"<<endl;
  50.     int size=xCells*yCells;
  51.     std::vector<int> countGrid(size);
  52.     //判断每个点云的法向量是否垂直
  53.     for (size_t i = 0; i < currentPC->size(); i++)
  54.     {
  55.     double x = currentPC->points[i].x;
  56.     double y = currentPC->points[i].y;
  57.     double z = cloud_normals->points[i].normal_z;
  58.     int xc = (int) ((x - xMin) / cellResolution); //取整后默认按照cellResolution将点分配到cell
  59.     int yc = (int) ((y - yMin) / cellResolution);
  60.     /*
  61.     法线是单位向量,z是发现的z值,z越接近于1,表明法线越垂直。
  62.     而acos(z)使得z值越接近于1,结果越小.
  63.     即acos(z)的结果越大,z越不垂直
  64.     */
  65.     double normal_value = acos(fabs(z));//值域 0--phi   地面fabs(z)应该是1 acos是0,最小值
  66.     if (normal_value > deviation)       //根据acos函数的递减性质,非地面点的值应该都比地面点大。可以设置deviation值,决定障碍物点的阈值
  67.       countGrid[yc * xCells + xc]++//统计一个cell中垂直方向满足条件的点数
  68.     }
  69.     cout<<"计算占据概率"<<endl;
  70.     //根据阈值计算占据概率
  71.     for (int i = 0; i < size; i++)  //size:xCells * yCells
  72.     {
  73.     if (countGrid[i] < buffer_size && countGrid[i]>0
  74.       ocGrid[i] = 0;
  75.     else if (countGrid[i] > buffer_size
  76.       ocGrid[i] = 100;
  77.     else if (countGrid[i] == 0
  78.       ocGrid[i] = 0// TODO Should be -1      
  79.     }
  80. }
  81. void updateGrid(nav_msgs::OccupancyGridPtr grid, int xCells, int yCells,
  82.                                double originX, double originY, std::vector<signed char> *ocGrid) 
  83. {
  84.     static int seq=0;
  85.     grid->header.frame_id = "map";
  86.     grid->header.seq=seq++;
  87.     grid->header.stamp.sec = ros::Time::now().sec;
  88.     grid->header.stamp.nsec = ros::Time::now().nsec;
  89.     grid->info.map_load_time = ros::Time::now();
  90.     grid->info.resolution = cellResolution;
  91.     grid->info.width = xCells;
  92.     grid->info.height = yCells;
  93.     grid->info.origin.position.x = originX;  //minx
  94.     grid->info.origin.position.y = originY;  //miny
  95.     grid->info.origin.position.z = 0;
  96.     grid->info.origin.orientation.w = 1;
  97.     grid->info.origin.orientation.x = 0;
  98.     grid->info.origin.orientation.y = 0;
  99.     grid->info.origin.orientation.z = 0;
  100.     grid->data = *ocGrid;
  101. }
  102. void computeGrid2(std::vector<signed char> &ocGrid, double xMin, double yMin,int xCells, int yCells)
  103. {
  104.     PointCloud::Ptr cpc(new PointCloud);
  105.     pcl::PassThrough<PointT> *passFilter=new pcl::PassThrough<PointT>;
  106.     passFilter->setFilterFieldName("z");
  107.     passFilter->setFilterLimitsNegative(false);//保留此区间内的数据
  108.     passFilter->setFilterLimits(0,0.5);
  109.     passFilter->setInputCloud(currentPC);
  110.     passFilter->filter(*cpc);
  111.     int size=xCells*yCells;
  112.     std::vector<int> countGrid(size);
  113.     //将每个点云分配到各个网格
  114.     for (size_t i = 0; i < cpc->size(); i++)
  115.     {
  116.     PointT p=cpc->points[i];
  117.     int xc = (int) ((p.x - xMin) / cellResolution); //取整后默认按照cellResolution将点分配到cell
  118.     int yc = (int) ((p.y - yMin) / cellResolution);
  119.     countGrid[yc * xCells + xc]++//统计一个cell中垂直方向满足条件的点数
  120.     }
  121.     for (int i = 0; i < size; i++)  //size:xCells * yCells
  122.     {
  123.     if (countGrid[i] < 10 && countGrid[i]>0
  124.       ocGrid[i] = 0;
  125.     else if (countGrid[i] > 10
  126.       ocGrid[i] = 100;
  127.     else if (countGrid[i] == 0
  128.       ocGrid[i] = 0// TODO Should be -1      
  129.     }
  130. }
  131. void callback(const PointCloud::ConstPtr& msg) 
  132. {
  133.   currentPC=msg;
  134.   ROS_INFO_STREAM("Convertor节点——接收到点云");
  135.     /*计算点云的最大和最小值*/
  136.     double xMax = 0, yMax = 0, xMin = 0, yMin = 0;
  137.     calcSize(&xMax, &yMax, &xMin, &yMin); 
  138.     cout<<"极值:"<<xMax<<" "<<yMax<<" "<<xMin<<" "<<yMin<<" "<<endl;
  139.     /* 确定栅格地图的长和宽 */
  140.     int xCells = ((int) ((xMax - xMin) / cellResolution)) + 1;
  141.     int yCells = ((int) ((yMax - yMin) / cellResolution)) + 1;
  142.     cout<<"地图大小:"<<xCells<<" "<<yCells<<endl;
  143.     /*计算栅格地图*/
  144.     std::vector<signed char> ocGrid(yCells * xCells);  //存储每个cell的值  0或者100
  145.     //computeGrid(ocGrid, xMin, yMin, xCells, yCells);
  146.     computeGrid2(ocGrid, xMin, yMin, xCells, yCells);
  147.     cout<<"成功计算得到栅格地图"<<endl;
  148.     //发布地图消息
  149.     nav_msgs::OccupancyGridPtr grid(new nav_msgs::OccupancyGrid);
  150.     updateGrid(grid, xCells, yCells, xMin, yMin, &ocGrid);
  151.     pub.publish(grid);
  152.     ROS_INFO_STREAM("Convertor节点——发布栅格地图");
  153. }
  154. int main(int argc, char** argv) 
  155. {
  156.     setlocale(LC_ALL"");
  157.     ros::init(argc, argv, "convertor_node");
  158.     ros::NodeHandle nh;
  159.     ros::Subscriber sub = nh.subscribe<PointCloud>("/point_cloud/raw"1, callback); 
  160.     pub = nh.advertise<nav_msgs::OccupancyGrid>("/map"1);
  161.     //构造占据网格消息
  162.     nav_msgs::OccupancyGridPtr grid(new nav_msgs::OccupancyGrid);
  163.     grid->header.seq = 1;
  164.     grid->header.frame_id = "map";//父坐标系
  165.     grid->info.origin.position.z = 0;
  166.     grid->info.origin.orientation.w = 1;
  167.     grid->info.origin.orientation.x = 0;
  168.     grid->info.origin.orientation.y = 0;
  169.     grid->info.origin.orientation.z = 0;
  170.     ROS_INFO_STREAM("Convertor节点初始化完成");
  171.     ros::Rate loop_rate(0.2);
  172.     ros::Duration t(10);
  173.     while (ros::ok()) 
  174.     {
  175.     ros::spinOnce();
  176.     t.sleep();
  177.     }
  178. }

    有了栅格地图,就可以进行全局路径规划了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/96203
推荐阅读
相关标签
  

闽ICP备14008679号