buffer_core.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00032 #include "tf2/buffer_core.h"
00033 #include "tf2/time_cache.h"
00034 #include "tf2/exceptions.h"
00035 #include "tf2_msgs/TF2Error.h"
00036 
00037 #include <ros/assert.h>
00038 #include <ros/console.h>
00039 #include "tf2/LinearMath/btTransform.h"
00040 
00041 //legacy
00042 //#include "tf/tf.h"
00043 //#include "tf/transform_datatypes.h"
00044 
00045 namespace tf2
00046 {
00047 
00048 // Must provide storage for non-integral static const class members.
00049 // Otherwise you get undefined symbol errors on OS X (why not on Linux?).
00050 // Thanks to Rob for pointing out the right way to do this.
00051 const double tf2::BufferCore::DEFAULT_CACHE_TIME;
00052 
00054 void transformMsgToTF2(const geometry_msgs::Transform& msg, btTransform& bt)
00055 {bt = btTransform(btQuaternion(msg.rotation.x, msg.rotation.y, msg.rotation.z, msg.rotation.w), btVector3(msg.translation.x, msg.translation.y, msg.translation.z));}
00056 
00058 void transformTF2ToMsg(const btTransform& bt, geometry_msgs::Transform& msg)
00059 {
00060   msg.translation.x = bt.getOrigin().x();
00061   msg.translation.y = bt.getOrigin().y();
00062   msg.translation.z = bt.getOrigin().z();
00063   msg.rotation.x = bt.getRotation().x();
00064   msg.rotation.y = bt.getRotation().y();
00065   msg.rotation.z = bt.getRotation().z();
00066   msg.rotation.w = bt.getRotation().w();
00067 }
00068 
00070 void transformTF2ToMsg(const btTransform& bt, geometry_msgs::TransformStamped& msg, ros::Time stamp, const std::string& frame_id, const std::string& child_frame_id)
00071 {
00072   transformTF2ToMsg(bt, msg.transform);
00073   msg.header.stamp = stamp;
00074   msg.header.frame_id = frame_id;
00075   msg.child_frame_id = child_frame_id;
00076 }
00077 
00078 void transformTF2ToMsg(const btQuaternion& orient, const btVector3& pos, geometry_msgs::Transform& msg)
00079 {
00080   msg.translation.x = pos.x();
00081   msg.translation.y = pos.y();
00082   msg.translation.z = pos.z();
00083   msg.rotation.x = orient.x();
00084   msg.rotation.y = orient.y();
00085   msg.rotation.z = orient.z();
00086   msg.rotation.w = orient.w();
00087 }
00088 
00089 void transformTF2ToMsg(const btQuaternion& orient, const btVector3& pos, geometry_msgs::TransformStamped& msg, ros::Time stamp, const std::string& frame_id, const std::string& child_frame_id)
00090 {
00091   transformTF2ToMsg(orient, pos, msg.transform);
00092   msg.header.stamp = stamp;
00093   msg.header.frame_id = frame_id;
00094   msg.child_frame_id = child_frame_id;
00095 }
00096 
00097 void setIdentity(geometry_msgs::Transform& tx)
00098 {
00099   tx.translation.x = 0;
00100   tx.translation.y = 0;
00101   tx.translation.z = 0;
00102   tx.rotation.x = 0;
00103   tx.rotation.y = 0;
00104   tx.rotation.z = 0;
00105   tx.rotation.w = 1;
00106 }
00107 
00108 bool startsWithSlash(const std::string& frame_id)
00109 {
00110   if (frame_id.size() > 0)
00111     if (frame_id[0] == '/')
00112       return true;
00113   return false;
00114 }
00115 
00116 std::string stripSlash(const std::string& in)
00117 {
00118   std::string out = in;
00119   if (startsWithSlash(in))
00120     out.erase(0,1);
00121   return out;
00122 }
00123 
00124 
00125 bool BufferCore::warnFrameId(const char* function_name_arg, const std::string& frame_id) const
00126 {
00127   if (frame_id.size() == 0)
00128   {
00129     std::stringstream ss;
00130     ss << "Invalid argument passed to "<< function_name_arg <<" in tf2 frame_ids cannot be empty";
00131     ROS_WARN("%s",ss.str().c_str());
00132     return true;
00133   }
00134 
00135   if (startsWithSlash(frame_id))
00136   {
00137     std::stringstream ss;
00138     ss << "Invalid argument \"" << frame_id << "\" passed to "<< function_name_arg <<" in tf2 frame_ids cannot start with a '/' like: ";
00139     ROS_WARN("%s",ss.str().c_str());
00140     return true;
00141   }
00142 
00143   return false;
00144 }
00145 
00146 CompactFrameID BufferCore::validateFrameId(const char* function_name_arg, const std::string& frame_id) const
00147 {
00148   if (frame_id.empty())
00149   {
00150     std::stringstream ss;
00151     ss << "Invalid argument passed to "<< function_name_arg <<" in tf2 frame_ids cannot be empty";
00152     throw tf2::InvalidArgumentException(ss.str().c_str());
00153   }
00154 
00155   if (startsWithSlash(frame_id))
00156   {
00157     std::stringstream ss;
00158     ss << "Invalid argument \"" << frame_id << "\" passed to "<< function_name_arg <<" in tf2 frame_ids cannot start with a '/' like: ";
00159     throw tf2::InvalidArgumentException(ss.str().c_str());
00160   }
00161 
00162   CompactFrameID id = lookupFrameNumber(frame_id);
00163   if (id == 0)
00164   {
00165     std::stringstream ss;
00166     ss << "\"" << frame_id << "\" passed to "<< function_name_arg <<" does not exist. ";
00167     throw tf2::LookupException(ss.str().c_str());
00168   }
00169   
00170   return id;
00171 }
00172 
00173 BufferCore::BufferCore(ros::Duration cache_time)
00174 : cache_time_(cache_time)
00175 , transformable_callbacks_counter_(0)
00176 , transformable_requests_counter_(0)
00177 {
00178   frameIDs_["NO_PARENT"] = 0;
00179   frames_.push_back(NULL);// new TimeCache(interpolating, cache_time, max_extrapolation_distance));//unused but needed for iteration over all elements
00180   frameIDs_reverse.push_back("NO_PARENT");
00181 }
00182 
00183 BufferCore::~BufferCore()
00184 {
00185 
00186 }
00187 
00188 void BufferCore::clear()
00189 {
00190   //old_tf_.clear();
00191 
00192 
00193   boost::mutex::scoped_lock lock(frame_mutex_);
00194   if ( frames_.size() > 1 )
00195   {
00196     for (std::vector< TimeCacheInterface*>::iterator  cache_it = frames_.begin() + 1; cache_it != frames_.end(); ++cache_it)
00197     {
00198       (*cache_it)->clearList();
00199     }
00200   }
00201   
00202 }
00203 
00204 bool BufferCore::setTransform(const geometry_msgs::TransformStamped& transform_in, const std::string& authority, bool is_static)
00205 {
00206 
00208   /* tf::StampedTransform tf_transform;
00209   tf::transformStampedMsgToTF(transform_in, tf_transform);
00210   if  (!old_tf_.setTransform(tf_transform, authority))
00211   {
00212     printf("Warning old setTransform Failed but was not caught\n");
00213     }*/
00214 
00216   geometry_msgs::TransformStamped stripped = transform_in;
00217   stripped.header.frame_id = stripSlash(stripped.header.frame_id);
00218   stripped.child_frame_id = stripSlash(stripped.child_frame_id);
00219 
00220 
00221   bool error_exists = false;
00222   if (stripped.child_frame_id == stripped.header.frame_id)
00223   {
00224     ROS_ERROR("TF_SELF_TRANSFORM: Ignoring transform from authority \"%s\" with frame_id and child_frame_id  \"%s\" because they are the same",  authority.c_str(), stripped.child_frame_id.c_str());
00225     error_exists = true;
00226   }
00227 
00228   if (stripped.child_frame_id == "")
00229   {
00230     ROS_ERROR("TF_NO_CHILD_FRAME_ID: Ignoring transform from authority \"%s\" because child_frame_id not set ", authority.c_str());
00231     error_exists = true;
00232   }
00233 
00234   if (stripped.header.frame_id == "")
00235   {
00236     ROS_ERROR("TF_NO_FRAME_ID: Ignoring transform with child_frame_id \"%s\"  from authority \"%s\" because frame_id not set", stripped.child_frame_id.c_str(), authority.c_str());
00237     error_exists = true;
00238   }
00239 
00240   if (std::isnan(stripped.transform.translation.x) || std::isnan(stripped.transform.translation.y) || std::isnan(stripped.transform.translation.z)||
00241       std::isnan(stripped.transform.rotation.x) ||       std::isnan(stripped.transform.rotation.y) ||       std::isnan(stripped.transform.rotation.z) ||       std::isnan(stripped.transform.rotation.w))
00242   {
00243     ROS_ERROR("TF_NAN_INPUT: Ignoring transform for child_frame_id \"%s\" from authority \"%s\" because of a nan value in the transform (%f %f %f) (%f %f %f %f)",
00244               stripped.child_frame_id.c_str(), authority.c_str(),
00245               stripped.transform.translation.x, stripped.transform.translation.y, stripped.transform.translation.z,
00246               stripped.transform.rotation.x, stripped.transform.rotation.y, stripped.transform.rotation.z, stripped.transform.rotation.w
00247               );
00248     error_exists = true;
00249   }
00250 
00251   if (error_exists)
00252     return false;
00253   
00254   {
00255     boost::mutex::scoped_lock lock(frame_mutex_);
00256     CompactFrameID frame_number = lookupOrInsertFrameNumber(stripped.child_frame_id);
00257     TimeCacheInterface* frame = getFrame(frame_number);
00258     if (frame == NULL)
00259       frame = allocateFrame(frame_number, is_static);
00260 
00261     if (frame->insertData(TransformStorage(stripped, lookupOrInsertFrameNumber(stripped.header.frame_id), frame_number)))
00262     {
00263       frame_authority_[frame_number] = authority;
00264     }
00265     else
00266     {
00267       ROS_WARN("TF_OLD_DATA ignoring data from the past for frame %s at time %g according to authority %s\nPossible reasons are listed at ", stripped.child_frame_id.c_str(), stripped.header.stamp.toSec(), authority.c_str());
00268       return false;
00269     }
00270   }
00271 
00272   testTransformableRequests();
00273 
00274   return true;
00275 }
00276 
00277 TimeCacheInterface* BufferCore::allocateFrame(CompactFrameID cfid, bool is_static)
00278 {
00279   TimeCacheInterface* frame_ptr = frames_[cfid];
00280   if ( frame_ptr != NULL)
00281     delete frame_ptr;
00282   if (is_static)
00283     frames_[cfid] = new StaticCache();
00284   else
00285     frames_[cfid] = new TimeCache(cache_time_);
00286   
00287   return frames_[cfid];
00288 }
00289 
00290 enum WalkEnding
00291 {
00292   Identity,
00293   TargetParentOfSource,
00294   SourceParentOfTarget,
00295   FullPath,
00296 };
00297 
00298 template<typename F>
00299 int BufferCore::walkToTopParent(F& f, ros::Time time, CompactFrameID target_id, CompactFrameID source_id, std::string* error_string) const
00300 {
00301   // Short circuit if zero length transform to allow lookups on non existant links
00302   if (source_id == target_id)
00303   {
00304     f.finalize(Identity, time);
00305     return tf2_msgs::TF2Error::NO_ERROR;
00306   }
00307 
00308   //If getting the latest get the latest common time
00309   if (time == ros::Time())
00310   {
00311     int retval = getLatestCommonTime(target_id, source_id, time, error_string);
00312     if (retval != tf2_msgs::TF2Error::NO_ERROR)
00313     {
00314       return retval;
00315     }
00316   }
00317 
00318   // Walk the tree to its root from the source frame, accumulating the transform
00319   CompactFrameID frame = source_id;
00320   CompactFrameID top_parent = frame;
00321   uint32_t depth = 0;
00322   while (frame != 0)
00323   {
00324     TimeCacheInterface* cache = getFrame(frame);
00325 
00326     if (!cache)
00327     {
00328       // There will be no cache for the very root of the tree
00329       top_parent = frame;
00330       break;
00331     }
00332 
00333     CompactFrameID parent = f.gather(cache, time, 0);
00334     if (parent == 0)
00335     {
00336       // Just break out here... there may still be a path from source -> target
00337       top_parent = frame;
00338       break;
00339     }
00340 
00341     // Early out... target frame is a direct parent of the source frame
00342     if (frame == target_id)
00343     {
00344       f.finalize(TargetParentOfSource, time);
00345       return tf2_msgs::TF2Error::NO_ERROR;
00346     }
00347 
00348     f.accum(true);
00349 
00350     top_parent = frame;
00351     frame = parent;
00352 
00353     ++depth;
00354     if (depth > MAX_GRAPH_DEPTH)
00355     {
00356       if (error_string)
00357       {
00358         std::stringstream ss;
00359         ss << "The tf tree is invalid because it contains a loop." << std::endl
00360            << allFramesAsString() << std::endl;
00361         *error_string = ss.str();
00362       }
00363       return tf2_msgs::TF2Error::LOOKUP_ERROR;
00364     }
00365   }
00366 
00367   // Now walk to the top parent from the target frame, accumulating its transform
00368   frame = target_id;
00369   depth = 0;
00370   while (frame != top_parent)
00371   {
00372     TimeCacheInterface* cache = getFrame(frame);
00373 
00374     if (!cache)
00375     {
00376       break;
00377     }
00378 
00379     CompactFrameID parent = f.gather(cache, time, error_string);
00380     if (parent == 0)
00381     {
00382       if (error_string)
00383       {
00384         std::stringstream ss;
00385         ss << *error_string << ", when looking up transform from frame [" << lookupFrameString(source_id) << "] to frame [" << lookupFrameString(target_id) << "]";
00386         *error_string = ss.str();
00387       }
00388 
00389       return tf2_msgs::TF2Error::EXTRAPOLATION_ERROR;
00390     }
00391 
00392     // Early out... source frame is a direct parent of the target frame
00393     if (frame == source_id)
00394     {
00395       f.finalize(SourceParentOfTarget, time);
00396       return tf2_msgs::TF2Error::NO_ERROR;
00397     }
00398 
00399     f.accum(false);
00400 
00401     frame = parent;
00402 
00403     ++depth;
00404     if (depth > MAX_GRAPH_DEPTH)
00405     {
00406       if (error_string)
00407       {
00408         std::stringstream ss;
00409         ss << "The tf tree is invalid because it contains a loop." << std::endl
00410            << allFramesAsString() << std::endl;
00411         *error_string = ss.str();
00412       }
00413       return tf2_msgs::TF2Error::LOOKUP_ERROR;
00414     }
00415   }
00416 
00417   if (frame != top_parent)
00418   {
00419     createConnectivityErrorString(source_id, target_id, error_string);
00420     return tf2_msgs::TF2Error::CONNECTIVITY_ERROR;
00421   }
00422 
00423   f.finalize(FullPath, time);
00424 
00425   return tf2_msgs::TF2Error::NO_ERROR;
00426 }
00427 
00428 struct TransformAccum
00429 {
00430   TransformAccum()
00431   : source_to_top_quat(0.0, 0.0, 0.0, 1.0)
00432   , source_to_top_vec(0.0, 0.0, 0.0)
00433   , target_to_top_quat(0.0, 0.0, 0.0, 1.0)
00434   , target_to_top_vec(0.0, 0.0, 0.0)
00435   , result_quat(0.0, 0.0, 0.0, 1.0)
00436   , result_vec(0.0, 0.0, 0.0)
00437   {
00438   }
00439 
00440   CompactFrameID gather(TimeCacheInterface* cache, ros::Time time, std::string* error_string)
00441   {
00442     if (!cache->getData(time, st, error_string))
00443     {
00444       return 0;
00445     }
00446 
00447     return st.frame_id_;
00448   }
00449 
00450   void accum(bool source)
00451   {
00452     if (source)
00453     {
00454       source_to_top_vec = quatRotate(st.rotation_, source_to_top_vec) + st.translation_;
00455       source_to_top_quat = st.rotation_ * source_to_top_quat;
00456     }
00457     else
00458     {
00459       target_to_top_vec = quatRotate(st.rotation_, target_to_top_vec) + st.translation_;
00460       target_to_top_quat = st.rotation_ * target_to_top_quat;
00461     }
00462   }
00463 
00464   void finalize(WalkEnding end, ros::Time _time)
00465   {
00466     switch (end)
00467     {
00468     case Identity:
00469       break;
00470     case TargetParentOfSource:
00471       result_vec = source_to_top_vec;
00472       result_quat = source_to_top_quat;
00473       break;
00474     case SourceParentOfTarget:
00475       {
00476         btQuaternion inv_target_quat = target_to_top_quat.inverse();
00477         btVector3 inv_target_vec = quatRotate(inv_target_quat, -target_to_top_vec);
00478         result_vec = inv_target_vec;
00479         result_quat = inv_target_quat;
00480         break;
00481       }
00482     case FullPath:
00483       {
00484         btQuaternion inv_target_quat = target_to_top_quat.inverse();
00485         btVector3 inv_target_vec = quatRotate(inv_target_quat, -target_to_top_vec);
00486 
00487         result_vec = quatRotate(inv_target_quat, source_to_top_vec) + inv_target_vec;
00488         result_quat = inv_target_quat * source_to_top_quat;
00489       }
00490       break;
00491     };
00492 
00493     time = _time;
00494   }
00495 
00496   TransformStorage st;
00497   ros::Time time;
00498   btQuaternion source_to_top_quat;
00499   btVector3 source_to_top_vec;
00500   btQuaternion target_to_top_quat;
00501   btVector3 target_to_top_vec;
00502 
00503   btQuaternion result_quat;
00504   btVector3 result_vec;
00505 };
00506 
00507 geometry_msgs::TransformStamped BufferCore::lookupTransform(const std::string& target_frame,
00508                                                             const std::string& source_frame,
00509                                                             const ros::Time& time) const
00510 {
00511   boost::mutex::scoped_lock lock(frame_mutex_);
00512 
00513   if (target_frame == source_frame) {
00514     geometry_msgs::TransformStamped identity;
00515     identity.header.frame_id = target_frame;
00516     identity.header.stamp = time;
00517     identity.child_frame_id = source_frame;
00518     identity.transform.rotation.w = 1;
00519     return identity;
00520   }
00521 
00522   CompactFrameID target_id = validateFrameId("lookupTransform argument target_frame", target_frame);
00523   CompactFrameID source_id = validateFrameId("lookupTransform argument source_frame", source_frame);
00524 
00525   std::string error_string;
00526   TransformAccum accum;
00527   int retval = walkToTopParent(accum, time, target_id, source_id, &error_string);
00528   if (retval != tf2_msgs::TF2Error::NO_ERROR)
00529   {
00530     switch (retval)
00531     {
00532     case tf2_msgs::TF2Error::CONNECTIVITY_ERROR:
00533       throw ConnectivityException(error_string);
00534     case tf2_msgs::TF2Error::EXTRAPOLATION_ERROR:
00535       throw ExtrapolationException(error_string);
00536     case tf2_msgs::TF2Error::LOOKUP_ERROR:
00537       throw LookupException(error_string);
00538     default:
00539       ROS_ERROR("Unknown error code: %d", retval);
00540       ROS_BREAK();
00541     }
00542   }
00543 
00544   geometry_msgs::TransformStamped output_transform;
00545   transformTF2ToMsg(accum.result_quat, accum.result_vec, output_transform, accum.time, target_frame, source_frame);
00546   return output_transform;
00547 }
00548 
00549                                                        
00550 geometry_msgs::TransformStamped BufferCore::lookupTransform(const std::string& target_frame, 
00551                                                         const ros::Time& target_time,
00552                                                         const std::string& source_frame,
00553                                                         const ros::Time& source_time,
00554                                                         const std::string& fixed_frame) const
00555 {
00556   validateFrameId("lookupTransform argument target_frame", target_frame);
00557   validateFrameId("lookupTransform argument source_frame", source_frame);
00558   validateFrameId("lookupTransform argument fixed_frame", fixed_frame);
00559 
00560   geometry_msgs::TransformStamped output;
00561   geometry_msgs::TransformStamped temp1 =  lookupTransform(fixed_frame, source_frame, source_time);
00562   geometry_msgs::TransformStamped temp2 =  lookupTransform(target_frame, fixed_frame, target_time);
00563   
00564   btTransform bt1, bt2;
00565   transformMsgToTF2(temp1.transform, bt1);
00566   transformMsgToTF2(temp2.transform, bt2);
00567   transformTF2ToMsg(bt2*bt1, output.transform);
00568   output.header.stamp = temp2.header.stamp;
00569   output.header.frame_id = target_frame;
00570   output.child_frame_id = source_frame;
00571   return output;
00572 }
00573 
00574 
00575 
00576 /*
00577 geometry_msgs::Twist BufferCore::lookupTwist(const std::string& tracking_frame, 
00578                                           const std::string& observation_frame, 
00579                                           const ros::Time& time, 
00580                                           const ros::Duration& averaging_interval) const
00581 {
00582   try
00583   {
00584   geometry_msgs::Twist t;
00585   old_tf_.lookupTwist(tracking_frame, observation_frame, 
00586                       time, averaging_interval, t);
00587   return t;
00588   }
00589   catch (tf::LookupException& ex)
00590   {
00591     throw tf2::LookupException(ex.what());
00592   }
00593   catch (tf::ConnectivityException& ex)
00594   {
00595     throw tf2::ConnectivityException(ex.what());
00596   }
00597   catch (tf::ExtrapolationException& ex)
00598   {
00599     throw tf2::ExtrapolationException(ex.what());
00600   }
00601   catch (tf::InvalidArgument& ex)
00602   {
00603     throw tf2::InvalidArgumentException(ex.what());
00604   }
00605 }
00606 
00607 geometry_msgs::Twist BufferCore::lookupTwist(const std::string& tracking_frame, 
00608                                           const std::string& observation_frame, 
00609                                           const std::string& reference_frame,
00610                                           const tf2::Point & reference_point, 
00611                                           const std::string& reference_point_frame, 
00612                                           const ros::Time& time, 
00613                                           const ros::Duration& averaging_interval) const
00614 {
00615   try{
00616   geometry_msgs::Twist t;
00617   old_tf_.lookupTwist(tracking_frame, observation_frame, reference_frame, reference_point, reference_point_frame,
00618                       time, averaging_interval, t);
00619   return t;
00620   }
00621   catch (tf::LookupException& ex)
00622   {
00623     throw tf2::LookupException(ex.what());
00624   }
00625   catch (tf::ConnectivityException& ex)
00626   {
00627     throw tf2::ConnectivityException(ex.what());
00628   }
00629   catch (tf::ExtrapolationException& ex)
00630   {
00631     throw tf2::ExtrapolationException(ex.what());
00632   }
00633   catch (tf::InvalidArgument& ex)
00634   {
00635     throw tf2::InvalidArgumentException(ex.what());
00636   }
00637 }
00638 */
00639 
00640 struct CanTransformAccum
00641 {
00642   CompactFrameID gather(TimeCacheInterface* cache, ros::Time time, std::string* error_string)
00643   {
00644     return cache->getParent(time, error_string);
00645   }
00646 
00647   void accum(bool source)
00648   {
00649   }
00650 
00651   void finalize(WalkEnding end, ros::Time _time)
00652   {
00653   }
00654 
00655   TransformStorage st;
00656 };
00657 
00658 bool BufferCore::canTransformNoLock(CompactFrameID target_id, CompactFrameID source_id,
00659                     const ros::Time& time, std::string* error_msg) const
00660 {
00661   if (target_id == 0 || source_id == 0)
00662   {
00663     return false;
00664   }
00665 
00666   if (target_id == source_id)
00667   {
00668     return true;
00669   }
00670 
00671   CanTransformAccum accum;
00672   if (walkToTopParent(accum, time, target_id, source_id, error_msg) == tf2_msgs::TF2Error::NO_ERROR)
00673   {
00674     return true;
00675   }
00676 
00677   return false;
00678 }
00679 
00680 bool BufferCore::canTransformInternal(CompactFrameID target_id, CompactFrameID source_id,
00681                                   const ros::Time& time, std::string* error_msg) const
00682 {
00683   boost::mutex::scoped_lock lock(frame_mutex_);
00684   return canTransformNoLock(target_id, source_id, time, error_msg);
00685 }
00686 
00687 bool BufferCore::canTransform(const std::string& target_frame, const std::string& source_frame,
00688                            const ros::Time& time, std::string* error_msg) const
00689 {
00690   if (warnFrameId("canTransform argument target_frame", target_frame))
00691     return false;
00692   if (warnFrameId("canTransform argument source_frame", source_frame))
00693     return false;
00694 
00695   boost::mutex::scoped_lock lock(frame_mutex_);
00696 
00697   CompactFrameID target_id = lookupFrameNumber(target_frame);
00698   CompactFrameID source_id = lookupFrameNumber(source_frame);
00699 
00700   return canTransformNoLock(target_id, source_id, time, error_msg);
00701 }
00702 
00703 bool BufferCore::canTransform(const std::string& target_frame, const ros::Time& target_time,
00704                           const std::string& source_frame, const ros::Time& source_time,
00705                           const std::string& fixed_frame, std::string* error_msg) const
00706 {
00707   if (warnFrameId("canTransform argument target_frame", target_frame))
00708     return false;
00709   if (warnFrameId("canTransform argument source_frame", source_frame))
00710     return false;
00711   if (warnFrameId("canTransform argument fixed_frame", fixed_frame))
00712     return false;
00713 
00714   return canTransform(target_frame, fixed_frame, target_time) && canTransform(fixed_frame, source_frame, source_time, error_msg);
00715 }
00716 
00717 
00718 tf2::TimeCacheInterface* BufferCore::getFrame(CompactFrameID frame_id) const
00719 {
00720   if (frame_id == 0 || frame_id > frames_.size()) 
00721     return NULL;
00722   else
00723   {
00724     return frames_[frame_id];
00725   }
00726 }
00727 
00728 CompactFrameID BufferCore::lookupFrameNumber(const std::string& frameid_str) const
00729 {
00730   CompactFrameID retval;
00731   M_StringToCompactFrameID::const_iterator map_it = frameIDs_.find(frameid_str);
00732   if (map_it == frameIDs_.end())
00733   {
00734     retval = CompactFrameID(0);
00735   }
00736   else
00737     retval = map_it->second;
00738   return retval;
00739 }
00740 
00741 CompactFrameID BufferCore::lookupOrInsertFrameNumber(const std::string& frameid_str)
00742 {
00743   CompactFrameID retval = 0;
00744   M_StringToCompactFrameID::iterator map_it = frameIDs_.find(frameid_str);
00745   if (map_it == frameIDs_.end())
00746   {
00747     retval = CompactFrameID(frames_.size());
00748     frames_.push_back( NULL);//new TimeCache(cache_time_, max_extrapolation_distance_));
00749     frameIDs_[frameid_str] = retval;
00750     frameIDs_reverse.push_back(frameid_str);
00751   }
00752   else
00753     retval = frameIDs_[frameid_str];
00754 
00755   return retval;
00756 }
00757 
00758 const std::string& BufferCore::lookupFrameString(CompactFrameID frame_id_num) const
00759 {
00760     if (frame_id_num >= frameIDs_reverse.size())
00761     {
00762       std::stringstream ss;
00763       ss << "Reverse lookup of frame id " << frame_id_num << " failed!";
00764       throw tf2::LookupException(ss.str());
00765     }
00766     else
00767       return frameIDs_reverse[frame_id_num];
00768 }
00769 
00770 void BufferCore::createConnectivityErrorString(CompactFrameID source_frame, CompactFrameID target_frame, std::string* out) const
00771 {
00772   if (!out)
00773   {
00774     return;
00775   }
00776   *out = std::string("Could not find a connection between '"+lookupFrameString(target_frame)+"' and '"+
00777                      lookupFrameString(source_frame)+"' because they are not part of the same tree."+
00778                      "Tf has two or more unconnected trees.");
00779 }
00780 
00781 std::string BufferCore::allFramesAsString() const
00782 {
00783   boost::mutex::scoped_lock lock(frame_mutex_);
00784   return this->allFramesAsStringNoLock();
00785 }
00786 
00787 std::string BufferCore::allFramesAsStringNoLock() const
00788 {
00789   std::stringstream mstream;
00790 
00791   TransformStorage temp;
00792 
00793   //  for (std::vector< TimeCache*>::iterator  it = frames_.begin(); it != frames_.end(); ++it)
00794 
00796   for (unsigned int counter = 1; counter < frames_.size(); counter ++)
00797   {
00798     TimeCacheInterface* frame_ptr = getFrame(CompactFrameID(counter));
00799     if (frame_ptr == NULL)
00800       continue;
00801     CompactFrameID frame_id_num;
00802     if(  frame_ptr->getData(ros::Time(), temp))
00803       frame_id_num = temp.frame_id_;
00804     else
00805     {
00806       frame_id_num = 0;
00807     }
00808     mstream << "Frame "<< frameIDs_reverse[counter] << " exists with parent " << frameIDs_reverse[frame_id_num] << "." <<std::endl;
00809   }
00810 
00811   return mstream.str();
00812 }
00813 
00814 struct TimeAndFrameIDFrameComparator
00815 {
00816   TimeAndFrameIDFrameComparator(CompactFrameID id)
00817   : id(id)
00818   {}
00819 
00820   bool operator()(const P_TimeAndFrameID& rhs) const
00821   {
00822     return rhs.second == id;
00823   }
00824 
00825   CompactFrameID id;
00826 };
00827 
00828 int BufferCore::getLatestCommonTime(CompactFrameID target_id, CompactFrameID source_id, ros::Time & time, std::string * error_string) const
00829 {
00830   if (source_id == target_id)
00831   {
00832     //Set time to latest timestamp of frameid in case of target and source frame id are the same
00833     time = ros::Time();                 
00834     return tf2_msgs::TF2Error::NO_ERROR;
00835   }
00836 
00837   lct_cache_.clear();
00838 
00839   // Walk the tree to its root from the source frame, accumulating the list of parent/time as well as the latest time
00840   // in the target is a direct parent
00841   CompactFrameID frame = source_id;
00842   P_TimeAndFrameID temp;
00843   uint32_t depth = 0;
00844   ros::Time common_time = ros::TIME_MAX;
00845   while (frame != 0)
00846   {
00847     TimeCacheInterface* cache = getFrame(frame);
00848 
00849     if (!cache)
00850     {
00851       // There will be no cache for the very root of the tree
00852       break;
00853     }
00854 
00855     P_TimeAndFrameID latest = cache->getLatestTimeAndParent();
00856 
00857     if (latest.second == 0)
00858     {
00859       // Just break out here... there may still be a path from source -> target
00860       break;
00861     }
00862 
00863     if (!latest.first.isZero())
00864     {
00865       common_time = std::min(latest.first, common_time);
00866     }
00867 
00868     lct_cache_.push_back(latest);
00869 
00870     frame = latest.second;
00871 
00872     // Early out... target frame is a direct parent of the source frame
00873     if (frame == target_id)
00874     {
00875       time = common_time;
00876       if (time == ros::TIME_MAX)
00877       {
00878         time = ros::Time();
00879       }
00880       return tf2_msgs::TF2Error::NO_ERROR;
00881     }
00882 
00883     ++depth;
00884     if (depth > MAX_GRAPH_DEPTH)
00885     {
00886       if (error_string)
00887       {
00888         std::stringstream ss;
00889         ss<<"The tf tree is invalid because it contains a loop." << std::endl
00890           << allFramesAsString() << std::endl;
00891         *error_string = ss.str();
00892       }
00893       return tf2_msgs::TF2Error::LOOKUP_ERROR;
00894     }
00895   }
00896 
00897   // Now walk to the top parent from the target frame, accumulating the latest time and looking for a common parent
00898   frame = target_id;
00899   depth = 0;
00900   common_time = ros::TIME_MAX;
00901   CompactFrameID common_parent = 0;
00902   while (true)
00903   {
00904     TimeCacheInterface* cache = getFrame(frame);
00905 
00906     if (!cache)
00907     {
00908       break;
00909     }
00910 
00911     P_TimeAndFrameID latest = cache->getLatestTimeAndParent();
00912 
00913     if (latest.second == 0)
00914     {
00915       break;
00916     }
00917 
00918     if (!latest.first.isZero())
00919     {
00920       common_time = std::min(latest.first, common_time);
00921     }
00922 
00923     std::vector<P_TimeAndFrameID>::iterator it = std::find_if(lct_cache_.begin(), lct_cache_.end(), TimeAndFrameIDFrameComparator(latest.second));
00924     if (it != lct_cache_.end()) // found a common parent
00925     {
00926       common_parent = it->second;
00927       break;
00928     }
00929 
00930     frame = latest.second;
00931 
00932     // Early out... source frame is a direct parent of the target frame
00933     if (frame == source_id)
00934     {
00935       time = common_time;
00936       if (time == ros::TIME_MAX)
00937       {
00938         time = ros::Time();
00939       }
00940       return tf2_msgs::TF2Error::NO_ERROR;
00941     }
00942 
00943     ++depth;
00944     if (depth > MAX_GRAPH_DEPTH)
00945     {
00946       if (error_string)
00947       {
00948         std::stringstream ss;
00949         ss<<"The tf tree is invalid because it contains a loop." << std::endl
00950           << allFramesAsString() << std::endl;
00951         *error_string = ss.str();
00952       }
00953       return tf2_msgs::TF2Error::LOOKUP_ERROR;
00954     }
00955   }
00956 
00957   if (common_parent == 0)
00958   {
00959     createConnectivityErrorString(source_id, target_id, error_string);
00960     return tf2_msgs::TF2Error::CONNECTIVITY_ERROR;
00961   }
00962 
00963   // Loop through the source -> root list until we hit the common parent
00964   {
00965     std::vector<P_TimeAndFrameID>::iterator it = lct_cache_.begin();
00966     std::vector<P_TimeAndFrameID>::iterator end = lct_cache_.end();
00967     for (; it != end; ++it)
00968     {
00969       if (!it->first.isZero())
00970       {
00971         common_time = std::min(common_time, it->first);
00972       }
00973 
00974       if (it->second == common_parent)
00975       {
00976         break;
00977       }
00978     }
00979   }
00980 
00981   if (common_time == ros::TIME_MAX)
00982   {
00983     common_time = ros::Time();
00984   }
00985 
00986   time = common_time;
00987   return tf2_msgs::TF2Error::NO_ERROR;
00988 }
00989 
00990 std::string BufferCore::allFramesAsYAML() const
00991 {
00992   std::stringstream mstream;
00993   boost::mutex::scoped_lock lock(frame_mutex_);
00994 
00995   TransformStorage temp;
00996 
00997   if (frames_.size() ==1)
00998     mstream <<"[]";
00999 
01000   mstream.precision(3);
01001   mstream.setf(std::ios::fixed,std::ios::floatfield);
01002     
01003    //  for (std::vector< TimeCache*>::iterator  it = frames_.begin(); it != frames_.end(); ++it)
01004   for (unsigned int counter = 1; counter < frames_.size(); counter ++)//one referenced for 0 is no frame
01005   {
01006     CompactFrameID cfid = CompactFrameID(counter);
01007     CompactFrameID frame_id_num;
01008     TimeCacheInterface* cache = getFrame(cfid);
01009     if (!cache)
01010     {
01011       continue;
01012     }
01013 
01014     if(!cache->getData(ros::Time(), temp))
01015     {
01016       continue;
01017     }
01018 
01019     frame_id_num = temp.frame_id_;
01020 
01021     std::string authority = "no recorded authority";
01022     std::map<CompactFrameID, std::string>::const_iterator it = frame_authority_.find(cfid);
01023     if (it != frame_authority_.end())
01024       authority = it->second;
01025 
01026     double rate = getFrame(cfid)->getListLength() / std::max((getFrame(cfid)->getLatestTimestamp().toSec() -
01027                                                                  getFrame(cfid)->getOldestTimestamp().toSec() ), 0.0001);
01028 
01029     mstream << std::fixed; //fixed point notation
01030     mstream.precision(3); //3 decimal places
01031     mstream << frameIDs_reverse[cfid] << ": " << std::endl;
01032     mstream << "  parent: '" << frameIDs_reverse[frame_id_num] << "'" << std::endl;
01033     mstream << "  broadcaster: '" << authority << "'" << std::endl;
01034     mstream << "  rate: " << rate << std::endl;
01035     mstream << "  most_recent_transform: " << (getFrame(cfid)->getLatestTimestamp()).toSec() << std::endl;
01036     mstream << "  oldest_transform: " << (getFrame(cfid)->getOldestTimestamp()).toSec() << std::endl;
01037     mstream << "  buffer_length: " << (getFrame(cfid)->getLatestTimestamp()-getFrame(cfid)->getOldestTimestamp()).toSec() << std::endl;
01038   }
01039   
01040   return mstream.str();
01041 }
01042 
01043 TransformableCallbackHandle BufferCore::addTransformableCallback(const TransformableCallback& cb)
01044 {
01045   boost::mutex::scoped_lock lock(transformable_callbacks_mutex_);
01046   TransformableCallbackHandle handle = ++transformable_callbacks_counter_;
01047   while (!transformable_callbacks_.insert(std::make_pair(handle, cb)).second)
01048   {
01049     handle = ++transformable_callbacks_counter_;
01050   }
01051 
01052   return handle;
01053 }
01054 
01055 struct BufferCore::RemoveRequestByCallback
01056 {
01057   RemoveRequestByCallback(TransformableCallbackHandle handle)
01058   : handle_(handle)
01059   {}
01060 
01061   bool operator()(const TransformableRequest& req)
01062   {
01063     return req.cb_handle == handle_;
01064   }
01065 
01066   TransformableCallbackHandle handle_;
01067 };
01068 
01069 void BufferCore::removeTransformableCallback(TransformableCallbackHandle handle)
01070 {
01071   {
01072     boost::mutex::scoped_lock lock(transformable_callbacks_mutex_);
01073     transformable_callbacks_.erase(handle);
01074   }
01075 
01076   {
01077     boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01078     V_TransformableRequest::iterator it = std::remove_if(transformable_requests_.begin(), transformable_requests_.end(), RemoveRequestByCallback(handle));
01079     transformable_requests_.erase(it, transformable_requests_.end());
01080   }
01081 }
01082 
01083 TransformableRequestHandle BufferCore::addTransformableRequest(TransformableCallbackHandle handle, const std::string& target_frame, const std::string& source_frame, ros::Time time)
01084 {
01085   // shortcut if target == source
01086   if (target_frame == source_frame)
01087   {
01088     return 0;
01089   }
01090 
01091   TransformableRequest req;
01092   req.target_id = lookupFrameNumber(target_frame);
01093   req.source_id = lookupFrameNumber(source_frame);
01094 
01095   // First check if the request is already transformable.  If it is, return immediately
01096   if (canTransformInternal(req.target_id, req.source_id, time, 0))
01097   {
01098     return 0;
01099   }
01100 
01101   // Might not be transformable at all, ever (if it's too far in the past)
01102   if (req.target_id && req.source_id)
01103   {
01104     ros::Time latest_time;
01105     // TODO: This is incorrect, but better than nothing.  Really we want the latest time for
01106     // any of the frames
01107     getLatestCommonTime(req.target_id, req.source_id, latest_time, 0);
01108     if (!latest_time.isZero() && time + cache_time_ < latest_time)
01109     {
01110       return 0xffffffffffffffffULL;
01111     }
01112   }
01113 
01114   req.cb_handle = handle;
01115   req.time = time;
01116   req.request_handle = ++transformable_requests_counter_;
01117   if (req.request_handle == 0 || req.request_handle == 0xffffffffffffffffULL)
01118   {
01119     req.request_handle = 1;
01120   }
01121 
01122   if (req.target_id == 0)
01123   {
01124     req.target_string = target_frame;
01125   }
01126 
01127   if (req.source_id == 0)
01128   {
01129     req.source_string = source_frame;
01130   }
01131 
01132   boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01133   transformable_requests_.push_back(req);
01134 
01135   return req.request_handle;
01136 }
01137 
01138 struct BufferCore::RemoveRequestByID
01139 {
01140   RemoveRequestByID(TransformableRequestHandle handle)
01141   : handle_(handle)
01142   {}
01143 
01144   bool operator()(const TransformableRequest& req)
01145   {
01146     return req.request_handle == handle_;
01147   }
01148 
01149   TransformableCallbackHandle handle_;
01150 };
01151 
01152 void BufferCore::cancelTransformableRequest(TransformableRequestHandle handle)
01153 {
01154   boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01155   V_TransformableRequest::iterator it = std::remove_if(transformable_requests_.begin(), transformable_requests_.end(), RemoveRequestByID(handle));
01156 
01157   if (it != transformable_requests_.end())
01158   {
01159     transformable_requests_.erase(it, transformable_requests_.end());
01160   }
01161 }
01162 
01163 void BufferCore::testTransformableRequests()
01164 {
01165   boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01166   V_TransformableRequest::iterator it = transformable_requests_.begin();
01167   for (; it != transformable_requests_.end();)
01168   {
01169     TransformableRequest& req = *it;
01170 
01171     // One or both of the frames may not have existed when the request was originally made.
01172     if (req.target_id == 0)
01173     {
01174       req.target_id = lookupFrameNumber(req.target_string);
01175     }
01176 
01177     if (req.source_id == 0)
01178     {
01179       req.source_id = lookupFrameNumber(req.source_string);
01180     }
01181 
01182     ros::Time latest_time;
01183     bool do_cb = false;
01184     TransformableResult result = TransformAvailable;
01185     // TODO: This is incorrect, but better than nothing.  Really we want the latest time for
01186     // any of the frames
01187     getLatestCommonTime(req.target_id, req.source_id, latest_time, 0);
01188     if (!latest_time.isZero() && req.time + cache_time_ < latest_time)
01189     {
01190       do_cb = true;
01191       result = TransformFailure;
01192     }
01193     else if (canTransformInternal(req.target_id, req.source_id, req.time, 0))
01194     {
01195       do_cb = true;
01196       result = TransformAvailable;
01197     }
01198 
01199     if (do_cb)
01200     {
01201       {
01202         boost::mutex::scoped_lock lock2(transformable_callbacks_mutex_);
01203         M_TransformableCallback::iterator it = transformable_callbacks_.find(req.cb_handle);
01204         if (it != transformable_callbacks_.end())
01205         {
01206           const TransformableCallback& cb = it->second;
01207           cb(req.request_handle, lookupFrameString(req.target_id), lookupFrameString(req.source_id), req.time, result);
01208         }
01209       }
01210 
01211       if (transformable_requests_.size() > 1)
01212       {
01213         transformable_requests_[it - transformable_requests_.begin()] = transformable_requests_.back();
01214       }
01215 
01216       transformable_requests_.erase(transformable_requests_.end() - 1);
01217     }
01218     else
01219     {
01220       ++it;
01221     }
01222   }
01223 }
01224 
01225 } // namespace tf2


tf2
Author(s): Tully Foote, Eitan Marder-Eppstein, Wim Meeussen
autogenerated on Mon Oct 6 2014 00:12:43