zyonz_find_leaf_probing_points_alg_node.cpp
Go to the documentation of this file.
00001 #include "zyonz_find_leaf_probing_points_alg_node.h"
00002 
00003 /*  [sorting function] */
00004 bool MyDataSortPredicate(const geometry_msgs::Pose& d1, const geometry_msgs::Pose& d2)
00005 {
00006   return d1.position.y < d2.position.y;
00007 }
00008 
00009 ZyonzFindLeafProbingPointsAlgNode::ZyonzFindLeafProbingPointsAlgNode(void) :
00010   algorithm_base::IriBaseAlgorithm<ZyonzFindLeafProbingPointsAlgorithm>(),
00011   data_processed_(false)
00012 {
00013   //init class attributes if necessary
00014   //this->loop_rate_ = 2;//in [Hz]
00015 
00016   // [init publishers]
00017   poses_publisher_ = public_node_handle_.advertise<geometry_msgs::PoseArray>("poses", 10);
00018   output_marker_publisher_ = public_node_handle_.advertise<visualization_msgs::Marker>("output_marker", 10);
00019   output_pointcloud_publisher_ = public_node_handle_.advertise<sensor_msgs::PointCloud2>("output_pointcloud", 10);
00020   
00021   // [init subscribers]
00022   input_subscriber_ = public_node_handle_.subscribe("input", 10, &ZyonzFindLeafProbingPointsAlgNode::input_callback, this);
00023   
00024   // [init services]
00025   get_pose_array_server_ = public_node_handle_.advertiseService("get_pose_array", &ZyonzFindLeafProbingPointsAlgNode::get_pose_arrayCallback, this);
00026   
00027   // [init clients]
00028   
00029   // [init action servers]
00030   
00031   // [init action clients]
00032 }
00033 
00034 ZyonzFindLeafProbingPointsAlgNode::~ZyonzFindLeafProbingPointsAlgNode(void)
00035 {
00036   // [free dynamic memory]
00037 }
00038 
00039 void ZyonzFindLeafProbingPointsAlgNode::mainNodeThread(void)
00040 {
00041   // [fill msg structures]
00042   //this->PoseArray_msg_.data = my_var;
00043   //this->Marker_msg_.data = my_var;
00044   //this->PointCloud2_msg_.data = my_var;
00045   
00046   // [fill srv structure and make request to the server]
00047   
00048   // [fill action structure and make request to the action server]
00049 
00050   // [publish messages]
00051   //this->poses_publisher_.publish(this->PoseArray_msg_);
00052   //this->output_marker_publisher_.publish(this->Marker_msg_);
00053   //this->output_pointcloud_publisher_.publish(this->PointCloud2_msg_);
00054 }
00055 
00056 /*  [subscriber callbacks] */
00057 void ZyonzFindLeafProbingPointsAlgNode::input_callback(const sensor_msgs::PointCloud2::ConstPtr& msg) 
00058 { 
00059   //ROS_INFO("ZyonzFindLeafProbingPointsAlgNode::input_callback: New Message Received"); 
00060   
00061   /* Load input PointCloud2 */
00062   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00063   pcl::fromROSMsg (*msg, *cloud);
00064 
00065   //use appropiate mutex to shared variables if necessary 
00066   //alg_.lock(); 
00067   //input_mutex_.enter(); 
00068   
00069   pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00070   pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00071   // Create the segmentation object
00072   pcl::SACSegmentation<pcl::PointXYZ> seg;
00073   // Optional
00074   seg.setOptimizeCoefficients (true);
00075   // Mandatory
00076   seg.setModelType (pcl::SACMODEL_PLANE);
00077   seg.setMethodType (pcl::SAC_RANSAC);
00078   seg.setDistanceThreshold (0.01);
00079   seg.setInputCloud (cloud);
00080   seg.segment (*inliers, *coefficients);
00081 //  std::cerr << "PointCloud after segmentation has: "
00082 //            << inliers->indices.size () << " inliers." << std::endl;
00083   
00084   // Project the model inliers 
00085   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected (new pcl::PointCloud<pcl::PointXYZ>);
00086   pcl::ProjectInliers<pcl::PointXYZ> proj;
00087   proj.setModelType (pcl::SACMODEL_PLANE);
00088   proj.setInputCloud (cloud);
00089   proj.setModelCoefficients (coefficients);
00090   proj.filter (*cloud_projected);
00091 //  std::cerr << "PointCloud after projection has: "
00092 //            << cloud_projected->points.size () << " data points." << std::endl;
00093   
00094 // Create a Concave Hull representation of the projected inliers
00095   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
00096   pcl::ConcaveHull<pcl::PointXYZ> chull;
00097   //  chull.setKeepInformation (true);
00098   chull.setInputCloud (cloud_projected);
00099   chull.setAlpha (0.1);
00100   chull.reconstruct (*cloud_hull);
00101   
00102   // Compute the cluster centroid
00103   Eigen::Vector4f centroid;
00104   pcl::compute3DCentroid (*cloud, centroid);
00105   // ROS_INFO("Cluster Centroid: (%f, %f, %f)", centroid(0), centroid(1), centroid(2));
00106   
00107   // Principal Component Analysis (PCA)
00108   // 1) Compute Covariance
00109   Eigen::MatrixXf B(cloud->points.size(),3);
00110   int aa = 0;
00111   for (pcl::PointCloud<pcl::PointXYZ>::iterator it = cloud->begin(); it != cloud->end(); ++it, ++aa){
00112     B.row(aa)[0] = it->x - centroid(0);
00113     B.row(aa)[1] = it->y - centroid(1);
00114     B.row(aa)[2] = it->z - centroid(2);
00115     // std::cout << "Point " << aa << " of " << cloud_filtered->points.size() << ": " << it->x << ", " << it->y << ", " << it->z << std::endl;
00116   }
00117   Eigen::Matrix3f C = (B.transpose()*B)/cloud->points.size();
00118   //std::cout << "Covariance Matrix: \n" << C << std::endl;
00119   
00120   // 2) Get EigenValues and EigenVectors
00121   Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigensolver(C);
00122   if (eigensolver.info() != Eigen::Success)
00123     ROS_ERROR("EigenVectors not found :'(");
00124   std::cout << "Eigenvalues are: \n" << eigensolver.eigenvalues() << std::endl << "Eigenvectors are: \n" << eigensolver.eigenvectors() << std::endl;
00125   std::cout << "1st EigenVector: (" << eigensolver.eigenvectors()(0,0) << ", " << eigensolver.eigenvectors()(0,1) << ", " << eigensolver.eigenvectors()(0,2) << ")" << std::endl; 
00126   
00127   //TODO: Check the direction of the Z axis respect the camera
00128   Eigen::Matrix3f rot_m;
00129   rot_m << -eigensolver.eigenvectors()(0,1), -eigensolver.eigenvectors()(0,2), eigensolver.eigenvectors()(0,0),
00130            -eigensolver.eigenvectors()(1,1), -eigensolver.eigenvectors()(1,2), eigensolver.eigenvectors()(1,0),
00131            -eigensolver.eigenvectors()(2,1), -eigensolver.eigenvectors()(2,2), eigensolver.eigenvectors()(2,0);
00132   
00133   //Eigen::Quaternionf pose_c(eigensolver.eigenvectors());
00134   Eigen::Quaternionf pose_c(rot_m);
00135   // std::cout << "Quaternion: \n" << "(" << pose_c.x() << ", " << pose_c.y() << ", " << pose_c.z() << ", " << pose_c.w() << ")" << std::endl;
00136   
00137   // Transform (translate and rotate) the countours to the origen of the world so we have the leaf correctly oriented
00138   Eigen::Vector3f translation (-centroid(0), -centroid(1), -centroid(2));
00139   pcl::PointCloud<pcl::PointXYZ>::Ptr trasl_cluster (new pcl::PointCloud<pcl::PointXYZ>);
00140   pcl::PointCloud<pcl::PointXYZ>::Ptr trasl_rot_cluster (new pcl::PointCloud<pcl::PointXYZ>);
00141   // I apply the transformation separately because first rotates and then translates :(  
00142   pcl::transformPointCloud(*cloud_hull, *trasl_cluster, translation, Eigen::Quaternionf(1, 0, 0, 0));
00143   pcl::transformPointCloud(*trasl_cluster, *trasl_rot_cluster, Eigen::Vector3f(0,0,0), pose_c.conjugate());
00144   
00145   // Extracting the right side indices
00146   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster_right (new pcl::PointCloud<pcl::PointXYZ>);
00147   pcl::PassThrough<pcl::PointXYZ> pass2;
00148   pass2.setInputCloud (trasl_rot_cluster);
00149   pass2.setFilterFieldName ("x");
00150   pass2.setFilterLimits (0, +20.0);
00151   pass2.filter (*cloud_cluster_right);
00152   //  ROS_INFO("PointCloud after passthrough filtering has: %u data points", (unsigned int)cloud_cluster_right->size());
00153   
00154   // Downsample the contour
00155   pcl::VoxelGrid<pcl::PointXYZ> sor;
00156   sor.setInputCloud (cloud_cluster_right);
00157   sor.setLeafSize (0.1f, 0.1f, 0.1f);
00158   sor.filter (*cloud_cluster_right);
00159   
00160   // Reduce 2 cm distance to the center
00161   for (pcl::PointCloud<pcl::PointXYZ>::iterator it = cloud_cluster_right->begin(); it != cloud_cluster_right->end(); ++it){
00162     Eigen::Vector3f point(it->x, it->y, it->z);
00163     it->x = point.x()*(point.norm()-0.02)/point.norm();
00164     it->y = point.y()*(point.norm()-0.02)/point.norm();
00165     it->z = point.z()*(point.norm()-0.02)/point.norm();
00166   }
00167   
00168   // Transform (translate and rotate) the countours to the origen of the world so we have the leaf correctly oriented
00169   translation = Eigen::Vector3f(centroid(0), centroid(1), centroid(2));
00170   // I apply the transformation separately because first rotates and then translates :(  
00171   pcl::transformPointCloud(*cloud_cluster_right, *trasl_cluster, Eigen::Vector3f(0, 0, 0), pose_c);
00172   pcl::transformPointCloud(*trasl_cluster, *cloud_cluster_right, translation, Eigen::Quaternionf(1, 0, 0, 0));
00173   
00174   static tf::TransformBroadcaster br;
00175   tf::Transform transform;
00176   transform.setOrigin( tf::Vector3(centroid(0), centroid(1), centroid(2)) );
00177   transform.setRotation( tf::Quaternion(pose_c.x(), pose_c.y(), pose_c.z(), pose_c.w()) );
00178   br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/camboard_frame", "centroid"));
00179 
00180 //  uint32_t shape = visualization_msgs::Marker::CUBE;
00181   uint32_t shape = visualization_msgs::Marker::SPHERE;
00182 //  uint32_t shape = visualization_msgs::Marker::ARROW;
00183 //  uint32_t shape = visualization_msgs::Marker::CYLINDER;
00184   Marker_msg_.header.frame_id = msg->header.frame_id;
00185   Marker_msg_.header.stamp = ros::Time::now();
00186   Marker_msg_.ns = "basic_shapes";
00187   Marker_msg_.id = 0;
00188   Marker_msg_.type = shape;
00189   Marker_msg_.action = visualization_msgs::Marker::ADD;
00190   Marker_msg_.pose.position.x = centroid.x();
00191   Marker_msg_.pose.position.y = centroid.y();
00192   Marker_msg_.pose.position.z = centroid.z();
00193   Marker_msg_.pose.orientation.x = pose_c.x();
00194   Marker_msg_.pose.orientation.y = pose_c.y();
00195   Marker_msg_.pose.orientation.z = pose_c.z();
00196   Marker_msg_.pose.orientation.w = pose_c.w();
00197   Marker_msg_.scale.x = eigensolver.eigenvalues()[1]*10;
00198   Marker_msg_.scale.y = eigensolver.eigenvalues()[2]*10;
00199   Marker_msg_.scale.z = eigensolver.eigenvalues()[0]*10;
00200   Marker_msg_.color.r = 0.0f;
00201   Marker_msg_.color.g = 1.0f;
00202   Marker_msg_.color.b = 0.0f;
00203   Marker_msg_.color.a = 1.0;
00204   Marker_msg_.lifetime = ros::Duration();
00205 
00206   // Extract Poses
00207   geometry_msgs::PoseArray leaf_pose_array;
00208   leaf_pose_array.poses.clear();
00209   leaf_pose_array.header.stamp = ros::Time::now(); 
00210   leaf_pose_array.header.frame_id = msg->header.frame_id; 
00211   for (pcl::PointCloud<pcl::PointXYZ>::iterator it = cloud_cluster_right->begin(); it != cloud_cluster_right->end(); ++it){
00212     
00213     Eigen::Vector3f vx (it->x-centroid.x(), it->y-centroid.y(), it->z-centroid.z()); 
00214     Eigen::Vector3f vy (-eigensolver.eigenvectors()(0,2),-eigensolver.eigenvectors()(1,2),  -eigensolver.eigenvectors()(2,2)); 
00215     Eigen::Vector3f vz (-eigensolver.eigenvectors()(0,0),-eigensolver.eigenvectors()(1,0),  -eigensolver.eigenvectors()(2,0)); 
00216     vx = vx/vx.norm();
00217     vz = vx.cross(vy);
00218     vz = vz/vz.norm();
00219     vy = vz.cross(vx);
00220     vy = vy/vy.norm();
00221 
00222     Eigen::Matrix3f rot_mm;
00223     rot_mm << vx.x(), vy.x(), vz.x(),
00224               vx.y(), vy.y(), vz.y(),
00225               vx.z(), vy.z(), vz.z();
00226     Eigen::Quaternionf pose_cc(rot_mm);
00227     
00228     geometry_msgs::Pose pose;
00229     pose.position.x = it->x;
00230     pose.position.y = it->y;
00231     pose.position.z = it->z;
00232     pose.orientation.x = pose_cc.x();
00233     pose.orientation.y = pose_cc.y();
00234     pose.orientation.z = pose_cc.z();
00235     pose.orientation.w = pose_cc.w();
00236     leaf_pose_array.poses.push_back(pose);
00237   }
00238   std::sort(leaf_pose_array.poses.begin(), leaf_pose_array.poses.end(), MyDataSortPredicate);
00239 
00240   // initial intermediate pose
00241   geometry_msgs::Pose initial_pose;
00242   initial_pose = leaf_pose_array.poses.front();
00243   Eigen::Vector3f initial_point;
00244   initial_point.x() = initial_pose.position.x - centroid.x(); 
00245   initial_point.y() = initial_pose.position.y - centroid.y(); 
00246   initial_point.z() = initial_pose.position.z - centroid.z(); 
00247   initial_point.x() = initial_point.x()*(initial_point.norm()+0.1)/initial_point.norm(); 
00248   initial_point.y() = initial_point.y()*(initial_point.norm()+0.1)/initial_point.norm(); 
00249   initial_point.z() = initial_point.z()*(initial_point.norm()+0.1)/initial_point.norm(); 
00250   initial_pose.position.x =  initial_point.x() + centroid.x();
00251   initial_pose.position.y =  initial_point.y() + centroid.y();
00252   initial_pose.position.z =  initial_point.z() + centroid.z();
00253  
00254   // final intermediate pose
00255   geometry_msgs::Pose final_pose;
00256   final_pose = leaf_pose_array.poses.back();
00257   Eigen::Vector3f final_point;
00258   final_point.x() = final_pose.position.x - centroid.x(); 
00259   final_point.y() = final_pose.position.y - centroid.y(); 
00260   final_point.z() = final_pose.position.z - centroid.z(); 
00261   final_point.x() = final_point.x()*(final_point.norm()+0.1)/final_point.norm(); 
00262   final_point.y() = final_point.y()*(final_point.norm()+0.1)/final_point.norm(); 
00263   final_point.z() = final_point.z()*(final_point.norm()+0.1)/final_point.norm(); 
00264   final_pose.position.x =  final_point.x()+centroid.x();
00265   final_pose.position.y =  final_point.y()+centroid.y();
00266   final_pose.position.z =  final_point.z()+centroid.z();
00267  
00268   // add initial and final poses
00269   pose_array_.poses.clear();
00270   pose_array_.header.stamp = ros::Time::now(); 
00271   pose_array_.header.frame_id = msg->header.frame_id; 
00272   pose_array_.poses.push_back(initial_pose);
00273   for (std::vector<geometry_msgs::Pose>::iterator it = leaf_pose_array.poses.begin(); it < leaf_pose_array.poses.end(); ++it){
00274     pose_array_.poses.push_back(*it);
00275   }
00276   pose_array_.poses.push_back(final_pose);
00277 
00278 //  // Estimate point normals
00279 //  pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); 
00280 //  //pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT> ());
00281 //  pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ> ());
00282 //  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
00283 //  ne.setSearchMethod (tree);
00284 //  ne.setInputCloud (cloud);
00285 //  ne.setKSearch (50);
00286 //  ne.compute (*normals);
00287 
00288 
00289   //unlock previously blocked shared variables 
00290   //alg_.unlock(); 
00291   //input_mutex_.exit(); 
00292 
00293   // publishing msgs
00294   output_marker_publisher_.publish(Marker_msg_);
00295   output_pointcloud_publisher_.publish(*cloud_cluster_right);
00296   poses_publisher_.publish(pose_array_);
00297   data_processed_ = true;
00298 }
00299 
00300 /*  [service callbacks] */
00301 bool ZyonzFindLeafProbingPointsAlgNode::get_pose_arrayCallback(zyonz_msgs::GetPoseArray::Request &req, zyonz_msgs::GetPoseArray::Response &res) 
00302 { 
00303   ROS_INFO("ZyonzFindLeafProbingPointsAlgNode::get_pose_arrayCallback: New Request Received!"); 
00304 
00305   //use appropiate mutex to shared variables if necessary 
00306   //this->alg_.lock(); 
00307   //this->get_pose_array_mutex_.enter(); 
00308 
00309   if(data_processed_) 
00310   { 
00311     ROS_INFO("ZyonzFindLeafProbingPointsAlgNode::get_pose_arrayCallback: Processing New Request!"); 
00312     //do operations with req and output on res 
00313     //res.data2 = req.data1 + my_var; 
00314 //    tf::StampedTransform current_transform;
00315 //    obtain_current_pose (current_transform);
00316 //    geometry_msgs::Pose current_pose;
00317 //    current_pose.position.x = current_transform.getOrigin().x();
00318 //    current_pose.position.y = current_transform.getOrigin().y();
00319 //    current_pose.position.z = current_transform.getOrigin().z();
00320 //    current_pose.orientation.x = current_transform.getRotation().x();
00321 //    current_pose.orientation.y = current_transform.getRotation().y();
00322 //    current_pose.orientation.z = current_transform.getRotation().z();
00323 //    current_pose.orientation.w = current_transform.getRotation().w();
00324 //    pose_array_.poses.push_back(current_pose);
00325     res.data = pose_array_;
00326   
00327   } 
00328   else 
00329   { 
00330     ROS_INFO("ZyonzFindLeafProbingPointsAlgNode::get_pose_arrayCallback: ERROR: alg has no data to request yet."); 
00331   } 
00332 
00333   //unlock previously blocked shared variables 
00334   //this->alg_.unlock(); 
00335   //this->get_pose_array_mutex_.exit(); 
00336 
00337   return true; 
00338 }
00339 
00340 /*  [action callbacks] */
00341 
00342 /*  [action requests] */
00343 void ZyonzFindLeafProbingPointsAlgNode::node_config_update(Config &config, uint32_t level)
00344 {
00345   this->alg_.lock();
00346 
00347   this->alg_.unlock();
00348 }
00349 
00350 void ZyonzFindLeafProbingPointsAlgNode::addNodeDiagnostics(void)
00351 {
00352 }
00353 
00354 /* main function */
00355 int main(int argc,char *argv[])
00356 {
00357   return algorithm_base::main<ZyonzFindLeafProbingPointsAlgNode>(argc, argv, "zyonz_find_leaf_probing_points_alg_node");
00358 }


zyonz_find_leaf_probing_points
Author(s): Sergi Foix
autogenerated on Fri Dec 6 2013 23:47:59