PCL八叉树 std::bad_alloc c++问题

3

我正在使用PCl库来压缩激光雷达数据。然后,我使用自定义消息通过ROS网络发送数据。为此,我有一个压缩节点和一个解压缩节点。如果我运行压缩节点,一切都按预期工作。但是,当调用decodePointCloud()函数时,解压缩节点会出现std::bad_alloc错误。

为了进行调试,我将解压缩代码复制到了压缩程序中。现在,当我运行压缩程序时,它可以正常工作。激光雷达数据首先被压缩,然后在同一文件中被解压缩。我通过可视化软件rviz进行了验证。

为什么当我在不同的节点中运行代码时,解压缩工作不正常,但是在同一节点中进行解压缩时却可以工作呢?我最初认为是由于缺乏内存,但是当我在同一节点中解压缩数据时,它也能够正常工作。我认为这应该需要大约相同的内存。

我在配置为Ubuntu 18.04、5GB RAM和4个处理器的虚拟机上运行两个程序。

压缩程序代码:

#include <stdint.h>
#include <ros/ros.h>
// PCL specific includes
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>


#include <inttypes.h>
#include <pcl/compression/octree_pointcloud_compression.h>
#include <stdio.h>
#include <sstream>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <std_msgs/String.h>
#include <bitset>
#include <std_msgs/UInt8MultiArray.h>
#include <stdint.h>
#include <iostream>
#include <vector>
#include <iterator>

//blob message
#include "my_pcl_tutorial/Blob.h"

ros::Publisher pub;

pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA>* PointCloudEncoder;



void 
cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input)
{
  // Create a container for the data.
  std::string output;
  std_msgs::String outputString;

  //convert to pointxyzrgba type
  pcl::PCLPointCloud2 pcl_pc2;
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr temp_cloud (new pcl::PointCloud<pcl::PointXYZRGBA>);//convert to pointer to satisfy function requirement
  pcl_conversions::toPCL(*input, pcl_pc2);
  pcl::fromPCLPointCloud2(pcl_pc2, *temp_cloud); 

  // stringstream to store compressed point cloud
  std::stringstream compressedData; 

  // compress point cloud
  PointCloudEncoder->encodePointCloud (temp_cloud, compressedData);


  compressedData.seekg(0,ios::end);
  int size = compressedData.tellg();
  compressedData.seekg(0,ios::beg);
  std::cout<<size<<std::endl;


  char * buffer = new char[size];

  compressedData.read(buffer,size);

  uint8_t * tempor = reinterpret_cast<uint8_t *>(buffer);
  std::vector<unsigned char> v(tempor, tempor + size);
  std::cout<<"Size: "<<v.size()<<std::endl;


  my_pcl_tutorial::Blob blobmsg;
  blobmsg.data=v;
  blobmsg.size=size;

  sensor_msgs::PointCloud2 pointcloudheader;
  pointcloudheader = *input;
  blobmsg.header = pointcloudheader.header;


//////////////////////////////////////////////
/*
  //converting back, used for testing
  std::stringstream test25;

  std::vector<unsigned char> v2(blobmsg.data);
std::cout<<"Size2: "<<v2.size()<<std::endl;
std::cout<<"Size of message: "<<blobmsg.size<<std::endl;

  std::copy(v2.begin(), v2.end(), std::ostream_iterator<unsigned char>(test25));
std::cout<<"debug"<<std::endl;

  test25.seekg(0,ios::end);
  int size2 = test25.tellg();
  test25.seekg(0,ios::beg);
  std::cout<<size2<<std::endl;

  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudOut (new pcl::PointCloud<pcl::PointXYZRGBA> ());
  //decompress
  PointCloudDecoder->decodePointCloud (test25, cloudOut);




  sensor_msgs::PointCloud2 outputmessage;
  std::cout<<"Convert to right format now .."<<std::endl;
  //save header info since toROSmsg throws away this information
  //convert to pointcloud2
  pcl::toROSMsg(*cloudOut, outputmessage);
  outputmessage.header = blobmsg.header;
  std::cout<<outputmessage.header<<std::endl;

/**/

/////////////////////////////


  // Publish the data.
  pub.publish (blobmsg);
}

int
main (int argc, char** argv)
{
  // Initialize ROS
  ros::init (argc, argv, "my_pcl_tutorial");
  ros::NodeHandle nh;


  //\\
  //setup compression algorithm


  bool showStatistics = false;

  pcl::io::compression_Profiles_e compressionProfile = pcl::io::LOW_RES_ONLINE_COMPRESSION_WITHOUT_COLOR;

  // instantiate point cloud compression for encoding and decoding
  PointCloudEncoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> (compressionProfile, showStatistics);
  //\\



  // Create a ROS subscriber for the input point cloud
  ros::Subscriber sub = nh.subscribe ("velodyne_points", 1, cloud_cb);

  // Create a ROS publisher for the output point cloud
  pub = nh.advertise<my_pcl_tutorial::Blob> ("velodyne_points/compressed", 1);

  // Spin
  ros::spin ();

  delete(PointCloudEncoder);
}


