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 #include <boost/thread/mutex.hpp>
00035
00036 #include <map>
00037
00038 #include <ros/ros.h>
00039 #include <tf/tfMessage.h>
00040 #include <tf/transform_datatypes.h>
00041
00042 #include <geometry_msgs/PoseStamped.h>
00043
00044 namespace pr2_interactive_manipulation
00045 {
00046
00047 class TFThrottle
00048 {
00049 protected:
00050
00051 class TransformInfo {
00052 public:
00053 geometry_msgs::TransformStamped transform_;
00054 bool changed_;
00055 ros::Time last_published_;
00056
00057 TransformInfo(geometry_msgs::TransformStamped trf)
00058 {
00059 changed_ = true;
00060 last_published_ = ros::Time(0);
00061 transform_ = trf;
00062 }
00063 };
00064
00065 std::map<std::string, TransformInfo> transforms_;
00066 ros::NodeHandle root_nh_;
00067 ros::NodeHandle priv_nh_;
00068 ros::Publisher pub_;
00069 ros::Subscriber sub_;
00070 boost::mutex mutex_;
00071 ros::Timer sync_timer_;
00072 ros::Duration republish_time_;
00073 bool use_diff_;
00074 double linear_change_threshold_;
00075 double angular_change_threshold_;
00076
00077 bool changed(const geometry_msgs::TransformStamped &t1,
00078 const geometry_msgs::TransformStamped &t2)
00079 {
00080 if (!use_diff_) return true;
00081 tf::Transform tf1, tf2;
00082 tf::transformMsgToTF(t1.transform, tf1);
00083 tf::transformMsgToTF(t2.transform, tf2);
00084
00085 if (linear_change_threshold_ == 0.0 || angular_change_threshold_ == 0.0 ||
00086 tf1.getOrigin().distance(tf2.getOrigin()) > linear_change_threshold_ ||
00087 tf1.getRotation().angle(tf2.getRotation()) > angular_change_threshold_) return true;
00088 return false;
00089 }
00090
00091 void callback(const tf::tfMessageConstPtr &msg)
00092 {
00093 boost::mutex::scoped_lock lock(mutex_);
00094 for (size_t i=0; i<msg->transforms.size(); i++)
00095 {
00096 std::string key = msg->transforms[i].header.frame_id + msg->transforms[i].child_frame_id;
00097 std::map<std::string, TransformInfo>::iterator it = transforms_.find(key);
00098 if (it == transforms_.end())
00099 {
00100 transforms_.insert( std::pair<std::string, TransformInfo>(key, TransformInfo(msg->transforms[i])) );
00101 }
00102 else
00103 {
00104 ros::Time tf_time(msg->transforms[i].header.stamp);
00105 if (it->second.changed_ && msg->transforms[i].header.stamp > it->second.transform_.header.stamp)
00106 {
00107 it->second.transform_ = msg->transforms[i];
00108 }
00109 else if (ros::Duration(tf_time - it->second.last_published_) > ros::Duration(republish_time_))
00110 {
00111 it->second.transform_ = msg->transforms[i];
00112 it->second.changed_ = true;
00113 }
00114 else if ( changed(it->second.transform_, msg->transforms[i]) )
00115 {
00116 ROS_DEBUG_STREAM("Transform has changed: " << key);
00117 it->second.transform_ = msg->transforms[i];
00118 it->second.changed_ = true;
00119 }
00120 }
00121 }
00122 }
00123
00124 void sync()
00125 {
00126 boost::mutex::scoped_lock lock(mutex_);
00127 if (transforms_.empty()) return;
00128 tf::tfMessage msg;
00129 std::map<std::string, TransformInfo>::iterator it;
00130 for (it=transforms_.begin(); it!=transforms_.end(); it++)
00131 {
00132 if (it->second.changed_)
00133 {
00134 it->second.changed_ = false;
00135 it->second.last_published_ = ros::Time(it->second.transform_.header.stamp);
00136 msg.transforms.push_back(it->second.transform_);
00137 }
00138 }
00139 pub_.publish(msg);
00140 }
00141
00142 public:
00143 TFThrottle() : root_nh_(""), priv_nh_("~")
00144 {
00145 std::string pub_topic;
00146 priv_nh_.param<std::string>("publish_topic", pub_topic, "/tf_throttled");
00147 pub_ = root_nh_.advertise<tf::tfMessage>(pub_topic, 10);
00148 std::string sub_topic;
00149 priv_nh_.param<std::string>("subscribe_topic", sub_topic, "/tf");
00150 sub_ = root_nh_.subscribe(sub_topic, 10, &TFThrottle::callback, this);
00151 double rate;
00152 priv_nh_.param<double>("rate", rate, 10.0);
00153 sync_timer_ = root_nh_.createTimer(ros::Duration(1.0/rate), boost::bind( &TFThrottle::sync, this ) );
00154 double repub_time;
00155 priv_nh_.param<double>("republish_time", repub_time, 0.5);
00156 republish_time_ = ros::Duration(repub_time);
00157 priv_nh_.param<bool>("use_diff", use_diff_, true);
00158 priv_nh_.param<double>("angular_change_threshold", angular_change_threshold_, 0.02);
00159 priv_nh_.param<double>("linear_change_threshold", linear_change_threshold_, 1.0);
00160 ROS_INFO("TF throttle started; listening to %s and publishing on %s at %f Hz", sub_topic.c_str(),
00161 pub_topic.c_str(), rate);
00162 }
00163 };
00164
00165 }
00166
00167 int main(int argc, char **argv)
00168 {
00169 ros::init(argc, argv, "tf_throttle");
00170 pr2_interactive_manipulation::TFThrottle throttle;
00171 ros::spin();
00172 return 0;
00173 }