pole_structure_mapper.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2011, ISR University of Coimbra.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the ISR University of Coimbra nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Gonçalo Cabrita on 03/10/2012
00036 *********************************************************************/
00037 
00038 #include <ros/ros.h>
00039 #include <tf/tf.h>
00040 #include <boost/foreach.hpp>
00041 #include <visualization_msgs/Marker.h>
00042 #include <pole_structure_mapper/PoleSectionStamped.h>
00043 #include <pole_structure_mapper/PoleStructure.h>
00044 
00045 #include <tf/transform_listener.h>
00046 #include <tf/message_filter.h>
00047 #include <message_filters/subscriber.h>
00048 
00049 class PoleMapper
00050 {
00051         public:
00052         PoleMapper();
00053         ~PoleMapper();
00054         
00055         void displayStructure();
00056         void publishStructure();
00057 
00058         private:
00059         void poleSectionCallback(const pole_structure_mapper::PoleSectionStamped::ConstPtr& msg);
00060     
00061         bool polesAreTheSame(pole_structure_mapper::PoleSection * pole1, pole_structure_mapper::PoleSection * pole2);
00062         void getPointInAxis(pole_structure_mapper::PoleSection * pole, geometry_msgs::Point * p, geometry_msgs::Point * p_in_axis);
00063     
00064         // ROS stuff
00065         ros::NodeHandle nh_;
00066         ros::NodeHandle pnh_;
00067     
00068         // Global frame_id
00069         std::string global_frame_id_;
00070     
00071         // Thresholds
00072         double diameter_threshold_;
00073         double axis_threshold_;
00074         double distance_threshold_;
00075         double length_threshold_;
00076     
00077         //ros::Subscriber cloud_sub_;
00078         message_filters::Subscriber<pole_structure_mapper::PoleSectionStamped> pole_sub_;
00079         tf::TransformListener tf_;
00080         tf::MessageFilter<pole_structure_mapper::PoleSectionStamped> * tf_filter_;
00081     
00082         ros::Publisher pole_structure_pub_;
00083         ros::Publisher marker_pub_;
00084     
00085         pole_structure_mapper::PoleStructure pole_structure_;
00086 };
00087 
00088 PoleMapper::PoleMapper() : nh_(), pnh_("~")
00089 {       
00090     pnh_.param<std::string>("global_frame_id", global_frame_id_, "/map");
00091     pnh_.param("diameter_threshold", diameter_threshold_, 0.03);
00092     pnh_.param("axis_threshold", axis_threshold_, 10.0);
00093     axis_threshold_ = axis_threshold_*M_PI/180.0;
00094     pnh_.param("distance_threshold", distance_threshold_, 0.10);
00095     pnh_.param("length_threshold", length_threshold_, 0.60);
00096     
00097     pole_sub_.subscribe(nh_, "/pole", 1);
00098         tf_filter_ = new tf::MessageFilter<pole_structure_mapper::PoleSectionStamped>(pole_sub_, tf_, global_frame_id_, 10);
00099     tf_filter_->registerCallback( boost::bind(&PoleMapper::poleSectionCallback, this, _1) );
00100     
00101         pole_structure_pub_ = nh_.advertise<pole_structure_mapper::PoleStructure>("pole_structure", 1);
00102     marker_pub_ = nh_.advertise<visualization_msgs::Marker>("pole_structure_visualizer", 1);
00103     
00104     pole_structure_.header.frame_id = global_frame_id_;
00105 }
00106 
00107 PoleMapper::~PoleMapper()
00108 {
00109         
00110 }
00111 
00112 void PoleMapper::poleSectionCallback(const pole_structure_mapper::PoleSectionStamped::ConstPtr& msg)
00113 {
00114     ROS_INFO("Pole Structure Mapper - %s - Got a pole section...", __FUNCTION__);
00115     
00116         if(msg->pole.length < length_threshold_) return;
00117 
00118         // 1. Transform pole section into global frame
00119     geometry_msgs::PointStamped cylinder_point, map_point;
00120     
00121     cylinder_point.header = msg->header;
00122     cylinder_point.point = msg->pole.base;
00123     
00124     try { tf_.transformPoint(global_frame_id_, cylinder_point, map_point); }
00125         catch(tf::TransformException &ex) 
00126         {
00127                 ROS_ERROR("Pole Structure Mapper- %s - Error: %s", __FUNCTION__, ex.what());
00128                 return;
00129         }
00130     
00131     geometry_msgs::Vector3Stamped cylinder_axis, map_axis;
00132     
00133     cylinder_axis.header = msg->header;
00134     cylinder_axis.vector = msg->pole.axis;
00135     
00136     try { tf_.transformVector(global_frame_id_, cylinder_axis, map_axis); }
00137         catch(tf::TransformException &ex) 
00138         {
00139                 ROS_ERROR("Pole Structure Mapper- %s - Error: %s", __FUNCTION__, ex.what());
00140                 return;
00141         }
00142     
00143     pole_structure_mapper::PoleSection map_pole_section;
00144     map_pole_section.base = map_point.point;
00145     map_pole_section.axis = map_axis.vector;
00146     map_pole_section.length = msg->pole.length;
00147     map_pole_section.diameter = msg->pole.diameter;
00148     
00149     // 2. Check if pole exists in the current structure
00150     bool found_pole = false;
00151     for(int i=0 ; i<pole_structure_.pole.size() ; i++)
00152     {
00153         // 2.1 If it already exists update it
00154         if(polesAreTheSame(&pole_structure_.pole[i], &map_pole_section))
00155         {
00156             ROS_INFO("Poles are the same!!!");
00157 
00158             // Update pole position and length!
00159             geometry_msgs::Point points[4];
00160             
00161             points[0].x = pole_structure_.pole[i].base.x;
00162             points[0].y = pole_structure_.pole[i].base.y;
00163             points[0].z = pole_structure_.pole[i].base.z;
00164             
00165             points[1].x = pole_structure_.pole[i].base.x + pole_structure_.pole[i].length * pole_structure_.pole[i].axis.x;
00166             points[1].y = pole_structure_.pole[i].base.y + pole_structure_.pole[i].length * pole_structure_.pole[i].axis.y;
00167             points[1].z = pole_structure_.pole[i].base.z + pole_structure_.pole[i].length * pole_structure_.pole[i].axis.z;
00168             
00169             geometry_msgs::Point top2, base2;
00170             points[3].x = map_pole_section.base.x + map_pole_section.length * map_pole_section.axis.x;
00171             points[3].y = map_pole_section.base.y + map_pole_section.length * map_pole_section.axis.y;
00172             points[3].z = map_pole_section.base.z + map_pole_section.length * map_pole_section.axis.z;
00173             getPointInAxis(&pole_structure_.pole[i], &points[3], &points[3]);
00174             getPointInAxis(&pole_structure_.pole[i], &map_pole_section.base, &points[2]);
00175             
00176             geometry_msgs::Point cylinder_top;
00177             
00178             double lowest_t = 0.0;
00179             double highest_t = 0.0;
00180             
00181             for(int j=1 ; j<4 ; j++)
00182             {
00183                 double t = (points[j].x - pole_structure_.pole[i].base.x)/pole_structure_.pole[i].axis.x;
00184                 
00185                 if(t<lowest_t)
00186                 {
00187                     pole_structure_.pole[i].base.x = points[j].x;
00188                     pole_structure_.pole[i].base.y = points[j].y;
00189                     pole_structure_.pole[i].base.z = points[j].z;
00190                     lowest_t = t;
00191                 }
00192                 
00193                 if(t>highest_t)
00194                 {
00195                     cylinder_top.x = points[j].x;
00196                     cylinder_top.y = points[j].y;
00197                     cylinder_top.z = points[j].z;
00198                     highest_t = t;
00199                 }
00200             }
00201             
00202             // New length
00203             pole_structure_.pole[i].length = sqrt(pow(cylinder_top.x - pole_structure_.pole[i].base.x, 2) + pow(cylinder_top.y - pole_structure_.pole[i].base.y, 2) + pow(cylinder_top.z - pole_structure_.pole[i].base.z, 2));
00204             
00205             // Average diameter
00206             pole_structure_.pole[i].diameter = (pole_structure_.pole[i].diameter + map_pole_section.diameter) / 2.0;
00207             
00208             // Linear interpolation of both axis
00209             tf::Vector3 pi(pole_structure_.pole[i].axis.x, pole_structure_.pole[i].axis.y, pole_structure_.pole[i].axis.z);
00210             tf::Vector3 p(map_pole_section.axis.x, map_pole_section.axis.y, map_pole_section.axis.z);
00211             pi = pi.lerp(p, 0);
00212             pole_structure_.pole[i].axis.x = pi.x();
00213             pole_structure_.pole[i].axis.y = pi.y();
00214             pole_structure_.pole[i].axis.z = pi.z();
00215             
00216             // Average base point
00217             // TODO: Finish this...
00218             
00219             found_pole = true;
00220             break;
00221         }
00222     }
00223     
00224     // 2.2 If not add it
00225     if(!found_pole)
00226     {
00227         ROS_INFO("Poles are not the same!!!");
00228 
00229         pole_structure_.pole.push_back(map_pole_section);
00230     }
00231     
00232     pole_structure_.header.stamp = ros::Time::now();
00233 }
00234 
00235 bool PoleMapper::polesAreTheSame(pole_structure_mapper::PoleSection * pole1, pole_structure_mapper::PoleSection * pole2)
00236 {
00237     // 1. Check the diameter
00238     if(fabs(pole1->diameter - pole2->diameter) > diameter_threshold_)
00239        return false;
00240 
00241         ROS_INFO("Passed diameter...");
00242     
00243     // 2. Check the axis
00244     tf::Vector3 p1(pole1->axis.x, pole1->axis.y, pole1->axis.z);
00245     tf::Vector3 p2(pole2->axis.x, pole2->axis.y, pole2->axis.z);
00246     double alpha = fabs(acos(p1.dot(p2)));
00247     if(axis_threshold_ < alpha && alpha < M_PI-axis_threshold_)
00248         return false;
00249 
00250         ROS_INFO("Passed axis...");
00251     
00252     // 3. Check the position
00253     geometry_msgs::Point p;
00254     getPointInAxis(pole1, &pole2->base, &p);
00255     
00256     double distance = sqrt(pow(pole2->base.x - p.x, 2) + pow(pole2->base.y - p.y, 2) + pow(pole2->base.z - p.z,2));
00257     
00258     if(distance > distance_threshold_) return false;
00259 
00260         ROS_INFO("Passed position...");
00261        
00262     return true;
00263 }
00264 
00265 void PoleMapper::getPointInAxis(pole_structure_mapper::PoleSection * pole, geometry_msgs::Point * p, geometry_msgs::Point * p_in_axis)
00266 {
00267     double t = (pole->axis.x*(p->x-pole->base.x) + pole->axis.y*(p->y-pole->base.y) + pole->axis.z*(p->z-pole->base.z))/(pow(pole->axis.x,2) + pow(pole->axis.y,2) + pow(pole->axis.z,2));
00268     
00269     p_in_axis->x = pole->base.x + pole->axis.x * t;
00270     p_in_axis->y = pole->base.y + pole->axis.y * t;
00271     p_in_axis->z = pole->base.z + pole->axis.z * t;
00272 }
00273 
00274 void PoleMapper::publishStructure()
00275 {
00276         pole_structure_pub_.publish(pole_structure_);
00277 }
00278 
00279 void PoleMapper::displayStructure()
00280 {
00281     for(int i=0 ; i<pole_structure_.pole.size() ; i++)
00282     {
00283         char tag[16];
00284         sprintf(tag, "pole_%d", i);
00285         
00286         // Display the cylinder
00287         visualization_msgs::Marker marker;
00288         marker.header.frame_id = global_frame_id_;
00289         marker.header.stamp = ros::Time::now();
00290         
00291         marker.ns = tag;
00292         marker.id = 0;
00293         
00294         marker.type = visualization_msgs::Marker::CYLINDER;
00295         
00296         marker.action = visualization_msgs::Marker::ADD;
00297         
00298         // For the marker the position is the middle point between the bottom and the top
00299         marker.pose.position.x = pole_structure_.pole[i].base.x + pole_structure_.pole[i].length/2.0 * pole_structure_.pole[i].axis.x;
00300         marker.pose.position.y = pole_structure_.pole[i].base.y + pole_structure_.pole[i].length/2.0 * pole_structure_.pole[i].axis.y;
00301         marker.pose.position.z = pole_structure_.pole[i].base.z + pole_structure_.pole[i].length/2.0 * pole_structure_.pole[i].axis.z;
00302 
00303         tf::Vector3 axis_vector(pole_structure_.pole[i].axis.x, pole_structure_.pole[i].axis.y, pole_structure_.pole[i].axis.z);
00304         tf::Vector3 up_vector(0.0, 0.0, 1.0);
00305         tf::Vector3 right_vector = axis_vector.cross(up_vector);
00306         right_vector.normalized();
00307         tf::Quaternion q(right_vector, -1.0*acos(axis_vector.dot(up_vector)));
00308         q.normalize();
00309         geometry_msgs::Quaternion cylinder_orientation;
00310         tf::quaternionTFToMsg(q, cylinder_orientation);
00311 
00312         marker.pose.orientation = cylinder_orientation;
00313         
00314         marker.scale.x = pole_structure_.pole[i].diameter;
00315         marker.scale.y = pole_structure_.pole[i].diameter;
00316         marker.scale.z = pole_structure_.pole[i].length;
00317         
00318         marker.color.r = 1.0f;
00319         marker.color.g = 0.0f;
00320         marker.color.b = 0.0f;
00321         marker.color.a = 0.8;
00322         
00323         marker.lifetime = ros::Duration();
00324         
00325         // Publish the marker
00326         marker_pub_.publish(marker);
00327     }
00328 }
00329 
00330 
00331 int main(int argc, char** argv)
00332 {
00333         ros::init(argc, argv, "pole_structure_mapper_node");
00334     
00335         ROS_INFO("Pole Structure Mapper for ROS v0.1");
00336         
00337         PoleMapper pm;
00338         
00339         ros::Rate r(1.0);
00340         while(ros::ok())
00341         {
00342                 pm.publishStructure();
00343                 pm.displayStructure();
00344                 
00345                 ros::spinOnce();
00346                 r.sleep();
00347         }
00348 }
00349 
00350 // EOF
00351 


pole_structure_mapper
Author(s): Gonçalo Cabrita and Mahmoud Tavakoli
autogenerated on Mon Jan 6 2014 11:26:24