解压代码:

#include <stdint.h>
#include <ros/ros.h>
// PCL specific includes
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>

#include <inttypes.h>
#include <pcl/compression/octree_pointcloud_compression.h>
#include <stdio.h>
#include <sstream>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <std_msgs/String.h>
#include <iostream>
#include <cstring>


#include <bitset>
#include <std_msgs/UInt8MultiArray.h>
#include <stdint.h>
#include <iostream>
#include <vector>
#include <iterator>

//blob message
//#include "decompression/Blob.h"
#include <my_pcl_tutorial/Blob.h>

ros::Publisher pub;


pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA>* PointCloudDecoder;




void 
cloud_cb (const my_pcl_tutorial::Blob& input)
{


  //converting back, used for testing
  std::stringstream test25;

  std::vector<unsigned char> v2(input.data);
std::cout<<"Size2: "<<v2.size()<<std::endl;
std::cout<<"Size of message: "<<input.size<<std::endl;

  std::copy(v2.begin(), v2.end(), std::ostream_iterator<unsigned char>(test25));
std::cout<<"debug"<<std::endl;

  test25.seekg(0,ios::end);
  int size2 = test25.tellg();
  test25.seekg(0,ios::beg);
  std::cout<<size2<<std::endl;

  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudOut (new pcl::PointCloud<pcl::PointXYZRGBA> ());
  //decompress
  PointCloudDecoder->decodePointCloud (test25, cloudOut);




  sensor_msgs::PointCloud2 outputmessage;
  std::cout<<"Convert to right format now .."<<std::endl;
  //save header info since toROSmsg throws away this information
  //convert to pointcloud2
  pcl::toROSMsg(*cloudOut, outputmessage);
  outputmessage.header = input.header;
  std::cout<<outputmessage.header<<std::endl;

  pub.publish(outputmessage);
}

int
main (int argc, char** argv)
{
  // Initialize ROS
  ros::init (argc, argv, "decompressLidar");
  ros::NodeHandle nh;

  //\\
  //setup compression algorithm

  PointCloudDecoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> ();
  //\\



  // Create a ROS subscriber for the input point cloud
  ros::Subscriber sub = nh.subscribe ("velodyne_points/compressed", 1, cloud_cb);

  // Create a ROS publisher for the output point cloud
  pub = nh.advertise<sensor_msgs::PointCloud2> ("decompress", 1);

  // Spin
  ros::spin ();

  //delete(PointCloudDecoder);
}
1个回答

0

看起来你正在正确地使用/调用pcl函数。我有些怀疑。除非我漏掉了什么,decodePointCloud 调用的唯一一个可能会抛出 bad alloc 的函数是 vector::reserve。因此,我怀疑你的内存不够用。关于非 ROS 分配/使用内存,请参见其他 SO 帖子(ex)。至于同一节点与不同节点之间的区别,这就是节点和nodelet之间的精确区别:

Nodelets旨在提供一种在单个进程中,在单个机器上运行多个算法的方式,而不会在传递进程内消息时产生复制成本。roscpp具有优化功能,可以在同一节点内的发布和订阅调用之间进行零拷贝指针传递。为了实现这一点,nodelets允许将类动态加载到同一节点中,但它们提供简单的分离命名空间,使得nodelet表现得像一个独立的节点,尽管它位于同一进程中。这已经进一步扩展,可以使用pluginlib在运行时动态加载。
另请参见this answer

谢谢您的回答。我已将内存增加到6GB,但没有帮助。您有任何想法如何强制nodelet不要“聪明”,让它产生复制成本吗?这样我就可以确定是否缺乏内存是问题所在了。 - user71649
现在,你没有使用nodelets。ROS nodelets基本上是将“一切放在一个节点中”的高级方法,然而,当你在一个节点中运行它时,你所看到的就是复制被有意优化掉了。将它们分开运行是没有优化的。ROS事先复制/分配的内存。它设置了通过连接传输的数据大小的期望值(参见TransportHints,可配置)。在调用decodePointCloud之前,在解码器中有办法查看你的内存使用情况,参见示例 - JWCS
我成功解决了问题。这只是启动顺序的问题。我过去习惯先启动rosbag,然后是压缩节点,最后是解压缩节点。这就是我遇到错误的原因。当我首先启动压缩节点,然后是解压缩节点,最后再启动rosbag时,一切都正常工作了。感谢您的时间。 - user71649

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接