Search code examples
c++c++11cmakepoint-cloud-librarypoint-clouds

How to properly read a Point Cloud File in C++ and ROS


I just started using the Point Cloud Library and as a start I would like to read a point cloud from file. I followed the tutorial related to that. This is just a small example of a major CMake project I am building. Just slightly different from the tutorial I divided the project to make it more CMake suitable. The CMake runs well and the project seems to be organized. However when I try to run the project I get the following /home/emanuele/catkin_ws/src/map_ros/src/pointcloud_reader_node.cpp:6:10: fatal error: ../map_ros/include/cloud.h: No such file or directory #include "../map_ros/include/cloud.h" error::Cloud::readPCloud(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) and I don't know how to explain this error.

Below the snippet of code I am using:

cloud.h

#ifndef CLOUD_H
#define CLOUD_H

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <sensor_msgs/PointCloud2.h>
#include <string>

class Cloud
{
public:
    void readPCloud(std::string filename);
private:
    std::string path;
};

#endif// CLOUD_H

cloud.cpp

#include "cloud.h"

void Cloud::readPCloud(std::string filename)
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if(pcl::io::loadPCDFile<pcl::PointXYZ> (filename, *cloud) == -1) // load point cloud file
    {
        PCL_ERROR("Could not read the file");
        return;
    }
    std::cout<<"Loaded"<<cloud->width * cloud->height
             <<"data points from filename with the following fields: "
             <<std::endl;

    for(size_t i = 0; i < cloud->points.size(); ++i)
        std::cout << "    " << cloud->points[i].x
                  << " "    << cloud->points[i].y
                  << " "    << cloud->points[i].z << std::endl;
}

pointcloud_reader_node.cpp

#include <ros/ros.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include "../map_ros/include/cloud.h"

using namespace std;

int main()
{
    std::string fstring = "/home/to/Desktop/file.pcd";
    Cloud p;
    p.readPCloud(fstring); // <-- Error Here
    return 0;
}

Also for completeness I am adding the CMake file below:

cmake_minimum_required(VERSION 2.8.3)
project(map_ros)

add_compile_options(-std=c++11)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
find_package(catkin REQUIRED COMPONENTS
    // ....
    )

catkin_package(
  INCLUDE_DIRS include
  LIBRARIES ${PROJECT_NAME}
  CATKIN_DEPENDS
    // ......
)

###########
## Build ##
###########

include_directories(${catkin_INCLUDE_DIRS})
add_executable(pointcloud_reader_node src/pointcloud_reader_node.cpp ${SRCS})
target_link_libraries(pointcloud_reader_node ${catkin_LIBRARIES})

Solution

  • I have figured out the problem to my question some time ago but wanted to share it in case someone has my same problem. So there were two issues coming at the same time that made me think it was a CMake problem only:

    1) catkin_make was not properly compiling not because of CMake as I thought for a long time, but because the cache file catkin_ws.workspace was causing problem to CMake itself. So the first solution to this problem was to erase the cache file catkin_ws.workspace and do a fresh compile. All CMake issues disappeared.

    2) Second problem: The correct pseudo code for reading the point-cloud it was like:

    main()
    {
        init node
        create pointcloud publisher
        create rate object with 1 second duration
        load point cloud from file
        while(ros::ok())
        {
            rate.sleep
    
            publish point cloud message
        }
    }
    

    And I realized nothing was being published on the input and the callback was executed. Below the complete code that reads point-cloud from file and gives an output of all points to a .txt file. I hope this can be helpful to anyone who may encounter this problem:

    test.cpp

    #include <ros/ros.h>
    #include <sensor_msgs/PointCloud2.h>
    #include <pcl/io/pcd_io.h>
    #include <pcl_conversions/pcl_conversions.h>
    #include <pcl/point_cloud.h>
    #include <pcl/point_types.h>
    #include <pcl/filters/voxel_grid.h>
    
    void loadFromFile(std::string filename)
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
        if(pcl::io::loadPCDFile<pcl::PointXYZ> (filename, *cloud) == -1) // load point cloud file
        {
            PCL_ERROR("Could not read the file");
            return;
        }
        std::cout<<"Loaded"<<cloud->width * cloud->height
                 <<"data points from /home/to/Desktop/point_cloud/yourFile.pcd with the following fields: "
                 <<std::endl;
    
    // Write entire point clouds to a .txt file
            std::ofstream myfile;
            myfile.open ("/home/to/Desktop/exampleCloud.txt");
            if (myfile.is_open()) {
                for(size_t i = 0; i <   cloud->points.size(); ++i)
                       myfile << " " << cloud->points[i].x
                              << " " << cloud->points[i].y
                              << " " << cloud->points[i].z << std::endl;
                myfile.close();
        }
    }
    
    int main (int argc, char** argv)
    {
        // Initialize ROS
        ros::init (argc, argv, "pcl_tutorial_cloud");
        ros::NodeHandle nh;
        ros::Publisher pub = nh.advertise<sensor_msgs::PointCloud2>("output", 1000);
        ros::Rate loop_rate(1);
        loadFromFile("/home/to/Desktop/yourFile.pcd");
        int count = 0;
        while(ros::ok())
        {
            sensor_msgs::PointCloud2 pcloud2;
            pub.publish(pcloud2);
            ros::spinOnce();
            loop_rate.sleep();
            count ++;
        }
        return 0;
    }
    

    Here is the result after running :

    1) catkin_make

    2) rosrun yourProject test

    pcl_read