@@ -13,7 +13,7 @@ target_link_libraries(ground_plane_segmentation ${catkin_LIBRARIES})
1313*/
1414
1515#include " object_detection/boost.h"
16- #include < ros/ros .h>
16+ #include < visualization_msgs/Marker .h>
1717
1818// TF includes
1919#include < tf/tf.h>
@@ -57,6 +57,7 @@ ros::Publisher coef_pub;
5757ros::Publisher bbox_pub;
5858ros::Publisher template_pub;
5959ros::Publisher pose_pub;
60+ ros::Publisher marker_pub;
6061
6162// Globals
6263bool invert;
@@ -66,24 +67,72 @@ string input_topic;
6667string output_topic;
6768string coefficients_topic;
6869
70+ int argmin = -1 ;
6971Eigen::Matrix4d icp_transform;
70- string template_cuboid_filename ;
72+ vector<Eigen::Matrix4d> icp_transforms ;
7173sensor_msgs::PointCloud2 bbox_msg;
7274sensor_msgs::PointCloud2 output_msg;
7375sensor_msgs::PointCloud2 template_msg;
7476tf::TransformListener* listener;
7577geometry_msgs::Pose pose_msg;
7678Eigen::Affine3d pose_transform;
77- double dimensions[3 ] ;
79+ double dimensions[] = { 0.1 , 0.02 , 0.02 } ;
7880double icp_fitness_score;
7981pcl::PCLPointCloud2::Ptr input_pcl (new pcl::PCLPointCloud2);
8082
83+ // Template paths
84+ string template_path;
85+ string template_filenames[] = { " " , " screwdriver_ascii_tf.pcd" , " eraser_ascii_tf.pcd" ,
86+ " clamp_ascii_tf.pcd" , " marker_ascii_tf.pcd" };
87+
8188// Flags
8289bool DEBUG = false ;
8390bool ICP_SUCCESS = false ;
8491bool FIRST = true ;
8592bool POSE_FLAG = false ;
8693
94+ void publish_grasp_marker (geometry_msgs::Pose& p)
95+ {
96+ visualization_msgs::Marker marker;
97+ // Set the frame ID and timestamp. See the TF tutorials for information on these.
98+ marker.header .frame_id = " camera_depth_optical_frame" ;
99+ marker.header .stamp = ros::Time::now ();
100+
101+ // Set the namespace and id for this marker
102+ marker.ns = " grasp_pose" ;
103+ marker.id = 0 ;
104+
105+ // Set the marker type. Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
106+ marker.type = visualization_msgs::Marker::CUBE;
107+
108+ // Set the marker action. Options are ADD, DELETE, and new in ROS Indigo: 3 (DELETEALL)
109+ marker.action = visualization_msgs::Marker::ADD;
110+
111+ // Set the pose of the marker. This is a full 6DOF pose relative to the frame/time specified in the header
112+ marker.pose .position .x = p.position .x ;
113+ marker.pose .position .y = p.position .y ;
114+ marker.pose .position .z = p.position .z ;
115+ marker.pose .orientation .x = p.orientation .x ;
116+ marker.pose .orientation .y = p.orientation .y ;
117+ marker.pose .orientation .z = p.orientation .z ;
118+ marker.pose .orientation .w = p.orientation .w ;
119+
120+ // Set the scale of the marker -- 1x1x1 here means 1m on a side
121+ marker.scale .x = dimensions[0 ];
122+ marker.scale .y = dimensions[1 ];
123+ marker.scale .z = dimensions[2 ];
124+
125+ // Set the color -- be sure to set alpha to something non-zero!
126+ marker.color .r = 1 .0f ;
127+ marker.color .g = 0 .0f ;
128+ marker.color .b = 0 .0f ;
129+ marker.color .a = 0 .5f ;
130+
131+ // Publish the marker
132+ marker.lifetime = ros::Duration ();
133+ marker_pub.publish (marker);
134+ }
135+
87136void publish_pose (Eigen::Matrix4d H)
88137{
89138 // Set translation
@@ -113,6 +162,9 @@ void publish_pose(Eigen::Matrix4d H)
113162 p.orientation .z = quaternion.z ();
114163 p.orientation .w = quaternion.w ();
115164
165+ // Publish visualization marker
166+ publish_grasp_marker (p);
167+
116168 // Broadcast the transforms
117169 static tf::TransformBroadcaster br;
118170 br.sendTransform (tf::StampedTransform (transform, ros::Time::now (), " camera_depth_optical_frame" , " object_frame" ));
@@ -141,24 +193,23 @@ void publish_bounding_box(Eigen::Matrix4d H)
141193 pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud (new pcl::PointCloud<pcl::PointXYZ>);
142194 pcl::transformPointCloud (box_cloud, *transformed_cloud, H.cast <float >());
143195
144- if (FIRST) {
145- FIRST = false ;
146- cout << " Bounding Box Points:" << endl;
147- for (int i = 0 ; i < transformed_cloud->size (); i++) {
148- cout << " X: " << transformed_cloud->points [i].x << " | "
149- << " Y: " << transformed_cloud->points [i].y << " | "
150- << " Z: " << transformed_cloud->points [i].z << endl;
151- }
152- }
196+ // cout << "Bounding Box Points:" << endl;
197+ // for (int i = 0; i < transformed_cloud->size(); i++)
198+ // {
199+ // cout << "X: " << transformed_cloud->points[i].x << " | "
200+ // << "Y: " << transformed_cloud->points[i].y << " | "
201+ // << "Z: " << transformed_cloud->points[i].z << endl;
202+ // }
153203
154204 // Convert to ROS data type and publish
155205 pcl::toROSMsg (*transformed_cloud, bbox_msg);
156206 bbox_msg.header .frame_id = " camera_depth_optical_frame" ;
157207 bbox_pub.publish (bbox_msg);
158208}
159209
160- void icp_registration (pcl::PointCloud<pcl::PointXYZ>::Ptr input_pcl, pcl::PointCloud<pcl::PointXYZ>::Ptr template_pcl)
210+ double icp_registration (pcl::PointCloud<pcl::PointXYZ>::Ptr input_pcl, pcl::PointCloud<pcl::PointXYZ>::Ptr template_pcl)
161211{
212+ int max_iter = 0 ;
162213 while (1 ) {
163214 // Point cloud containers
164215 pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud (new pcl::PointCloud<pcl::PointXYZ>);
@@ -173,21 +224,22 @@ void icp_registration(pcl::PointCloud<pcl::PointXYZ>::Ptr input_pcl, pcl::PointC
173224 icp.setEuclideanFitnessEpsilon (icp_fitness_score);
174225 icp.setRANSACOutlierRejectionThreshold (1.5 );
175226 icp.align (*output_cloud);
176- icp_transform = icp.getFinalTransformation ().cast <double >().inverse ();
227+ Eigen::Matrix4d icp_transform_local = icp.getFinalTransformation ().cast <double >().inverse ();
228+ icp_transforms.push_back (icp_transform_local);
177229
178230 cerr << " ICP Score Before: " << icp.getFitnessScore () << endl;
231+ max_iter++;
179232
180- if (icp.hasConverged () && icp.getFitnessScore () < icp_fitness_score) {
233+ if (( icp.hasConverged () && icp.getFitnessScore () < icp_fitness_score) || (max_iter > 10 ) ) {
181234 // Display ICP results
182235 cerr << " \n ICP Score: " << icp.getFitnessScore () << endl;
183236 cerr << " ICP Transform:\n "
184- << icp_transform << endl;
237+ << icp_transform_local << endl;
185238
186239 // Convert to ROS data type
187240 pcl::toROSMsg (*output_cloud, output_msg);
188241 pcl::toROSMsg (*template_pcl, template_msg);
189- ICP_SUCCESS = true ;
190- return ;
242+ return icp.getFitnessScore ();
191243 }
192244 }
193245}
@@ -200,11 +252,11 @@ void pcl_callback(const sensor_msgs::PointCloud2ConstPtr& input)
200252 cerr << " PointCloud before filtering: " << input_pcl->width << " " << input_pcl->height << " data points." << endl;
201253
202254 // Publish template point cloud
203- if (ICP_SUCCESS) {
255+ if (ICP_SUCCESS and argmin != - 1 ) {
204256 icp_pub.publish (output_msg);
205257 template_msg.header .frame_id = " camera_depth_optical_frame" ;
206258 template_pub.publish (template_msg);
207- publish_bounding_box (icp_transform);
259+ // publish_bounding_box(icp_transform);
208260 publish_pose (icp_transform);
209261 }
210262}
@@ -274,7 +326,7 @@ bool service_callback(object_detection::ObjectDetection::Request& req,
274326 pcl::PassThrough<pcl::PCLPointCloud2> pass_z2;
275327 pass_z2.setInputCloud (plane_cloud_ptr);
276328 pass_z2.setFilterFieldName (" z" );
277- pass_z2.setFilterLimits (0.0 , 0.7 );
329+ pass_z2.setFilterLimits (0.0 , 0.75 );
278330 pass_z2.filter (*cloud_filtered_ptr_z2);
279331 if (DEBUG)
280332 cerr << " PointCloud after filtering: " << cloud_filtered_ptr_z2->width << " " << cloud_filtered_ptr->height << " data points." << endl;
@@ -299,10 +351,15 @@ bool service_callback(object_detection::ObjectDetection::Request& req,
299351 ec.extract (object_cluster_indices);
300352
301353 // Display number of objects detceted
354+ cerr << " \n Requested Object: " << template_filenames[req.object_id ] << endl;
302355 cerr << " Objects Detected: " << object_cluster_indices.size () << endl;
303- int obj_id = 1 ;
304356
305- // What is this?
357+ // Find the best registered object
358+ int obj_id = req.object_id ;
359+ vector<double > icp_scores;
360+ icp_transforms.clear ();
361+ ICP_SUCCESS = false ;
362+
306363 for (vector<pcl::PointIndices>::const_iterator it = object_cluster_indices.begin (); it != object_cluster_indices.end (); ++it) {
307364 // Create a pcl object to hold the extracted cluster
308365 pcl::PCLPointCloud2::Ptr object_cluster (new pcl::PCLPointCloud2);
@@ -323,7 +380,7 @@ bool service_callback(object_detection::ObjectDetection::Request& req,
323380 pcl_pub.publish (output);
324381
325382 // Read template point cloud
326- string template_filename = " /home/karmesh/dash_ws/src/perception/object_detection/templates/eraser_ascii_tf.pcd " ;
383+ string template_filename = template_path + template_filenames[req. object_id ] ;
327384 pcl::PointCloud<pcl::PointXYZ>::Ptr template_pcl (new pcl::PointCloud<pcl::PointXYZ>);
328385 if (pcl::io::loadPCDFile<pcl::PointXYZ>(template_filename, *template_pcl) == -1 ) {
329386 PCL_ERROR (" Couldn't read the template PCL file" );
@@ -332,9 +389,35 @@ bool service_callback(object_detection::ObjectDetection::Request& req,
332389 }
333390
334391 // Register using ICP and broadcast TF
335- icp_registration (object_cluster_pcl, template_pcl);
392+ double score = icp_registration (object_cluster_pcl, template_pcl);
393+ icp_scores.push_back (score);
394+ }
395+
396+ // Find the object with best ICP score
397+ double min_score = 1000 ;
398+ argmin = -1 ;
399+ for (int i = 0 ; i < icp_scores.size (); i++) {
400+ if (icp_scores[i] < min_score) {
401+ argmin = i;
402+ min_score = icp_scores[i];
403+ }
404+ }
405+
406+ cerr << " \n Lowest Object Index: " << argmin << " with Score: " << min_score << endl;
407+ icp_transform = icp_transforms[argmin];
408+
409+ if (min_score < icp_fitness_score) {
410+ cerr << " ICP Registration Success!\n "
411+ << endl;
412+ ICP_SUCCESS = true ;
336413 res.success = true ;
337414 return true ;
415+ } else {
416+ cerr << " ICP Registration Failed to Converge within Threshold!\n "
417+ << endl;
418+ ICP_SUCCESS = false ;
419+ res.success = false ;
420+ return false ;
338421 }
339422}
340423
@@ -351,6 +434,7 @@ int main(int argc, char** argv)
351434 nh.getParam (" input" , input_topic);
352435 nh.getParam (" output" , output_topic);
353436 nh.getParam (" icp_fitness_score" , icp_fitness_score);
437+ nh.getParam (" template_path" , template_path);
354438
355439 // Params defaults
356440 nh.param <bool >(" invert" , invert, true );
@@ -365,7 +449,8 @@ int main(int argc, char** argv)
365449 cout << " Distance Threshold: " << distance_threshold << endl;
366450 cout << " Input Topic: " << input_topic << endl;
367451 cout << " Output Topic: " << output_topic << endl;
368- cerr << " ICP Fitness Score:" << icp_fitness_score << endl;
452+ cerr << " ICP Fitness Score: " << icp_fitness_score << endl;
453+ cerr << " ICP Template Folder: " << template_path << endl;
369454
370455 // Create a ROS subscriber for the input point cloud
371456 ros::Subscriber sub = nh.subscribe (input_topic, 1 , pcl_callback);
@@ -377,6 +462,7 @@ int main(int argc, char** argv)
377462 bbox_pub = nh.advertise <sensor_msgs::PointCloud2>(" /icp/bbox_points" , 1 );
378463 template_pub = nh.advertise <sensor_msgs::PointCloud2>(" /icp/template" , 1 );
379464 pose_pub = nh.advertise <geometry_msgs::Pose>(" /icp/pose" , 1 );
465+ marker_pub = nh.advertise <visualization_msgs::Marker>(" object_pose_detection/grasp_pose" , 1 );
380466
381467 // Spin
382468 ros::spin ();
0 commit comments