官方教程:
1.创建一个ROS包
$ catkin_create_pkg my_pcl_tutorial pcl_conversions pcl_ros roscpp sensor_msgs
修改package.xml 添加
<build_depend>libpcl-all-dev</build_depend>
<exec_depend>libpcl-all</exec_depend>
2.创建代码框架
创建一个名为src / example.cpp的空文件,并将以下代码粘贴到其中:
#include
// PCL specific includes
#include
#include
#include
#include
ros::Publisher pub;
void
cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input)
{
// Create a container for the data.
sensor_msgs::PointCloud2 output;
// Do data processing here...
output = *input;
// Publish the data.
pub.publish (output);
}
int main (int argc, char** argv)
{
// Initialize ROS
ros::init (argc, argv, "my_pcl_tutorial");
ros::NodeHandle nh;
// Create a ROS subscriber for the input point cloud
ros::Subscriber sub = nh.subscribe ("input", 1, cloud_cb);
// Create a ROS publisher for the output point cloud
pub = nh.advertise<sensor_msgs::PointCloud2> ("output", 1);
// Spin
ros::spin ();
}
初始化ROS,为PointCloud2数据创建订阅者和发布者。
3.将源文件添加到CMakeLists.txt
在新创建的功能包中编辑CMakeLists.txt文件,并添加:
add_executable(example src/example.cpp)
target_link_libraries(example ${catkin_LIBRARIES})
4.从PCL教程下载源代码
PCL大约有四种表示点云数据的方式,类型是:
sensor_msgs :: PointCloud — ROS消息(不建议使用)
sensor_msgs :: PointCloud2 — ROS消息
pcl :: PCLPointCloud2 — PCL数据结构主要是为了与ROS兼容
pcl :: PointCloud < T> —标准PCL数据结构
重点关注ROS消息(sensor_msgs :: PointCloud2)和标准PCL数据结构(pcl :: PointCloud < T>)。
pcl :: PCLPointCloud2也是一种重要且有用的类型:可以使用该类型直接订阅节点,并且它将自动与sensor_msgs类型进行序列化。pcl :: PCLPointCloud2
- sensor_msgs / PointCloud2
如果您想保存一些复制和粘贴的信息,可以在此处下载此示例的源文件。将文件重命名为example.cpp或编辑CMakeLists.txt即可。
sensor_msgs / PointCloud2格式是一个ROS消息,用于ROS应用的首选。
在下面的示例中,我们使用3D网格对PointCloud2结构进行下采样,从而大大减少了输入数据集中的点数。
要将此功能添加到上面的代码框架中,请执行以下步骤:
请访问http://www.pointclouds.org/documentation/,单击“教程”,然后使用VoxelGrid过滤器教程(http://www.pointclouds.org/documentation/tutorials/voxel_grid.php)导航到对PointCloud进行降采样。
阅读此处提供的代码和说明。该代码主要分为三部分:
加载云(9-19行)
处理云(第20-24行)
保存输出(第25-32行)
由于我们在上面的代码片段中使用了ROS订阅者和发布者,因此可以忽略使用PCD格式加载和保存点云数据。因此,本教程中唯一相关的部分仍然是第20-24行,它们创建PCL对象,传递输入数据并执行实际计算:
// Create the filtering object
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01, 0.01, 0.01);
sor.filter (*cloud_filtered);
在这些行中,输入数据集称为cloud,输出数据集称为cloud_filtered。需要做一些额外的工作才能将 ROS消息转换为PCL类型。修改回调函数,如下所示:
#include
...
void
cloud_cb (const sensor_msgs::PointCloud2ConstPtr& cloud_msg)
{
// Container for original & filtered data
pcl::PCLPointCloud2* cloud = new pcl::PCLPointCloud2;
pcl::PCLPointCloud2ConstPtr cloudPtr(cloud);
pcl::PCLPointCloud2 cloud_filtered;
// Convert to PCL data type
pcl_conversions::toPCL(*cloud_msg, *cloud);
// Perform the actual filtering
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud (cloudPtr);
sor.setLeafSize (0.1, 0.1, 0.1);
sor.filter (cloud_filtered);
// Convert to ROS data type
sensor_msgs::PointCloud2 output;
pcl_conversions::fromPCL(cloud_filtered, output);
// Publish the data
pub.publish (output);
}
请注意,我们必须将变量名输入更改为cloud,并将输出名更改为cloud_filtered,以便与我们复制的教程中的代码匹配。
请注意,此处效率略有下降。该fromPCL可以替换moveFromPCL防止复制整个(过滤后)的点云。但是,由于原始输入为const,因此无法以这种方式优化toPCL调用。
保存输出文件,然后构建:
$ cd %TOP_DIR_YOUR_CATKIN_HOME%
$ catkin_make
然后运行:
$ rosrun my_pcl_tutorial example input:=/narrow_stereo_textured/points2
或者,如果您正在运行兼容OpenNI的深度传感器,请尝试:
$ roslaunch openni_launch openni.launch
$ rosrun my_pcl_tutorial example input:=/camera/depth/points
您可以通过运行RViz可视化结果:
$ rosrun rviz rviz
添加“ PointCloud2 ”显示。选择camera_depth_frame的固定框架(或任何框架适合您的传感器),并选择输出为PointCloud2话题。您应该会看到高度降采样的点云。为了进行比较,您可以查看/ camera / depth / points主题,并查看已被缩减采样的数量。
- pcl/PointCloud< T>
与前面的示例一样,如果要跳过一些步骤,则可以在此处下载此示例的源文件。
所述pcl/PointCloud< T>格式表示内部PCL点云格式。
出于模块化和效率的原因,该格式在点类型上进行了模板化,并且PCL提供了与SSE对齐的模板化常见类型的列表。
以下示例中,估计在一个场景中的最大平面的平面系数。
要将此功能添加到上面的代码框架中,请执行以下步骤:
请访问http://www.pointclouds.org/documentation/,单击“教程”,然后导航至“ 平面模型细分”教程(http://www.pointclouds.org/documentation/tutorials/planar_segmentation.php)
阅读此处提供的代码和说明。该代码主要分为三部分:
创建一个云并为其填充值(第12-30行)
处理云(38-56)
写系数(58-68)
由于我们在上面的代码片段中使用ROS订阅,因此我们可以忽略第一步,而直接处理在回调中接收到的云。因此,本教程中唯一相关的部分仍然是第38-56行,它们创建PCL对象,传递输入数据并执行实际计算:
pcl::ModelCoefficients coefficients;
pcl::PointIndices inliers;
// Create the segmentation object 创建细分对象
pcl::SACSegmentation<pcl::PointXYZ> seg;
// Optional
seg.setOptimizeCoefficients (true);
// Mandatory
seg.setModelType (pcl::SACMODEL_PLANE);
seg.setMethodType (pcl::SAC_RANSAC);
seg.setDistanceThreshold (0.01);
seg.setInputCloud (cloud.makeShared ());
seg.segment (inliers, coefficients);
输入数据集名为cloud,类型为pcl :: PointCloud < pcl :: PointXYZ>,输出由一组点索引表示,这些点索引包含平面以及平面系数。cloud.makeShared()创建了一个提升的shared_ptr的对象物体云(PCL ::点云API文档)。
通过如下修改回调函数,在上面的代码片段中复制这些行:
#include
#include
#include
...
void
cloud_cb (const sensor_msgs::PointCloud2ConstPtr& input)
{
// 将sensor_msgs / PointCloud2数据转换为pcl / PointCloud
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::fromROSMsg (*input, cloud);
pcl::ModelCoefficients coefficients;
pcl::PointIndices inliers;
// Create the segmentation object
pcl::SACSegmentation<pcl::PointXYZ> seg;
// Optional
seg.setOptimizeCoefficients (true);
// Mandatory
seg.setModelType (pcl::SACMODEL_PLANE);
seg.setMethodType (pcl::SAC_RANSAC);
seg.setDistanceThreshold (0.01);
seg.setInputCloud (cloud.makeShared ());
seg.segment (inliers, coefficients);
// Publish the model coefficients发布模型系数
pcl_msgs::ModelCoefficients ros_coefficients;
pcl_conversions::fromPCL(coefficients, ros_coefficients);
pub.publish (ros_coefficients);
}
注意,我们添加了两个转换步骤:从sensor_msgs / PointCloud2到pcl / PointCloud < T>和从pcl :: ModelCoefficients到pcl_msgs :: ModelCoefficients。将发布的变量从输出更改为系数。
此外,由于我们现在要发布找到的平面模型系数而不是点云数据,因此我们必须将发布者类型从以下更改:
// Create a ROS publisher for the output point cloud,为输出点云创建ROS发布器
pub = nh.advertise<sensor_msgs::PointCloud2> ("output", 1);
// Create a ROS publisher for the output model coefficients,为输出模型系数创建ROS发布器
pub = nh.advertise<pcl_msgs::ModelCoefficients> ("output", 1);
保存输出文件,然后编译并运行上面的代码:
$ rosrun my_pcl_tutorial example input:=/narrow_stereo_textured/points2
或者,如果您正在运行兼容OpenNI的深度传感器,请尝试:
$ rosrun my_pcl_tutorial example input:=/camera/depth/points
查看输出
$ rostopic echo output