tf_web_republisher.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  *  Copyright (c) 2014, Willow Garage, Inc.
00004  *  All rights reserved.
00005  *
00006  *  Redistribution and use in source and binary forms, with or without
00007  *  modification, are permitted provided that the following conditions
00008  *  are met:
00009  *
00010  *   * Redistributions of source code must retain the above copyright
00011  *     notice, this list of conditions and the following disclaimer.
00012  *   * Redistributions in binary form must reproduce the above
00013  *     copyright notice, this list of conditions and the following
00014  *     disclaimer in the documentation and/or other materials provided
00015  *     with the distribution.
00016  *   * Neither the name of the Willow Garage nor the names of its
00017  *     contributors may be used to endorse or promote products derived
00018  *     from this software without specific prior written permission.
00019  *
00020  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031  *  POSSIBILITY OF SUCH DAMAGE.
00032 
00033  *  Author: Julius Kammerl (jkammerl@willowgarage.com)
00034  *
00035  */
00036 
00037 #include <ros/ros.h>
00038 #include <tf2_ros/transform_listener.h>
00039 
00040 #include <boost/thread/mutex.hpp>
00041 #include "boost/thread.hpp"
00042 
00043 #include <tf/tfMessage.h>
00044 #include <tf/transform_datatypes.h>
00045 #include <geometry_msgs/TransformStamped.h>
00046 
00047 #include <actionlib/server/simple_action_server.h>
00048 #include <tf2_web_republisher/TFSubscriptionAction.h>
00049 
00050 #include "tf_pair.h"
00051 
00052 class TFRepublisher
00053 {
00054 protected:
00055 
00056   typedef actionlib::ActionServer<tf2_web_republisher::TFSubscriptionAction> TFTransformServer;
00057   typedef TFTransformServer::GoalHandle GoalHandle;
00058 
00059   ros::NodeHandle nh_;
00060 
00061   TFTransformServer as_;
00062 
00063   // struct that manages client goals
00064   struct ClientGoalInfo
00065   {
00066     GoalHandle handle;
00067     std::vector<TFPair> tf_subscriptions_;
00068     unsigned int client_ID_;
00069     ros::Timer  timer_;
00070   };
00071 
00072   std::list<boost::shared_ptr<ClientGoalInfo> > active_goals_;
00073   boost::mutex goals_mutex_;
00074 
00075   // tf2 buffer and transformer
00076 #if ROS_VERSION_MINOR < 10
00077   tf2::Buffer tf_buffer_;
00078   tf2::TransformListener tf_listener_;
00079 #else
00080   tf2_ros::Buffer tf_buffer_;
00081   tf2_ros::TransformListener tf_listener_;
00082 #endif
00083   boost::mutex tf_buffer_mutex_;
00084 
00085   unsigned int client_ID_count_;
00086 
00087 public:
00088 
00089   TFRepublisher(const std::string& name) :
00090       nh_(), as_(ros::NodeHandle(),
00091                  name,
00092                  boost::bind(&TFRepublisher::goalCB, this, _1),
00093                  boost::bind(&TFRepublisher::cancelCB, this, _1),
00094                  false),
00095       tf_listener_(tf_buffer_), client_ID_count_(0)
00096   {
00097     // start action server
00098     as_.start();
00099   }
00100 
00101   ~TFRepublisher() {}
00102 
00103   void cancelCB(GoalHandle& gh)
00104   {
00105     boost::mutex::scoped_lock l(goals_mutex_);
00106 
00107     ROS_DEBUG("GoalHandle canceled");
00108 
00109     // search for goal handle and remove it from active_goals_ list
00110     for(std::list<boost::shared_ptr<ClientGoalInfo> >::iterator it = active_goals_.begin(); it != active_goals_.end();)
00111     {
00112       ClientGoalInfo& info = **it;
00113       if(info.handle == gh)
00114       {
00115         it = active_goals_.erase(it);
00116         info.timer_.stop();
00117         info.handle.setCanceled();
00118         return;
00119       }
00120       else
00121         ++it;
00122     }
00123   }
00124 
00125   const std::string cleanTfFrame( const std::string frame_id ) const
00126   {
00127     if ( frame_id[0] == '/' ) {
00128       return frame_id.substr(1);
00129     }
00130     return frame_id;
00131   }
00132 
00133   void goalCB(GoalHandle& gh)
00134   {
00135     ROS_DEBUG("GoalHandle request received");
00136 
00137     // accept new goals
00138     gh.setAccepted();
00139 
00140     // get goal from handle
00141     const tf2_web_republisher::TFSubscriptionGoal::ConstPtr& goal = gh.getGoal();
00142 
00143     // generate goal_info struct
00144     boost::shared_ptr<ClientGoalInfo> goal_info = boost::make_shared<ClientGoalInfo>();
00145     goal_info->handle = gh;
00146     goal_info->client_ID_ = client_ID_count_++;
00147     goal_info->timer_ = nh_.createTimer(ros::Duration(1.0 / goal->rate),
00148                                         boost::bind(&TFRepublisher::processGoal, this, goal_info, _1));
00149 
00150     std::size_t request_size_ = goal->source_frames.size();
00151     goal_info->tf_subscriptions_.resize(request_size_);
00152 
00153     for (std::size_t i=0; i<request_size_; ++i )
00154     {
00155       TFPair& tf_pair = goal_info->tf_subscriptions_[i];
00156 
00157       std::string source_frame = cleanTfFrame(goal->source_frames[i]);
00158       std::string target_frame = cleanTfFrame(goal->target_frame);
00159 
00160       tf_pair.setSourceFrame(source_frame);
00161       tf_pair.setTargetFrame(target_frame);
00162       tf_pair.setAngularThres(goal->angular_thres);
00163       tf_pair.setTransThres(goal->trans_thres);
00164     }
00165 
00166     {
00167       boost::mutex::scoped_lock l(goals_mutex_);
00168       // add new goal to list of active goals/clients
00169       active_goals_.push_back(goal_info);
00170     }
00171 
00172   }
00173 
00174   void processGoal(boost::shared_ptr<ClientGoalInfo> goal_info, const ros::TimerEvent& )
00175   {
00176       tf2_web_republisher::TFSubscriptionFeedback feedback;
00177 
00178       {
00179         // iterate over tf_subscription map
00180         std::vector<TFPair>::iterator it ;
00181         std::vector<TFPair>::const_iterator end = goal_info->tf_subscriptions_.end();
00182 
00183         for (it=goal_info->tf_subscriptions_.begin(); it!=end; ++it)
00184         {
00185           geometry_msgs::TransformStamped transform;
00186 
00187           try
00188           {
00189             // protecting tf_buffer
00190             boost::mutex::scoped_lock lock (tf_buffer_mutex_);
00191 
00192             // lookup transformation for tf_pair
00193             transform = tf_buffer_.lookupTransform(it->getTargetFrame(),
00194                                                    it->getSourceFrame(),
00195                                                    ros::Time(0));
00196 
00197             // update tf_pair with transformtion
00198             it->updateTransform(transform);
00199           }
00200           catch (tf2::TransformException ex)
00201           {
00202             ROS_ERROR("%s", ex.what());
00203           }
00204 
00205           // check angular and translational thresholds
00206           if (it->updateNeeded())
00207           {
00208             transform.header.stamp = ros::Time::now();
00209             transform.header.frame_id = it->getTargetFrame();
00210             transform.child_frame_id = it->getSourceFrame();
00211 
00212             // notify tf_subscription that a network transmission has been triggered
00213             it->transmissionTriggered();
00214 
00215             // add transform to the feedback
00216             feedback.transforms.push_back(transform);
00217           }
00218         }
00219       }
00220 
00221       if (feedback.transforms.size() > 0)
00222       {
00223         // publish feedback
00224         goal_info->handle.publishFeedback(feedback);
00225         ROS_DEBUG("Client %d: TF feedback published:", goal_info->client_ID_);
00226       } else
00227       {
00228         ROS_DEBUG("Client %d: No TF frame update needed:", goal_info->client_ID_);
00229       }
00230     }
00231 };
00232 
00233 int main(int argc, char **argv)
00234 {
00235 ros::init(argc, argv, "tf2_web_republisher");
00236 
00237 TFRepublisher tf2_web_republisher(ros::this_node::getName());
00238 ros::spin();
00239 
00240 return 0;
00241 }


tf2_web_republisher
Author(s): Julius Kammer
autogenerated on Mon Oct 6 2014 07:54:39