ROS里面已经预装好了pcl,和一些与pcl之间的转换,我们接下来看看如何在ros里面使用pcl.。
总的来说,PCL包含了一个很重要得到数据结构,叫PointCloud,这是一个模板类,把点的类型作为模板参数。
下面是最重要的在点云里面的公共域
header 这个域是pcl::PCLHeader类型和指定点云的获取时间。
points:这个域是std::vector<PointT,..>类型,是点云存储的容器。PointT是类模板参数。
width:这个域指定点云的宽度在组织一个图像的时候,否则只有一个。
height:这个域指定点云的高度,没有指定则只有一个。
is_dense:这个域指定点云是否包含无效值(infinite或者NaN)
sensor_origin_:这个域是Eigen::Vector4f 类型,它定义 了传感器的获取姿势就一个区域的转换而言。
sensor_orientation_:这个域是Eigen::Quaternion类型,他定义了sensor作为一个旋转的角度而言。
了解了点云的数据结构以后,下面就可以了解不同点云的类型,pcl是怎么工作的,已及pcl与ROS间的关系。
不同的点云类型
前面所说的,pcl::PointCloud包含一个域,它作为点的容器,这个域是PointT类型的,这个域是PointT类型的是pcl::PointCloud类的模板参数,定义了点云的存储类型。PCL定义了很多类型的点,下面是一些最常用的:
pcl::PointXYZ 这是最简单的点的类型,存储着点的x,y,z信息。
pcl::PointXYZI:这个类型的点是和前面的那个很相似的,但是他也包含一个域描述了点的密集程度。另外还有两个其他的标准的特殊的点的类型:第一个是pcl::InterestPoint,它有一个域去存储长处而不是密集度。pcl::PointWithRange,存储了点的范围(深度).
pcl::PointXYZRGBA:这个类型的点存储了3D信息同时和RGB与Alpha(透明度)
pcl::PointXYZRGB
pcl::Normal:这是一个最常用的点的类型,它代表了给定点的 曲面法线(normal翻译为法线有点奇怪)和曲率的测量。
pcl::PointNormal:这个类型和前面那个一样。只不过它多了坐标(x,y,z)。他的变体有PointXYZRGBNormal和PointXYZINormal,就像名字所说的一样,前者包含颜色,后者包含密集度。
除了以上这些常用的点的类型,还有很多 标准的其他的PCL类型,比如PointWithViewpoint,MomentInvariants,Boundary,PrincipalCurvatures,Histogram.更重要的是在PCL里面除了这些类型,用户还可以自己定义自己的类型。
PCL里面的算法
PCL用一个很特别的设计模式贯穿整个库去定义点云处理算法。总体来说,上面这些类型的算法是高度配置的,为了开发他们的潜能,库必须要提供一个机制对用户来指定哪些参数是需要的,哪些是默认的。
为了解决这个问题,PCL的开发者决定去使每个算法属于一个特定共同点下的同层次的类。这个方式允许PCL开发者通过派生和添加参数值的方式,复用存在的算法。它也允许用户去提供参数值,剩余的是默认值。下面是一小段代码当使用PCL算法时看起来的样子:
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::Po
intXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr result(new pcl::PointCloud<pcl::P
ointXYZ>);
pcl::Algorithm<pcl::PointXYZ> algorithm;
algorithm.setInputCloud(cloud);
algorithm.setParameter(1.0);
algorithm.setAnotherParameter(0.33);
algorithm.process (*result);
PCL对ROS的接口
PCL对ROS的接口提供PCL数据结构的交流,通过通过ROS提供的以消息为基础的交流系统。为了这么做,有几个消息类型交流系统提供的去把点云和其他数据进行涵盖。为了结合这些数据类型,一系列的转换函数提供用来转换原始的PCL数据类型成消息型。一些最有用的message类型列举在下面。
std_msgs:Header:这不是真的消息类型,但是他用在Ros消息里面的每一个部分。它包含了消息被发送的时间和序列号和框名。PCL等于pcl::Header类型
sensor_msgs::PointCloud2:这是最重要的类型。这个消息通常是用来转换pcl::PointCloud类型的,然而,它是很重要的去了解pcl::PCLPointCloud2这个类型,因为前面版本的可能被废除。
pcl_msgs::PointIndices:这个类型存储属于点云里面的点的下标,在pcl里面等于pcl::PointIndices
pcl_msgs::PolygonMesh这个类型包括消息需要描述多边形网眼,就是顶点和边,在pcl里面等于pcl::PolygonMesh
pcl_msgs::Vertices:这个类型包含了一系列的顶点作为一个数组的下标,来描述一个多边形。在pcl里面等于pcl::Vertices
pcl_msgs::ModelCoefficients:这存储了一个模型的不同的系数,比如描述一个平面需要4个系数。在PCL里面等于pcl::ModelCoefficients
上面的数据可以从PCL转成ROS里面的PCL。所有的函数有一个类似的特征,意味着一旦我们知道这样去转换一个类型,我们就能学会转换其他的类型。下面的函数是在pcl_conversions命名空间里面提供的函数
void fromPCL(const <PCL Type> &, <ROS Message type> &);
void moveFromPCL(<PCL Type> &, <ROS Message type> &);
void toPCL(const <ROS Message type> &, <PCL Type> &);
void moveToPCL(<ROS Message type> &, <PCL Type> &);
这里,PCL类型必须被替换成先前指定的PCL类型和ROS里面相应的类型。sensor_msgs::PointCloud2有一个特定的函数集去执行转换
voidtoROSMsg(const pcl::PointCloud<T> &, sensor_msgs::PointCloud2 &);
void fromROSMsg(const sensor_msgs::PointCloud2 &, pcl::PointCloud<T>
&);
void moveFromROSMsg(sensor_msgs::PointCloud2 &, pcl::PointCloud<T> &);
你可能会对每个函数的不同感到奇怪还有它的move版本。其实是正常版本执行的是一个深拷贝(完全拷贝),而move版的是浅拷贝,并使源数据作废。
上面废话了这么多,可以来写代码了,不过小伙伴们不要激动,这不是虽然万恶的"hello world",但也没啥特殊的效果。
先建一个包
catkin_create_pkg chapter6_tutorials pcl_conversions pcl_ros pcl_msgs
sensor_msgs
然后再建一个cpp文件,叫pcl_sample的cpp文件
/*
*File Name pcl_sample
*Author shukai
*Date Mon Apr 4 09:29:48 CDT 2016
*Description A simple pcl demo
*/
#include<ros/ros.h>
#include<pcl/point_cloud.h>
#include<pcl_ros/point_cloud.h>
#include<pcl_conversions/pcl_conversions.h>
#include<sensor_msgs/PointCloud2.h>
int main(int argc,char** argv)
{
ros::init(argc,argv,"pcl_sample");
ros::NodeHandle nh;
ros::Publisher pcl_pub = nh.advertise<sensor_msgs::PointCloud2>("pcl_output",1);
sensor_msgs::PointCloud2 output;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
cloud->width = 100;
cloud->height= 1;
cloud->points.resize(cloud->width*cloud->height);
//Convert the cloud to ROS message
pcl::toROSMsg(*cloud,output);
pcl_pub.publish(output);
ros::spinOnce();
return 0;
}
这个程序的主要目的是建立一个有效的使用PCL的节点,同时看看编译有没有什么问题。
然后接着在CMakelist.txt里面加入以下的东西
寻找系统里面的PCL库
find_package(PCL REQUIRED)
include_directories(include ${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS}
然后下面是生成可执行文件和链接相应的库
add_executable(pcl_sample src/pcl_sample.cpp)
target_link_libraries(pcl_sample ${catkin_LIBRARIES} ${PCL_LIBRARIES})
最后用catkin_make就可以了