• attachment:pcl_cylinder.cpp of biped_robin_coffee_butler

Attachment 'pcl_cylinder.cpp'

Download

   1 #include <ros/ros.h>
   2 #include <sensor_msgs/PointCloud2.h>
   3 
   4 #include <pcl/ros/conversions.h>
   5 #include <pcl/point_types.h>
   6 #include <pcl_ros/transforms.h>
   7 #include <pcl/point_cloud.h>
   8 #include <pcl/point_types.h>
   9 #include <pcl_ros/point_cloud.h>
  10 
  11 #include <pcl/io/pcd_io.h>
  12 #include <pcl/ModelCoefficients.h>
  13 
  14 #include <pcl/filters/passthrough.h>
  15 #include <pcl/filters/extract_indices.h>
  16 
  17 #include <pcl/features/normal_3d.h>
  18 
  19 #include <pcl/sample_consensus/method_types.h>
  20 #include <pcl/sample_consensus/model_types.h>
  21 #include <pcl/segmentation/sac_segmentation.h>
  22 
  23 #include "tf/transform_broadcaster.h"
  24 #include "tf/transform_listener.h"
  25 #include "std_srvs/Empty.h"
  26 
  27 ros::Publisher plane_pub;
  28 ros::Publisher cylinder_pub;
  29 ros::Publisher filter_pub;
  30 int i = 0;
  31 bool detect = false;
  32 bool cylinder_found = false;
  33 
  34 static double table_height = 0.72;
  35 static tf::TransformBroadcaster* pBroadcaster = NULL;
  36 static tf::TransformListener* pListener = NULL;
  37 static tf::StampedTransform odom_camera_transform;
  38 static tf::Transform cylinder_transform;
  39 static sensor_msgs::PointCloud2::Ptr buffer (new sensor_msgs::PointCloud2);
  40 
  41 bool startCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
  42 {
  43 	ROS_INFO("start detecting");
  44 	detect = true;
  45 	cylinder_found = false;	
  46 	return true;
  47 }
  48 
  49 bool stopCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
  50 {
  51 	ROS_INFO("stop detecting");
  52 	detect = false;
  53 	cylinder_found = false;	
  54 	return true;
  55 }
  56 
  57 void callback(const sensor_msgs::PointCloud2::ConstPtr& cloud)
  58 {
  59 	if(cylinder_found){
  60 			pBroadcaster->sendTransform(tf::StampedTransform(cylinder_transform, ros::Time::now(), "/odom", "/cylinder_center"));	
  61 	} 	
  62 
  63 	if(i < 8 ){ //rate limiting
  64 		i++;
  65 		ros::spinOnce();
  66 	} else if (!detect){
  67 		i = 0;
  68 	} else {
  69 		i = 0;				
  70 
  71 		// filter		
  72 		pcl::PassThrough<sensor_msgs::PointCloud2> pass;
  73 		pcl::ExtractIndices<pcl::PointXYZ> extract_indices;
  74 		pcl::ExtractIndices<pcl::Normal> extract_normals;
  75 
  76 		// Normal estimation
  77 		pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
  78 		pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> segmentation_from_normals;
  79 
  80 		// Create the segmentation object
  81 		pcl::SACSegmentation<pcl::PointXYZ> seg;
  82 
  83 		pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
  84 		pcl::search::KdTree<pcl::PointXYZ>::Ptr tree2 (new pcl::search::KdTree<pcl::PointXYZ> ());
  85 		pcl::search::KdTree<pcl::PointXYZ>::Ptr tree3 (new pcl::search::KdTree<pcl::PointXYZ> ());
  86 
  87 		// The plane and cylinder coefficients
  88 		pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ());
  89 		pcl::ModelCoefficients::Ptr coefficients_plane (new pcl::ModelCoefficients ());
  90 		pcl::ModelCoefficients::Ptr coefficients_cylinder (new pcl::ModelCoefficients ());
  91 
  92 		// The plane and cylinder inliers
  93 		pcl::PointIndices::Ptr inliers (new pcl::PointIndices ());
  94 		pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices ());
  95 		pcl::PointIndices::Ptr inliers_cylinder (new pcl::PointIndices ());
  96 
  97 		// The point clouds
  98 		sensor_msgs::PointCloud2::Ptr passthrough_filtered (new sensor_msgs::PointCloud2);
  99 		sensor_msgs::PointCloud2::Ptr plane_output_cloud (new sensor_msgs::PointCloud2);
 100 		sensor_msgs::PointCloud2::Ptr cylinder_output_cloud (new sensor_msgs::PointCloud2);
 101 		sensor_msgs::PointCloud2::Ptr cloud_transformed (new sensor_msgs::PointCloud2); 
 102 
 103 		// The PointCloud
 104 		pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud (new pcl::PointCloud<pcl::PointXYZ>);
 105 		pcl::PointCloud<pcl::PointXYZ>::Ptr plane_cloud (new pcl::PointCloud<pcl::PointXYZ>);
 106 		pcl::PointCloud<pcl::PointXYZ>::Ptr plane_output (new pcl::PointCloud<pcl::PointXYZ>);
 107 		pcl::PointCloud<pcl::PointXYZ>::Ptr remove_transformed_cloud (new pcl::PointCloud<pcl::PointXYZ>);
 108 		pcl::PointCloud<pcl::PointXYZ>::Ptr cylinder_cloud (new pcl::PointCloud<pcl::PointXYZ>);
 109 		pcl::PointCloud<pcl::PointXYZ>::Ptr cylinder_output (new pcl::PointCloud<pcl::PointXYZ>);
 110 
 111 		// The cloud normals
 112 		pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal> ());        // for plane
 113 		pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2 (new pcl::PointCloud<pcl::Normal> ());       // for cylinder
 114 		pcl::PointCloud<pcl::Normal>::Ptr cloud_normals3 (new pcl::PointCloud<pcl::Normal> ()); 	  
 115 		
 116 
 117 		// Convert PointCloud2 to /odom frame
 118 		try{		
 119 			pListener->waitForTransform("/odom", (*cloud).header.frame_id, (*cloud).header.stamp, ros::Duration(10.0) );
 120 			pcl_ros::transformPointCloud ("/odom", *cloud, *cloud_transformed, *pListener);
 121 		}
 122 	catch(tf::TransformException e){
 123 			ROS_INFO("Transform_PointCloud: %s", e.what());
 124 			return;
 125 		}
 126 		
 127 		//Pass through Filtering
 128 		pass.setInputCloud (cloud_transformed);	
 129 		pass.setFilterFieldName ("x");
 130 		pass.setFilterLimits (0.35, 0.55);
 131 		pass.filter (*passthrough_filtered);
 132 
 133 		pass.setInputCloud (passthrough_filtered);
 134 		pass.setFilterFieldName ("y");
 135 		pass.setFilterLimits (-0.08, 0.22);
 136 		pass.filter (*passthrough_filtered);
 137 
 138 		pass.setInputCloud (passthrough_filtered);
 139 		pass.setFilterFieldName ("z");
 140 		pass.setFilterLimits (0.70, 0.85);
 141 		pass.filter (*passthrough_filtered);	
 142 
 143 		//publish the filtered cloud
 144 		filter_pub.publish(passthrough_filtered);	
 145 		
 146 		// Convert the sensor_msgs/PointCloud2 data to pcl/PointCloud
 147 		pcl::fromROSMsg (*passthrough_filtered, *plane_cloud);
 148 
 149 
 150 		// Estimate point normals
 151 		normal_estimation.setSearchMethod (tree2);
 152 		normal_estimation.setInputCloud (plane_cloud);
 153 		normal_estimation.setKSearch (25);
 154 		normal_estimation.compute (*cloud_normals2);
 155 
 156 		// Create the segmentation object for the planar model and set all the parameters
 157 		segmentation_from_normals.setOptimizeCoefficients (true);
 158 		segmentation_from_normals.setModelType (pcl::SACMODEL_NORMAL_PLANE);
 159 		segmentation_from_normals.setMethodType (pcl::SAC_RANSAC);
 160 		segmentation_from_normals.setNormalDistanceWeight (0.1);
 161 		segmentation_from_normals.setMaxIterations (5000);
 162 		segmentation_from_normals.setDistanceThreshold (0.06);
 163 		segmentation_from_normals.setInputCloud (plane_cloud);
 164 		segmentation_from_normals.setInputNormals (cloud_normals2);
 165 
 166 		// Obtain the plane inliers and coefficients
 167 		segmentation_from_normals.segment (*inliers_plane, *coefficients_plane);
 168 
 169 		 // Extract the planar inliers from the input cloud
 170 		extract_indices.setInputCloud (plane_cloud);
 171 		extract_indices.setIndices (inliers_plane);
 172 		extract_indices.setNegative (true);
 173 		extract_indices.filter (*cylinder_cloud);
 174 		extract_indices.setInputCloud (plane_cloud);
 175 		extract_indices.setIndices (inliers_plane);
 176 		extract_indices.setNegative (false);
 177 		extract_indices.filter (*plane_output);
 178 		extract_normals.setNegative (true);
 179 		extract_normals.setInputCloud (cloud_normals2);
 180 		extract_normals.setIndices (inliers_plane);
 181 		extract_normals.filter (*cloud_normals3);
 182 	
 183 		//colorize plane cloud and publish it
 184 		pcl::PointCloud<pcl::PointXYZRGB> plane_color;
 185 		plane_color.width    = plane_output->width;
 186 		plane_color.height   = plane_output->height;
 187 		plane_color.is_dense = true;
 188 		plane_color.points.resize (plane_color.width * plane_color.height);
 189 		plane_color.sensor_origin_ = plane_output->sensor_origin_;
 190 		plane_color.sensor_orientation_ = plane_output->sensor_orientation_;
 191 		plane_color.header = plane_output->header;
 192 
 193 		for(int i = 0; i < plane_color.size(); i++){
 194 			plane_color.points[i].x = plane_output->points[i].x;
 195 			plane_color.points[i].y = plane_output->points[i].y;		
 196 			plane_color.points[i].z = plane_output->points[i].z;
 197 			plane_color.points[i].r = 0;
 198 			plane_color.points[i].g = 240;
 199 			plane_color.points[i].b = 0;
 200 		}
 201 
 202 		pcl::toROSMsg (plane_color, *plane_output_cloud);
 203 	 	plane_pub.publish(plane_output_cloud);
 204 		
 205 		// Create the segmentation object for cylinder segmentation and set all the openniparameters
 206 		segmentation_from_normals.setOptimizeCoefficients (true);
 207 		segmentation_from_normals.setModelType (pcl::SACMODEL_CYLINDER);
 208 		segmentation_from_normals.setMethodType (pcl::SAC_RANSAC);
 209 		segmentation_from_normals.setNormalDistanceWeight (0.1);
 210 		segmentation_from_normals.setMaxIterations (5000);
 211 		segmentation_from_normals.setDistanceThreshold (0.02);
 212 		segmentation_from_normals.setRadiusLimits (0.02, 0.05);
 213 		segmentation_from_normals.setInputCloud (cylinder_cloud);
 214 		segmentation_from_normals.setInputNormals (cloud_normals3);
 215 
 216 		// Obtain the cylinder inliers and coefficients
 217 		segmentation_from_normals.segment (*inliers_cylinder, *coefficients_cylinder);
 218 
 219 		// Publish the cylinder cloud
 220 		extract_indices.setInputCloud (cylinder_cloud);
 221 		extract_indices.setIndices (inliers_cylinder);
 222 		extract_indices.setNegative (false);
 223 		extract_indices.filter (*cylinder_output);
 224 
 225 		if (cylinder_output->points.empty ()){
 226 		   std::cerr << "Can't find the cylinder component." << std::endl;
 227 			 return;		
 228 		}
 229 		
 230 		//colorize the clyinder cloud and publish it
 231 		pcl::PointCloud<pcl::PointXYZRGB> cylinder_color;
 232 		cylinder_color.width    = cylinder_output->width;
 233 		cylinder_color.height   = cylinder_output->height;
 234 		cylinder_color.is_dense = true;
 235 		cylinder_color.points.resize (cylinder_color.width * cylinder_color.height);
 236 		cylinder_color.sensor_origin_ = cylinder_output->sensor_origin_;
 237 		cylinder_color.sensor_orientation_ = cylinder_output->sensor_orientation_;
 238 		cylinder_color.header = cylinder_output->header;
 239 
 240 		for(int i = 0; i < cylinder_color.size(); i++){
 241 			cylinder_color.points[i].x = cylinder_output->points[i].x;
 242 			cylinder_color.points[i].y = cylinder_output->points[i].y;		
 243 			cylinder_color.points[i].z = cylinder_output->points[i].z;
 244 			cylinder_color.points[i].r = 238;
 245 			cylinder_color.points[i].g = 0;
 246 			cylinder_color.points[i].b = 0;
 247 		}
 248 		pcl::toROSMsg (cylinder_color, *cylinder_output_cloud);
 249 		cylinder_pub.publish(cylinder_output_cloud);		
 250 
 251 		//create a transform for the center of the cylinder
 252 		tf::Transform transform;
 253 		tf::Vector3 origin;
 254 		origin.setX(coefficients_cylinder->values[0]);
 255 		origin.setY(coefficients_cylinder->values[1]);
 256 		origin.setZ(coefficients_cylinder->values[2]);
 257 		transform.setOrigin(origin);
 258 		transform.setRotation(tf::Quaternion(0,0,0));	
 259 
 260 		double x_axis = coefficients_cylinder->values[3];
 261 		double y_axis = coefficients_cylinder->values[4];
 262 		double z_axis = coefficients_cylinder->values[5];
 263 			
 264 		ROS_INFO("x = %f", x_axis);
 265 		ROS_INFO("y = %f", y_axis);
 266 		ROS_INFO("z = %f", z_axis);
 267 		
 268 		//does the coordinate frame match our criteria
 269 		bool publish = coefficients_cylinder->values[6] > 0;
 270 		publish = publish && fabs(x_axis) < 0.2;
 271 		publish = publish && fabs(y_axis) < 0.2;	
 272 		publish = publish && fabs(z_axis) > 0.8;
 273 		publish = publish && fabs(sqrt(x_axis*x_axis+y_axis*y_axis+z_axis*z_axis)) < 1.2;		
 274 		publish = publish && transform.getOrigin().getX() > 0.35;
 275 		publish = publish && transform.getOrigin().getX() < 0.60;
 276 		publish = publish && transform.getOrigin().getY() > -0.08;
 277 		publish = publish && transform.getOrigin().getY() < 0.22;
 278 		publish = publish && transform.getOrigin().getZ() > table_height; 
 279 		publish = publish && transform.getOrigin().getZ() < table_height+0.1;
 280 	
 281 		//publish the center of the cylinder as tf_frame
 282 		if(publish){		
 283 			ROS_INFO("New cylinder frame published");
 284 			cylinder_found = true;
 285 			tf::Vector3 transform_origin = transform.getOrigin();
 286 			transform_origin.setZ(table_height + 0.05);
 287 			transform.setOrigin(transform_origin);
 288 			cylinder_transform = transform;
 289 		}	
 290 	}
 291 }
 292 
 293 int
 294 main (int argc, char** argv)
 295 {
 296   //INITIALIZE ROS
 297   ros::init (argc, argv, "extract_cylinder");
 298   ros::NodeHandle nh;
 299 	pListener = new(tf::TransformListener);
 300 	pBroadcaster = new(tf::TransformBroadcaster);
 301 	ros::ServiceServer start_srv = nh.advertiseService("start_detecting_srv", startCallback);
 302 	ros::ServiceServer stop_srv = nh.advertiseService("stop_detecting_srv", stopCallback);
 303 	
 304   ros::Subscriber sub = nh.subscribe("cloud_throttled", 1, callback);
 305 	filter_pub = nh.advertise<sensor_msgs::PointCloud2> ("filter_cloud", 1);
 306  	plane_pub = nh.advertise<sensor_msgs::PointCloud2> ("plane_cloud", 1);
 307   cylinder_pub = nh.advertise<sensor_msgs::PointCloud2> ("cylinder_cloud", 1);
 308 
 309   ros::spin();
 310 
 311   return (0);
 312 }

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2014-05-21 07:02:54, 3.0 KB) [[attachment:coffee_butler.cpp]]
  • [get | view] (2014-05-21 07:12:33, 0.6 KB) [[attachment:manifest.xml]]
  • [get | view] (2014-05-21 07:03:18, 11.8 KB) [[attachment:pcl_cylinder.cpp]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.