Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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
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
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
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
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
00138 gh.setAccepted();
00139
00140
00141 const tf2_web_republisher::TFSubscriptionGoal::ConstPtr& goal = gh.getGoal();
00142
00143
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
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
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
00190 boost::mutex::scoped_lock lock (tf_buffer_mutex_);
00191
00192
00193 transform = tf_buffer_.lookupTransform(it->getTargetFrame(),
00194 it->getSourceFrame(),
00195 ros::Time(0));
00196
00197
00198 it->updateTransform(transform);
00199 }
00200 catch (tf2::TransformException ex)
00201 {
00202 ROS_ERROR("%s", ex.what());
00203 }
00204
00205
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
00213 it->transmissionTriggered();
00214
00215
00216 feedback.transforms.push_back(transform);
00217 }
00218 }
00219 }
00220
00221 if (feedback.transforms.size() > 0)
00222 {
00223
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 }