door_cloud_alg_node.cpp
Go to the documentation of this file.
00001 #include "door_cloud_alg_node.h"
00002 
00003 DoorCloudAlgNode::DoorCloudAlgNode(void) :
00004   algorithm_base::IriBaseAlgorithm<DoorCloudAlgorithm>()
00005 {
00006   //init class attributes if necessary
00007   //this->loop_rate_ = 2;//in [Hz]
00008 
00009   // [init publishers]
00010   this->open_door_cloud_publisher_ = this->public_node_handle_.advertise<sensor_msgs::PointCloud2>("open_door_cloud", 1);
00011   this->open_door_marker_publisher_ = this->public_node_handle_.advertise<visualization_msgs::Marker>("open_door_marker", 1);
00012   this->door_centroid_publisher_ = this->public_node_handle_.advertise<geometry_msgs::PoseStamped>("door_centroid", 1);
00013 
00014   this->closed_door_cloud_publisher_ = this->public_node_handle_.advertise<sensor_msgs::PointCloud2>("closed_door_cloud", 1);
00015   this->closed_door_marker_publisher_ = this->public_node_handle_.advertise<visualization_msgs::Marker>("closed_door_marker", 1);
00016   this->door_handle_publisher_ = this->public_node_handle_.advertise<geometry_msgs::PoseStamped>("door_handle", 1);
00017   
00018   // [init subscribers]
00019   if (!no_simulator)
00020         this->door_action_start_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/door_detector_actions/door_action_start", 1, &DoorCloudAlgNode::door_action_start_callback, this);
00021 
00022   if (no_simulator)
00023   {
00024         this->points_subscriber_ = this->public_node_handle_.subscribe("/camera/depth/points", 1, &DoorCloudAlgNode::points_callback, this);
00025         this->door_centroid_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/open_door_detector/door_centroid", 1, &DoorCloudAlgNode::door_centroid_callback, this);
00026         this->handle_location_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/closed_door_detector/door_handle", 1, &DoorCloudAlgNode::handle_location_callback, this);
00027   }
00028   
00029   // [init services]
00030   
00031   // [init clients]
00032   
00033   // [init action servers]
00034   
00035   // [init action clients]
00036 
00037   // [init variables]
00038   captured_open = 0;
00039   captured_closed = 0;
00040   start = 0;
00041   tf_original_frame = "/kinect_depth_optical_frame";
00042 }
00043 
00044 DoorCloudAlgNode::~DoorCloudAlgNode(void)
00045 {
00046   // [free dynamic memory]
00047 }
00048 
00049 void DoorCloudAlgNode::mainNodeThread(void)
00050 {
00051   // [fill msg structures]
00052   //this->PointCloud2_msg_.data = my_var;
00053   //this->Marker_msg_.data = my_var;
00054   //this->PoseStamped_msg_.data = my_var;
00055   
00056   // [fill srv structure and make request to the server]
00057   
00058   // [fill action structure and make request to the action server]
00059 
00060   // [publish messages]
00061   //this->open_door_cloud_publisher_.publish(this->PointCloud2_msg_);
00062   //this->open_door_marker_publisher_.publish(this->Marker_msg_);
00063   //this->door_centroid_publisher_.publish(this->PoseStamped_msg_);
00064 }
00065 
00066 /*  [subscriber callbacks] */
00067 void DoorCloudAlgNode::door_action_start_callback(const std_msgs::Int8::ConstPtr& action_start) 
00068 { 
00069   //ROS_INFO("DoorCloudAlgNode::door_action_start_callback: New Message Received"); 
00070 
00071   //use appropiate mutex to shared variables if necessary 
00072   //this->alg_.lock(); 
00073   this->door_action_start_mutex_.enter(); 
00074 
00075   start=action_start->data;
00076   
00077   if (start==0)
00078   {
00079         points_subscriber_.shutdown();
00080         door_centroid_subscriber_.shutdown();
00081         handle_location_subscriber_.shutdown();
00082   }
00083   if (start==1)
00084   {
00085         this->points_subscriber_ = this->public_node_handle_.subscribe("/camera/depth/points", 1, &DoorCloudAlgNode::points_callback, this);
00086         this->door_centroid_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/open_door_detector/door_centroid", 1, &DoorCloudAlgNode::door_centroid_callback, this);
00087         this->handle_location_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/closed_door_detector/door_handle", 1, &DoorCloudAlgNode::handle_location_callback, this);
00088   }
00089 
00090   //unlock previously blocked shared variables 
00091   //this->alg_.unlock(); 
00092   this->door_action_start_mutex_.exit(); 
00093 }
00094 void DoorCloudAlgNode::door_centroid_callback(const geometry_msgs::PoseStamped::ConstPtr& door_centroid) 
00095 { 
00096   //use appropiate mutex to shared variables if necessary   
00097   //this->alg_.lock(); 
00098   this->door_centroid_mutex_.enter(); 
00099 
00100   if (captured_open==0)
00101   {
00102         y_open=door_centroid->pose.position.y;
00103         z_open=door_centroid->pose.position.z;
00104         w_open=door_centroid->pose.orientation.w;
00105 
00106         x_left = door_centroid->pose.position.x;
00107         x_right = door_centroid->pose.orientation.x;
00108         y_top = door_centroid->pose.orientation.y;
00109 
00110         x_open=(x_left+x_right)/2;
00111 
00112         //ROS_INFO("DoorCloudAlgNode::door_centroid_callback: New Message Received"); 
00113         captured_open=1;
00114   }
00115 
00116   //unlock previously blocked shared variables 
00117   //this->alg_.unlock(); 
00118   this->door_centroid_mutex_.exit(); 
00119 }
00120 void DoorCloudAlgNode::handle_location_callback(const geometry_msgs::PoseStamped::ConstPtr& handle_location) 
00121 { 
00122   //use appropiate mutex to shared variables if necessary 
00123   //this->alg_.lock(); 
00124   this->handle_location_mutex_.enter(); 
00125   
00126   //ROS_INFO("DoorCloudAlgNode::handle_location_callback: New Message Received"); 
00127 
00128   if (captured_closed==0)
00129   {
00130 
00131         x_closed=handle_location->pose.position.x;
00132         y_closed=handle_location->pose.position.y;
00133         z_closed=handle_location->pose.position.z;
00134         w_closed=handle_location->pose.orientation.w;
00135 
00136         captured_closed=1;
00137   }
00138 
00139   //unlock previously blocked shared variables 
00140   //this->alg_.unlock(); 
00141   this->handle_location_mutex_.exit(); 
00142 }
00143 
00144 void DoorCloudAlgNode::points_callback(const sensor_msgs::PointCloud2::ConstPtr& input_cloud) 
00145 { 
00146   //use appropiate mutex to shared variables if necessary 
00147   //this->alg_.lock(); 
00148   this->points_mutex_.enter(); 
00149 
00150   if(captured_open==1 || captured_closed==1)
00151   {
00152           //ROS_INFO("DoorCloudAlgNode::points_callback: New Message Received"); 
00153           pcl::fromROSMsg (*input_cloud,cloud);
00154           pcl::ModelCoefficients::Ptr cloud_coeffs (new pcl::ModelCoefficients ());
00155           pcl::PointIndices::Ptr cloud_inliers (new pcl::PointIndices);
00156 
00157           pcl::VoxelGrid<pcl::PointXYZ> sor;
00158           sor.setInputCloud (cloud.makeShared());
00159           sor.setLeafSize (0.01f, 0.01f, 0.01f);
00160           sor.filter (cloud);
00161   
00162           if(captured_open==1)
00163           {
00164                 //---OPEN DOOR STAGE
00165                 
00166                 cloud_filtered.clear();
00167                 cloud_filtered_left.clear();
00168                 cloud_filtered_right.clear();
00169                 cloud_filtered_top.clear();
00170 
00171                 cloud_filtered.header=cloud.header;
00172 
00173                 //ROS_ERROR("%f, %f, %f, %f", y_open, z_open, x_left, x_right);
00174 
00175                 //Bounding volume where a door may exist
00176                 //lower_x and upper_x defined in open door callback
00177                 lower_x = x_left-0.3;
00178                 upper_x = x_left;
00179                 lower_y = y_open-5.0;
00180                 upper_y = y_open;
00181                 lower_z = z_open-0.25;
00182                 upper_z = z_open+0.25;
00183 
00184                 //Filter cloud by bounding volume: x, y, z
00185                 cloud_filtered_left=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00186                 cloud_filtered_left.header=cloud.header;
00187                 cloud_filtered+=cloud_filtered_left;
00188 
00189                 //Bounding volume where a door may exist
00190                 lower_x = x_right;
00191                 upper_x = x_right+0.3;
00192 
00193                 //Filter cloud by bounding volume: x, y, z
00194                 cloud_filtered_right=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00195                 cloud_filtered_right.header=cloud.header;
00196                 cloud_filtered+=cloud_filtered_right;
00197 
00198                 //Bounding volume where a door may exist
00199                 lower_x = x_left-0.3;
00200                 upper_x = x_right+0.3;
00201                 lower_y = y_open-5.0;
00202                 upper_y = y_top;
00203 
00204                 //Filter cloud by bounding volume: x, y, z
00205                 cloud_filtered_top=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00206                 cloud_filtered_top.header.frame_id=input_cloud->header.frame_id;
00207                 //cloud_filtered+=cloud_filtered_top;
00208 
00209                 //Fit cloud to plane and get properties
00210                 door_plane = planeFit(cloud_filtered);
00211 
00212                 cloud_plane= boost::tuples::get<0>(door_plane);
00213                 cloud_inliers= boost::tuples::get<1>(door_plane);
00214                 cloud_coeffs= boost::tuples::get<2>(door_plane);
00215 
00216                 if (cloud_inliers->indices.size () == 0)
00217                 {
00218                         ROS_WARN("Open Door Detector: Could not compute plane! maybe there are too few points");
00219                 }
00220         
00221                 //prepare data for advertising
00222                 if (cloud_inliers->indices.size () > 0)
00223                 {
00224                         //Adjust vector to point forward 
00225                         if(cloud_coeffs->values[2]<0)
00226                         {
00227                                 cloud_coeffs->values[0]= -cloud_coeffs->values[0];      
00228                                 cloud_coeffs->values[1]= -cloud_coeffs->values[1];
00229                                 cloud_coeffs->values[2]= -cloud_coeffs->values[2];
00230                                 cloud_coeffs->values[3]= -cloud_coeffs->values[3];
00231                         }
00232 
00233                 
00234                         //ROS_ERROR("%s, %f", input_cloud->header.frame_id, input_cloud->header.stamp);
00235 
00236                         poses.header.frame_id=input_cloud->header.frame_id;
00237                         poses.header.stamp=input_cloud->header.stamp;
00238 
00239                         poses.pose.position.x = x_open;
00240                         poses.pose.position.y = y_open;
00241                         poses.pose.position.z = z_open;//-(x_open*cloud_coeffs->values[0]+y_open*cloud_coeffs->values[1]+cloud_coeffs->values[3])/cloud_coeffs->values[2];
00242 
00243                         poses.pose.orientation.x = cloud_coeffs->values[0];
00244                         poses.pose.orientation.y = cloud_coeffs->values[1];
00245                         poses.pose.orientation.z = cloud_coeffs->values[2];
00246                         poses.pose.orientation.w = w_open;
00247                         
00248                         door_centroid_publisher_.publish(poses);
00249 
00250                         tf::Vector3 initial_position = tf::Vector3(1.0,0.0,0.0);//align to z axis
00251                         tf::Vector3 plane_norm = tf::Vector3(poses.pose.orientation.x, 
00252                                                              poses.pose.orientation.y, 
00253                                                              poses.pose.orientation.z);
00254 
00255                         orient=quaternionFromVectors(initial_position, plane_norm);
00256                         poses.pose.orientation=orient;
00257 
00258                         pcl::toROSMsg(cloud_plane, open_door_cloud);
00259                         open_door_cloud.header.frame_id=input_cloud->header.frame_id;
00260                         open_door_cloud.header.stamp=input_cloud->header.stamp;
00261                         open_door_cloud_publisher_.publish(open_door_cloud);
00262 
00263                         cloud_plane.points.clear();
00264                         cloud_plane.width=1;
00265                         cloud_plane.height=1;
00266                         cloud_plane.points.resize (1);
00267                         pcl::toROSMsg(cloud_plane, closed_door_cloud);
00268                         closed_door_cloud.header=input_cloud->header;
00269                         closed_door_cloud_publisher_.publish(closed_door_cloud);
00270 
00271                         marker = ArrowMarker(input_cloud->header, poses.pose, 1, 2, "door_centroid_vector");
00272                         open_door_marker_publisher_.publish(marker);
00273 
00274                         marker.ns = "door_handle_vector";
00275                         marker.color.a = 0.0;
00276                         closed_door_marker_publisher_.publish(marker);
00277                 }
00278           }
00279 
00280           if(captured_closed==1)
00281           {
00282                 //---CLOSED DOOR STAGE
00283 
00284                 //Bounding volume where a door may exist
00285                 lower_x = x_closed-0.4;         
00286                 upper_x = x_closed+0.4;
00287                 lower_y = y_closed-5.0;         
00288                 upper_y = y_closed;
00289                 lower_z = z_closed-0.3;
00290                 upper_z = z_closed+0.3;
00291                 
00292                 if(w_closed==-1)
00293                 {
00294                         lower_x = x_closed-0.1;         
00295                         upper_x = x_closed+0.6;
00296                 }
00297                 if(w_closed==1)
00298                 {
00299                         lower_x = x_closed-0.6;
00300                         upper_x = x_closed+0.1;
00301                 }
00302 
00303                 //Filter cloud by bounding volume: x, y, z
00304                 cloud_filtered=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00305 
00306                 //Fit cloud to plane and get propertiers
00307                 door_plane = planeFit(cloud_filtered);
00308                 cloud_plane= boost::tuples::get<0>(door_plane);
00309                 cloud_inliers= boost::tuples::get<1>(door_plane);
00310                 cloud_coeffs= boost::tuples::get<2>(door_plane);
00311 
00312                 if (cloud_inliers->indices.size () == 0)
00313                 {
00314                         ROS_WARN("Closed Door Detector: Could not compute plane! maybe there are too few points");
00315                 
00316                 }
00317 
00318                 //prepare data for advertising
00319                 if (cloud_inliers->indices.size () > 0)
00320                 {
00321 
00322                         if(cloud_coeffs->values[2]<0)
00323                         {
00324                                 cloud_coeffs->values[3]=cloud_coeffs->values[3]-0.04;
00325                         }
00326                         if(cloud_coeffs->values[2]>0)
00327                         {
00328                                 cloud_coeffs->values[3]=cloud_coeffs->values[3]+0.04;
00329                         }
00330                         
00331 
00332                         //Adjust vector to point forward
00333                         if(cloud_coeffs->values[2]<0)
00334                         {
00335                                 cloud_coeffs->values[0]= -cloud_coeffs->values[0];      
00336                                 cloud_coeffs->values[1]= -cloud_coeffs->values[1];
00337                                 cloud_coeffs->values[2]= -cloud_coeffs->values[2];
00338                                 cloud_coeffs->values[3]= -cloud_coeffs->values[3];
00339                         }
00340 
00341                         //ROS_ERROR("%s, %f", input_cloud->header.frame_id, input_cloud->header.stamp);
00342 
00343                         poses.header.frame_id=input_cloud->header.frame_id;
00344                         poses.header.stamp=input_cloud->header.stamp;
00345 
00346                         poses.pose.position.x = x_closed;
00347                         poses.pose.position.y = y_closed;
00348                         poses.pose.position.z = z_closed;//-(x_closed*cloud_coeffs->values[0]+y_closed*cloud_coeffs->values[1]+cloud_coeffs->values[3])/cloud_coeffs->values[2];
00349 
00350                         poses.pose.orientation.x=cloud_coeffs->values[0];
00351                         poses.pose.orientation.y=cloud_coeffs->values[1];
00352                         poses.pose.orientation.z=cloud_coeffs->values[2];
00353                         poses.pose.orientation.w = w_closed;
00354 
00355                         door_handle_publisher_.publish(poses);
00356 
00357                         tf::Vector3 initial_position = tf::Vector3(-1.0,0.0,0.0);//align to z axis
00358                         tf::Vector3 plane_norm = tf::Vector3(poses.pose.orientation.x, 
00359                                                              poses.pose.orientation.y, 
00360                                                              poses.pose.orientation.z);
00361 
00362                         orient=quaternionFromVectors(initial_position, plane_norm);
00363                         poses.pose.orientation=orient;
00364 
00365                         pcl::toROSMsg(cloud_plane, closed_door_cloud);
00366                         closed_door_cloud.header.frame_id=input_cloud->header.frame_id;
00367                         closed_door_cloud.header.stamp=input_cloud->header.stamp;
00368 
00369                         closed_door_cloud_publisher_.publish(closed_door_cloud);
00370 
00371                         cloud_plane.points.clear();
00372                         cloud_plane.width=1;
00373                         cloud_plane.height=1;
00374                         cloud_plane.points.resize (1);
00375                         pcl::toROSMsg(cloud_plane, open_door_cloud);
00376                         open_door_cloud.header=input_cloud->header;
00377                         open_door_cloud_publisher_.publish(open_door_cloud);
00378 
00379                         marker = ArrowMarker(input_cloud->header, poses.pose, 1, 2, "door_handle_vector");
00380                         closed_door_marker_publisher_.publish(marker);
00381                 
00382                         marker.ns = "door_centroid_vector";
00383                         marker.color.a = 0.0;
00384                         open_door_marker_publisher_.publish(marker);
00385                 }
00386           }
00387 
00388           captured_open=0;
00389           captured_closed=0;
00390   } 
00391 
00392   //unlock previously blocked shared variables 
00393   //this->alg_.unlock(); 
00394   this->points_mutex_.exit(); 
00395 }
00396 
00397 /*  [service callbacks] */
00398 
00399 /*  [action callbacks] */
00400 
00401 /*  [action requests] */
00402 
00403 void DoorCloudAlgNode::node_config_update(Config &config, uint32_t level)
00404 {
00405   this->alg_.lock();
00406 
00407         this->no_simulator = config.no_simulator;
00408 
00409   this->alg_.unlock();
00410 }
00411 
00412 void DoorCloudAlgNode::addNodeDiagnostics(void)
00413 {
00414 }
00415 
00416 /* main function */
00417 int main(int argc,char *argv[])
00418 {
00419   return algorithm_base::main<DoorCloudAlgNode>(argc, argv, "door_cloud_alg_node");
00420 }
00421 
00422 /* algorithm functions */
00423 pcl::PointCloud<pcl::PointXYZ> DoorCloudAlgNode::filterCloud (pcl::PointCloud<pcl::PointXYZ> raw_cloud, float Lowx, float Uppx, float Lowy, float Uppy, float Lowz, float Uppz, bool negative_limits)
00424 {       
00425         //Filter points to door location
00426         pcl::PointCloud<pcl::PointXYZ> cloud_filtered_x;
00427         pcl::PointCloud<pcl::PointXYZ> cloud_filtered_z;
00428         pcl::PointCloud<pcl::PointXYZ> cloud_filtered_y;
00429 
00430         pcl::PassThrough<pcl::PointXYZ> pass;
00431         pass.setInputCloud (raw_cloud.makeShared());
00432         pass.setFilterFieldName ("x");
00433         pass.setFilterLimits (Lowx, Uppx);
00434         pass.setFilterLimitsNegative (negative_limits); 
00435         pass.filter (cloud_filtered_x);
00436         
00437         if (cloud_filtered_x.points.size()>0)
00438         {
00439                 pcl::PassThrough<pcl::PointXYZ> pass2;
00440                 pass2.setInputCloud (cloud_filtered_x.makeShared());
00441                 pass2.setFilterFieldName ("y");
00442                 pass2.setFilterLimits (Lowy, Uppy);
00443                 pass2.filter (cloud_filtered_y);
00444 
00445                 if (cloud_filtered_y.points.size()>0)
00446                 {
00447                         pcl::PassThrough<pcl::PointXYZ> pass3;
00448                         pass3.setInputCloud (cloud_filtered_y.makeShared());
00449                         pass3.setFilterFieldName ("z");
00450                         pass3.setFilterLimits (Lowz, Uppz);
00451                         pass3.filter (cloud_filtered_z);
00452                 }
00453         }
00454 
00455         return cloud_filtered_z;
00456 }
00457 
00458 boost::tuple<pcl::PointCloud<pcl::PointXYZ>, pcl::PointIndices::Ptr,pcl::ModelCoefficients::Ptr> DoorCloudAlgNode::planeFit (pcl::PointCloud<pcl::PointXYZ> raw_cloud)
00459 {
00460 
00461         pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ());
00462         pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00463         pcl::PointCloud<pcl::PointXYZ> planecloud;
00464 
00465         // Create the segmentation object
00466         pcl::SACSegmentation<pcl::PointXYZ> seg;
00467         // Optional
00468         seg.setOptimizeCoefficients (true);
00469         // Mandatory
00470         seg.setModelType (pcl::SACMODEL_PLANE);
00471         seg.setMethodType (pcl::SAC_RANSAC);
00472         seg.setDistanceThreshold (0.05);
00473 
00474         if (raw_cloud.points.size()>0)
00475         {
00476                 seg.setInputCloud (raw_cloud.makeShared ());
00477                 seg.segment (*inliers, *coefficients);
00478 
00479                 pcl::ExtractIndices<pcl::PointXYZ> extract;
00480                 extract.setInputCloud(raw_cloud.makeShared ());
00481                 extract.setIndices (inliers);
00482                 extract.setNegative(false);
00483                 extract.filter(planecloud);
00484         }
00485 
00486         boost::tuple<pcl::PointCloud<pcl::PointXYZ>, pcl::PointIndices::Ptr, pcl::ModelCoefficients::Ptr> planeFit (planecloud, inliers, coefficients);
00487 
00488         return planeFit;
00489 }
00490 
00491 geometry_msgs::Quaternion DoorCloudAlgNode::quaternionFromVectors (tf::Vector3 vector_1, tf::Vector3 vector_2)
00492 {       
00493 
00494         vector_1 = vector_1.normalize();
00495         vector_2 = vector_2.normalize();
00496         float rot_ang = acos(vector_1.dot(vector_2));
00497         tf::Vector3 rot_axis = vector_1.cross(vector_2);
00498         tf::Quaternion q = tf::Quaternion(rot_axis,rot_ang);
00499         q.normalize();
00500         tf::quaternionTFToMsg(q, orient);
00501         //ROS_ERROR("%f, %f, %f",poses.pose.orientation.x,poses.pose.orientation.y,poses.pose.orientation.z);
00502         //ROS_ERROR("%f, %f, %f, %f",orient.x,orient.y,orient.z,orient.w);
00503 
00504         return orient;
00505 }
00506 
00507 visualization_msgs::Marker DoorCloudAlgNode::ArrowMarker(std_msgs::Header header, geometry_msgs::Pose pose, int alpha, int color,  const char arrow_tag[])
00508 {       
00509 
00510         marker.header = header;
00511         marker.ns = arrow_tag;
00512         marker.id = 0;
00513         marker.type = visualization_msgs::Marker::ARROW;
00514         marker.action = visualization_msgs::Marker::ADD;
00515         marker.pose = pose;
00516 
00517         // scale
00518         marker.scale.x = 0.7;
00519         marker.scale.y = 0.7;
00520         marker.scale.z = 0.7;
00521 
00522         // color
00523         marker.color.a = alpha;
00524         marker.color.r = 0.0;
00525         marker.color.g = 0.0;
00526         marker.color.b = 0.0;
00527 
00528         if(color==1)
00529                 marker.color.r = 1.0;
00530         if(color==2)
00531                 marker.color.g = 1.0;
00532         if(color==3)
00533                 marker.color.b = 1.0;
00534 
00535         return marker;
00536 }


iri_door_detector
Author(s): Jose Rodriguez
autogenerated on Fri Dec 6 2013 23:57:16