当前位置:   article > 正文

3D激光SLAM点云地图pcd转导航可用的2D栅格地图_pcd2pgm

pcd2pgm

本文旨在帮助读者将激光点云地图转为2D栅格地图,以便完成路径规划与导航。本方法将pcd转为pgm的原理是将接收到的点云信息以"/map"话题的形式发布,用map_server来接收"/map"话题,保存2D栅格地图!

废话不多说,直接开始!

一、安装pcd2pgm

  1. #创建工作空间
  2. mkdir -p ~/pcd2pgm_ws/src
  3. cd ~/pcd2pgm_ws/src
  4. catkin_init_workspace
  5. #克隆代码
  6. git clone https://github.com/hujiax380/pcd2pgm.git

————————————————————————————————

针对评论区各位的问题,修改了部分内容,用下面代码覆盖test.cpp

需要修改pcd文件的路径以及名称

  1. #include <ros/ros.h>
  2. #include <nav_msgs/OccupancyGrid.h>
  3. #include <nav_msgs/GetMap.h>
  4. #include <sensor_msgs/PointCloud2.h>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl_conversions/pcl_conversions.h>
  7. #include <pcl/point_types.h>
  8. std::string file_directory;
  9. std::string file_name;
  10. std::string pcd_file;
  11. std::string map_topic_name;
  12. const std::string pcd_format = ".pcd";
  13. nav_msgs::OccupancyGrid map_topic_msg;
  14. double map_resolution = 0.05;
  15. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_PassThrough(new pcl::PointCloud<pcl::PointXYZ>);
  16. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_after_Radius(new pcl::PointCloud<pcl::PointXYZ>);
  17. pcl::PointCloud<pcl::PointXYZ>::Ptr pcd_cloud(new pcl::PointCloud<pcl::PointXYZ>);
  18. void SetMapTopicMsg(const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, nav_msgs::OccupancyGrid& msg);
  19. int main(int argc, char** argv)
  20. {
  21. ros::init(argc, argv, "pcl_filters");
  22. ros::NodeHandle nh;
  23. ros::NodeHandle private_nh("~");
  24. ros::Rate loop_rate(1.0);
  25. private_nh.param("file_directory", file_directory, std::string("/home/ubuntu/"));//此处需要修改为自己pcd文件的路径
  26. ROS_INFO("*** file_directory = %s ***\n", file_directory.c_str());
  27. private_nh.param("file_name", file_name, std::string("pcd_name"));//此处"pcd_name"需要修改为自己的pcd文件名,无需.pcd
  28. ROS_INFO("*** file_name = %s ***\n", file_name.c_str());
  29. pcd_file = file_directory + file_name + pcd_format;
  30. ROS_INFO("*** pcd_file = %s ***\n", pcd_file.c_str());
  31. private_nh.param("map_resolution", map_resolution, 0.05);
  32. private_nh.param("map_topic_name", map_topic_name, std::string("map"));
  33. ros::Publisher map_topic_pub = nh.advertise<nav_msgs::OccupancyGrid>(map_topic_name, 1);
  34. if (pcl::io::loadPCDFile<pcl::PointXYZ> (pcd_file, *pcd_cloud) == -1)
  35. {
  36. PCL_ERROR ("Couldn't read file: %s \n", pcd_file.c_str());
  37. return (-1);
  38. }
  39. std::cout << "输入点云点数:" << pcd_cloud->points.size() << std::endl;
  40. SetMapTopicMsg(pcd_cloud, map_topic_msg);
  41. while(ros::ok())
  42. {
  43. map_topic_pub.publish(map_topic_msg);
  44. loop_rate.sleep();
  45. ros::spinOnce();
  46. }
  47. return 0;
  48. }
  49. void SetMapTopicMsg(const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, nav_msgs::OccupancyGrid& msg)
  50. {
  51. msg.header.seq = 0;
  52. msg.header.stamp = ros::Time::now();
  53. msg.header.frame_id = "map";
  54. msg.info.map_load_time = ros::Time::now();
  55. msg.info.resolution = map_resolution;
  56. double x_min, x_max, y_min, y_max; //这里是投影到xy平面,如果要投到xz/yz,这里以及后面的xy对应的数据改为你想投影的平面
  57. if(cloud->points.empty())
  58. {
  59. ROS_WARN("pcd is empty!\n");
  60. return;
  61. }
  62. for(int i = 0; i < cloud->points.size() - 1; i++)
  63. {
  64. if(i == 0)
  65. {
  66. x_min = x_max = cloud->points[i].x;
  67. y_min = y_max = cloud->points[i].y;
  68. }
  69. double x = cloud->points[i].x;
  70. double y = cloud->points[i].y;
  71. if(x < x_min) x_min = x;
  72. if(x > x_max) x_max = x;
  73. if(y < y_min) y_min = y;
  74. if(y > y_max) y_max = y;
  75. }
  76. msg.info.origin.position.x = x_min;
  77. msg.info.origin.position.y = y_min;
  78. msg.info.origin.position.z = 0.0;
  79. msg.info.origin.orientation.x = 0.0;
  80. msg.info.origin.orientation.y = 0.0;
  81. msg.info.origin.orientation.z = 0.0;
  82. msg.info.origin.orientation.w = 1.0;
  83. msg.info.width = int((x_max - x_min) / map_resolution);
  84. msg.info.height = int((y_max - y_min) / map_resolution);
  85. msg.data.resize(msg.info.width * msg.info.height);
  86. msg.data.assign(msg.info.width * msg.info.height, 0);
  87. ROS_INFO("data size = %d\n", msg.data.size());
  88. for(int iter = 0; iter < cloud->points.size(); iter++)
  89. {
  90. int i = int((cloud->points[iter].x - x_min) / map_resolution);
  91. if(i < 0 || i >= msg.info.width) continue;
  92. int j = int((cloud->points[iter].y - y_min) / map_resolution);
  93. if(j < 0 || j >= msg.info.height - 1) continue;
  94. msg.data[i + j * msg.info.width] = 100;
  95. }
  96. }

修改之后完成编译:

  1. cd ~/pcd2pgm_ws
  2. catkin_make

二、转换地图

编译成功后:

  1. roscore
  2. #另起终端
  3. rosrun pcd2pgm pcd2topic

终端显示pcd文件信息:

 另起终端启动map_server

  1. #另起终端,保存地图
  2. rosrun map_server map_saver

如此就生成可用作2D导航的yaml与pgm文件!

本文主要参考:pcd转pgm/3d点云转2d灰度图

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

闽ICP备14008679号