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
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 <assert.h>
00038 #include <console_bridge/console.h>
00039 #include "tf2/LinearMath/Transform.h"
00040 #include <boost/foreach.hpp>
00041
00042 namespace tf2
00043 {
00044
00045
00046 static double QUATERNION_NORMALIZATION_TOLERANCE = 10e-3;
00047
00049 void transformMsgToTF2(const geometry_msgs::Transform& msg, tf2::Transform& tf2)
00050 {tf2 = tf2::Transform(tf2::Quaternion(msg.rotation.x, msg.rotation.y, msg.rotation.z, msg.rotation.w), tf2::Vector3(msg.translation.x, msg.translation.y, msg.translation.z));}
00051
00053 void transformTF2ToMsg(const tf2::Transform& tf2, geometry_msgs::Transform& msg)
00054 {
00055 msg.translation.x = tf2.getOrigin().x();
00056 msg.translation.y = tf2.getOrigin().y();
00057 msg.translation.z = tf2.getOrigin().z();
00058 msg.rotation.x = tf2.getRotation().x();
00059 msg.rotation.y = tf2.getRotation().y();
00060 msg.rotation.z = tf2.getRotation().z();
00061 msg.rotation.w = tf2.getRotation().w();
00062 }
00063
00065 void transformTF2ToMsg(const tf2::Transform& tf2, geometry_msgs::TransformStamped& msg, ros::Time stamp, const std::string& frame_id, const std::string& child_frame_id)
00066 {
00067 transformTF2ToMsg(tf2, msg.transform);
00068 msg.header.stamp = stamp;
00069 msg.header.frame_id = frame_id;
00070 msg.child_frame_id = child_frame_id;
00071 }
00072
00073 void transformTF2ToMsg(const tf2::Quaternion& orient, const tf2::Vector3& pos, geometry_msgs::Transform& msg)
00074 {
00075 msg.translation.x = pos.x();
00076 msg.translation.y = pos.y();
00077 msg.translation.z = pos.z();
00078 msg.rotation.x = orient.x();
00079 msg.rotation.y = orient.y();
00080 msg.rotation.z = orient.z();
00081 msg.rotation.w = orient.w();
00082 }
00083
00084 void transformTF2ToMsg(const tf2::Quaternion& orient, const tf2::Vector3& pos, geometry_msgs::TransformStamped& msg, ros::Time stamp, const std::string& frame_id, const std::string& child_frame_id)
00085 {
00086 transformTF2ToMsg(orient, pos, msg.transform);
00087 msg.header.stamp = stamp;
00088 msg.header.frame_id = frame_id;
00089 msg.child_frame_id = child_frame_id;
00090 }
00091
00092 void setIdentity(geometry_msgs::Transform& tx)
00093 {
00094 tx.translation.x = 0;
00095 tx.translation.y = 0;
00096 tx.translation.z = 0;
00097 tx.rotation.x = 0;
00098 tx.rotation.y = 0;
00099 tx.rotation.z = 0;
00100 tx.rotation.w = 1;
00101 }
00102
00103 bool startsWithSlash(const std::string& frame_id)
00104 {
00105 if (frame_id.size() > 0)
00106 if (frame_id[0] == '/')
00107 return true;
00108 return false;
00109 }
00110
00111 std::string stripSlash(const std::string& in)
00112 {
00113 std::string out = in;
00114 if (startsWithSlash(in))
00115 out.erase(0,1);
00116 return out;
00117 }
00118
00119
00120 bool BufferCore::warnFrameId(const char* function_name_arg, const std::string& frame_id) const
00121 {
00122 if (frame_id.size() == 0)
00123 {
00124 std::stringstream ss;
00125 ss << "Invalid argument passed to "<< function_name_arg <<" in tf2 frame_ids cannot be empty";
00126 logWarn("%s",ss.str().c_str());
00127 return true;
00128 }
00129
00130 if (startsWithSlash(frame_id))
00131 {
00132 std::stringstream ss;
00133 ss << "Invalid argument \"" << frame_id << "\" passed to "<< function_name_arg <<" in tf2 frame_ids cannot start with a '/' like: ";
00134 logWarn("%s",ss.str().c_str());
00135 return true;
00136 }
00137
00138 return false;
00139 }
00140
00141 CompactFrameID BufferCore::validateFrameId(const char* function_name_arg, const std::string& frame_id) const
00142 {
00143 if (frame_id.empty())
00144 {
00145 std::stringstream ss;
00146 ss << "Invalid argument passed to "<< function_name_arg <<" in tf2 frame_ids cannot be empty";
00147 throw tf2::InvalidArgumentException(ss.str().c_str());
00148 }
00149
00150 if (startsWithSlash(frame_id))
00151 {
00152 std::stringstream ss;
00153 ss << "Invalid argument \"" << frame_id << "\" passed to "<< function_name_arg <<" in tf2 frame_ids cannot start with a '/' like: ";
00154 throw tf2::InvalidArgumentException(ss.str().c_str());
00155 }
00156
00157 CompactFrameID id = lookupFrameNumber(frame_id);
00158 if (id == 0)
00159 {
00160 std::stringstream ss;
00161 ss << "\"" << frame_id << "\" passed to "<< function_name_arg <<" does not exist. ";
00162 throw tf2::LookupException(ss.str().c_str());
00163 }
00164
00165 return id;
00166 }
00167
00168 BufferCore::BufferCore(ros::Duration cache_time)
00169 : cache_time_(cache_time)
00170 , transformable_callbacks_counter_(0)
00171 , transformable_requests_counter_(0)
00172 , using_dedicated_thread_(false)
00173 {
00174 frameIDs_["NO_PARENT"] = 0;
00175 frames_.push_back(TimeCacheInterfacePtr());
00176 frameIDs_reverse.push_back("NO_PARENT");
00177 }
00178
00179 BufferCore::~BufferCore()
00180 {
00181
00182 }
00183
00184 void BufferCore::clear()
00185 {
00186
00187
00188
00189 boost::mutex::scoped_lock lock(frame_mutex_);
00190 if ( frames_.size() > 1 )
00191 {
00192 for (std::vector<TimeCacheInterfacePtr>::iterator cache_it = frames_.begin() + 1; cache_it != frames_.end(); ++cache_it)
00193 {
00194 if (*cache_it)
00195 (*cache_it)->clearList();
00196 }
00197 }
00198
00199 }
00200
00201 bool BufferCore::setTransform(const geometry_msgs::TransformStamped& transform_in, const std::string& authority, bool is_static)
00202 {
00203
00205
00206
00207
00208
00209
00210
00211
00213 geometry_msgs::TransformStamped stripped = transform_in;
00214 stripped.header.frame_id = stripSlash(stripped.header.frame_id);
00215 stripped.child_frame_id = stripSlash(stripped.child_frame_id);
00216
00217
00218 bool error_exists = false;
00219 if (stripped.child_frame_id == stripped.header.frame_id)
00220 {
00221 logError("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());
00222 error_exists = true;
00223 }
00224
00225 if (stripped.child_frame_id == "")
00226 {
00227 logError("TF_NO_CHILD_FRAME_ID: Ignoring transform from authority \"%s\" because child_frame_id not set ", authority.c_str());
00228 error_exists = true;
00229 }
00230
00231 if (stripped.header.frame_id == "")
00232 {
00233 logError("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());
00234 error_exists = true;
00235 }
00236
00237 if (std::isnan(stripped.transform.translation.x) || std::isnan(stripped.transform.translation.y) || std::isnan(stripped.transform.translation.z)||
00238 std::isnan(stripped.transform.rotation.x) || std::isnan(stripped.transform.rotation.y) || std::isnan(stripped.transform.rotation.z) || std::isnan(stripped.transform.rotation.w))
00239 {
00240 logError("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)",
00241 stripped.child_frame_id.c_str(), authority.c_str(),
00242 stripped.transform.translation.x, stripped.transform.translation.y, stripped.transform.translation.z,
00243 stripped.transform.rotation.x, stripped.transform.rotation.y, stripped.transform.rotation.z, stripped.transform.rotation.w
00244 );
00245 error_exists = true;
00246 }
00247
00248 bool valid = std::abs((stripped.transform.rotation.w * stripped.transform.rotation.w
00249 + stripped.transform.rotation.x * stripped.transform.rotation.x
00250 + stripped.transform.rotation.y * stripped.transform.rotation.y
00251 + stripped.transform.rotation.z * stripped.transform.rotation.z) - 1.0f) < QUATERNION_NORMALIZATION_TOLERANCE;
00252
00253 if (!valid)
00254 {
00255 logError("TF_DENORMALIZED_QUATERNION: Ignoring transform for child_frame_id \"%s\" from authority \"%s\" because of an invalid quaternion in the transform (%f %f %f %f)",
00256 stripped.child_frame_id.c_str(), authority.c_str(),
00257 stripped.transform.rotation.x, stripped.transform.rotation.y, stripped.transform.rotation.z, stripped.transform.rotation.w);
00258 error_exists = true;
00259 }
00260
00261 if (error_exists)
00262 return false;
00263
00264 {
00265 boost::mutex::scoped_lock lock(frame_mutex_);
00266 CompactFrameID frame_number = lookupOrInsertFrameNumber(stripped.child_frame_id);
00267 TimeCacheInterfacePtr frame = getFrame(frame_number);
00268 if (frame == NULL)
00269 frame = allocateFrame(frame_number, is_static);
00270
00271 if (frame->insertData(TransformStorage(stripped, lookupOrInsertFrameNumber(stripped.header.frame_id), frame_number)))
00272 {
00273 frame_authority_[frame_number] = authority;
00274 }
00275 else
00276 {
00277 logWarn("TF_OLD_DATA ignoring data from the past for frame %s at time %g according to authority %s\nPossible reasons are listed at http://wiki.ros.org/tf/Errors%%20explained", stripped.child_frame_id.c_str(), stripped.header.stamp.toSec(), authority.c_str());
00278 return false;
00279 }
00280 }
00281
00282 testTransformableRequests();
00283
00284 return true;
00285 }
00286
00287 TimeCacheInterfacePtr BufferCore::allocateFrame(CompactFrameID cfid, bool is_static)
00288 {
00289 TimeCacheInterfacePtr frame_ptr = frames_[cfid];
00290 if (is_static) {
00291 frames_[cfid] = TimeCacheInterfacePtr(new StaticCache());
00292 } else {
00293 frames_[cfid] = TimeCacheInterfacePtr(new TimeCache(cache_time_));
00294 }
00295
00296 return frames_[cfid];
00297 }
00298
00299 enum WalkEnding
00300 {
00301 Identity,
00302 TargetParentOfSource,
00303 SourceParentOfTarget,
00304 FullPath,
00305 };
00306
00307
00308 template<typename F>
00309 int BufferCore::walkToTopParent(F& f, ros::Time time, CompactFrameID target_id, CompactFrameID source_id, std::string* error_string) const
00310 {
00311 return walkToTopParent(f, time, target_id, source_id, error_string, NULL);
00312 }
00313
00314 template<typename F>
00315 int BufferCore::walkToTopParent(F& f, ros::Time time, CompactFrameID target_id,
00316 CompactFrameID source_id, std::string* error_string, std::vector<CompactFrameID>
00317 *frame_chain) const
00318 {
00319 if (frame_chain)
00320 frame_chain->clear();
00321
00322
00323 if (source_id == target_id)
00324 {
00325 f.finalize(Identity, time);
00326 return tf2_msgs::TF2Error::NO_ERROR;
00327 }
00328
00329
00330 if (time == ros::Time())
00331 {
00332 int retval = getLatestCommonTime(target_id, source_id, time, error_string);
00333 if (retval != tf2_msgs::TF2Error::NO_ERROR)
00334 {
00335 return retval;
00336 }
00337 }
00338
00339
00340 CompactFrameID frame = source_id;
00341 CompactFrameID top_parent = frame;
00342 uint32_t depth = 0;
00343
00344 std::string extrapolation_error_string;
00345 bool extrapolation_might_have_occurred = false;
00346
00347 while (frame != 0)
00348 {
00349 TimeCacheInterfacePtr cache = getFrame(frame);
00350 if (frame_chain)
00351 frame_chain->push_back(frame);
00352
00353 if (!cache)
00354 {
00355
00356 top_parent = frame;
00357 break;
00358 }
00359
00360 CompactFrameID parent = f.gather(cache, time, &extrapolation_error_string);
00361 if (parent == 0)
00362 {
00363
00364 top_parent = frame;
00365 extrapolation_might_have_occurred = true;
00366 break;
00367 }
00368
00369
00370 if (frame == target_id)
00371 {
00372 f.finalize(TargetParentOfSource, time);
00373 return tf2_msgs::TF2Error::NO_ERROR;
00374 }
00375
00376 f.accum(true);
00377
00378 top_parent = frame;
00379 frame = parent;
00380
00381 ++depth;
00382 if (depth > MAX_GRAPH_DEPTH)
00383 {
00384 if (error_string)
00385 {
00386 std::stringstream ss;
00387 ss << "The tf tree is invalid because it contains a loop." << std::endl
00388 << allFramesAsStringNoLock() << std::endl;
00389 *error_string = ss.str();
00390 }
00391 return tf2_msgs::TF2Error::LOOKUP_ERROR;
00392 }
00393 }
00394
00395
00396 frame = target_id;
00397 depth = 0;
00398 std::vector<CompactFrameID> reverse_frame_chain;
00399
00400 while (frame != top_parent)
00401 {
00402 TimeCacheInterfacePtr cache = getFrame(frame);
00403 if (frame_chain)
00404 reverse_frame_chain.push_back(frame);
00405
00406 if (!cache)
00407 {
00408 break;
00409 }
00410
00411 CompactFrameID parent = f.gather(cache, time, error_string);
00412 if (parent == 0)
00413 {
00414 if (error_string)
00415 {
00416 std::stringstream ss;
00417 ss << *error_string << ", when looking up transform from frame [" << lookupFrameString(source_id) << "] to frame [" << lookupFrameString(target_id) << "]";
00418 *error_string = ss.str();
00419 }
00420
00421 return tf2_msgs::TF2Error::EXTRAPOLATION_ERROR;
00422 }
00423
00424
00425 if (frame == source_id)
00426 {
00427 f.finalize(SourceParentOfTarget, time);
00428 if (frame_chain)
00429 {
00430
00431 frame_chain->swap(reverse_frame_chain);
00432
00433 std::reverse(frame_chain->begin(), frame_chain->end());
00434 }
00435 return tf2_msgs::TF2Error::NO_ERROR;
00436 }
00437
00438 f.accum(false);
00439
00440 frame = parent;
00441
00442 ++depth;
00443 if (depth > MAX_GRAPH_DEPTH)
00444 {
00445 if (error_string)
00446 {
00447 std::stringstream ss;
00448 ss << "The tf tree is invalid because it contains a loop." << std::endl
00449 << allFramesAsStringNoLock() << std::endl;
00450 *error_string = ss.str();
00451 }
00452 return tf2_msgs::TF2Error::LOOKUP_ERROR;
00453 }
00454 }
00455
00456 if (frame != top_parent)
00457 {
00458 if (extrapolation_might_have_occurred)
00459 {
00460 if (error_string)
00461 {
00462 std::stringstream ss;
00463 ss << extrapolation_error_string << ", when looking up transform from frame [" << lookupFrameString(source_id) << "] to frame [" << lookupFrameString(target_id) << "]";
00464 *error_string = ss.str();
00465 }
00466
00467 return tf2_msgs::TF2Error::EXTRAPOLATION_ERROR;
00468
00469 }
00470
00471 createConnectivityErrorString(source_id, target_id, error_string);
00472 return tf2_msgs::TF2Error::CONNECTIVITY_ERROR;
00473 }
00474 else if (frame_chain){
00475
00476 reverse_frame_chain.push_back(frame);
00477 }
00478
00479 f.finalize(FullPath, time);
00480 if (frame_chain)
00481 {
00482
00483 int m = reverse_frame_chain.size()-1;
00484 int n = frame_chain->size()-1;
00485 for (; m >= 0 && n >= 0; --m, --n)
00486 {
00487 if ((*frame_chain)[n] != reverse_frame_chain[m])
00488 {
00489 break;
00490 }
00491 }
00492
00493 if (n > 0)
00494 {
00495
00496 frame_chain->erase(frame_chain->begin() + (n + 2), frame_chain->end());
00497 }
00498 if (m < reverse_frame_chain.size())
00499 {
00500 for (int i = m; i >= 0; --i)
00501 {
00502 frame_chain->push_back(reverse_frame_chain[i]);
00503 }
00504 }
00505 }
00506
00507 return tf2_msgs::TF2Error::NO_ERROR;
00508 }
00509
00510
00511
00512 struct TransformAccum
00513 {
00514 TransformAccum()
00515 : source_to_top_quat(0.0, 0.0, 0.0, 1.0)
00516 , source_to_top_vec(0.0, 0.0, 0.0)
00517 , target_to_top_quat(0.0, 0.0, 0.0, 1.0)
00518 , target_to_top_vec(0.0, 0.0, 0.0)
00519 , result_quat(0.0, 0.0, 0.0, 1.0)
00520 , result_vec(0.0, 0.0, 0.0)
00521 {
00522 }
00523
00524 CompactFrameID gather(TimeCacheInterfacePtr cache, ros::Time time, std::string* error_string)
00525 {
00526 if (!cache->getData(time, st, error_string))
00527 {
00528 return 0;
00529 }
00530
00531 return st.frame_id_;
00532 }
00533
00534 void accum(bool source)
00535 {
00536 if (source)
00537 {
00538 source_to_top_vec = quatRotate(st.rotation_, source_to_top_vec) + st.translation_;
00539 source_to_top_quat = st.rotation_ * source_to_top_quat;
00540 }
00541 else
00542 {
00543 target_to_top_vec = quatRotate(st.rotation_, target_to_top_vec) + st.translation_;
00544 target_to_top_quat = st.rotation_ * target_to_top_quat;
00545 }
00546 }
00547
00548 void finalize(WalkEnding end, ros::Time _time)
00549 {
00550 switch (end)
00551 {
00552 case Identity:
00553 break;
00554 case TargetParentOfSource:
00555 result_vec = source_to_top_vec;
00556 result_quat = source_to_top_quat;
00557 break;
00558 case SourceParentOfTarget:
00559 {
00560 tf2::Quaternion inv_target_quat = target_to_top_quat.inverse();
00561 tf2::Vector3 inv_target_vec = quatRotate(inv_target_quat, -target_to_top_vec);
00562 result_vec = inv_target_vec;
00563 result_quat = inv_target_quat;
00564 break;
00565 }
00566 case FullPath:
00567 {
00568 tf2::Quaternion inv_target_quat = target_to_top_quat.inverse();
00569 tf2::Vector3 inv_target_vec = quatRotate(inv_target_quat, -target_to_top_vec);
00570
00571 result_vec = quatRotate(inv_target_quat, source_to_top_vec) + inv_target_vec;
00572 result_quat = inv_target_quat * source_to_top_quat;
00573 }
00574 break;
00575 };
00576
00577 time = _time;
00578 }
00579
00580 TransformStorage st;
00581 ros::Time time;
00582 tf2::Quaternion source_to_top_quat;
00583 tf2::Vector3 source_to_top_vec;
00584 tf2::Quaternion target_to_top_quat;
00585 tf2::Vector3 target_to_top_vec;
00586
00587 tf2::Quaternion result_quat;
00588 tf2::Vector3 result_vec;
00589 };
00590
00591 geometry_msgs::TransformStamped BufferCore::lookupTransform(const std::string& target_frame,
00592 const std::string& source_frame,
00593 const ros::Time& time) const
00594 {
00595 boost::mutex::scoped_lock lock(frame_mutex_);
00596
00597 if (target_frame == source_frame) {
00598 geometry_msgs::TransformStamped identity;
00599 identity.header.frame_id = target_frame;
00600 identity.child_frame_id = source_frame;
00601 identity.transform.rotation.w = 1;
00602
00603 if (time == ros::Time())
00604 {
00605 CompactFrameID target_id = lookupFrameNumber(target_frame);
00606 TimeCacheInterfacePtr cache = getFrame(target_id);
00607 if (cache)
00608 identity.header.stamp = cache->getLatestTimestamp();
00609 else
00610 identity.header.stamp = time;
00611 }
00612 else
00613 identity.header.stamp = time;
00614
00615 return identity;
00616 }
00617
00618
00619 CompactFrameID target_id = validateFrameId("lookupTransform argument target_frame", target_frame);
00620 CompactFrameID source_id = validateFrameId("lookupTransform argument source_frame", source_frame);
00621
00622 std::string error_string;
00623 TransformAccum accum;
00624 int retval = walkToTopParent(accum, time, target_id, source_id, &error_string);
00625 if (retval != tf2_msgs::TF2Error::NO_ERROR)
00626 {
00627 switch (retval)
00628 {
00629 case tf2_msgs::TF2Error::CONNECTIVITY_ERROR:
00630 throw ConnectivityException(error_string);
00631 case tf2_msgs::TF2Error::EXTRAPOLATION_ERROR:
00632 throw ExtrapolationException(error_string);
00633 case tf2_msgs::TF2Error::LOOKUP_ERROR:
00634 throw LookupException(error_string);
00635 default:
00636 logError("Unknown error code: %d", retval);
00637 assert(0);
00638 }
00639 }
00640
00641 geometry_msgs::TransformStamped output_transform;
00642 transformTF2ToMsg(accum.result_quat, accum.result_vec, output_transform, accum.time, target_frame, source_frame);
00643 return output_transform;
00644 }
00645
00646
00647 geometry_msgs::TransformStamped BufferCore::lookupTransform(const std::string& target_frame,
00648 const ros::Time& target_time,
00649 const std::string& source_frame,
00650 const ros::Time& source_time,
00651 const std::string& fixed_frame) const
00652 {
00653 validateFrameId("lookupTransform argument target_frame", target_frame);
00654 validateFrameId("lookupTransform argument source_frame", source_frame);
00655 validateFrameId("lookupTransform argument fixed_frame", fixed_frame);
00656
00657 geometry_msgs::TransformStamped output;
00658 geometry_msgs::TransformStamped temp1 = lookupTransform(fixed_frame, source_frame, source_time);
00659 geometry_msgs::TransformStamped temp2 = lookupTransform(target_frame, fixed_frame, target_time);
00660
00661 tf2::Transform tf1, tf2;
00662 transformMsgToTF2(temp1.transform, tf1);
00663 transformMsgToTF2(temp2.transform, tf2);
00664 transformTF2ToMsg(tf2*tf1, output.transform);
00665 output.header.stamp = temp2.header.stamp;
00666 output.header.frame_id = target_frame;
00667 output.child_frame_id = source_frame;
00668 return output;
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 struct CanTransformAccum
00738 {
00739 CompactFrameID gather(TimeCacheInterfacePtr cache, ros::Time time, std::string* error_string)
00740 {
00741 return cache->getParent(time, error_string);
00742 }
00743
00744 void accum(bool source)
00745 {
00746 }
00747
00748 void finalize(WalkEnding end, ros::Time _time)
00749 {
00750 }
00751
00752 TransformStorage st;
00753 };
00754
00755 bool BufferCore::canTransformNoLock(CompactFrameID target_id, CompactFrameID source_id,
00756 const ros::Time& time, std::string* error_msg) const
00757 {
00758 if (target_id == 0 || source_id == 0)
00759 {
00760 if (error_msg)
00761 {
00762 if (target_id == 0)
00763 {
00764 *error_msg += std::string("target_frame: " + lookupFrameString(target_id ) + " does not exist.");
00765 }
00766 if (source_id == 0)
00767 {
00768 if (target_id == 0)
00769 {
00770 *error_msg += std::string(" ");
00771 }
00772 *error_msg += std::string("source_frame: " + lookupFrameString(source_id) + " " + lookupFrameString(source_id ) + " does not exist.");
00773 }
00774 }
00775 return false;
00776 }
00777
00778 if (target_id == source_id)
00779 {
00780 return true;
00781 }
00782
00783 CanTransformAccum accum;
00784 if (walkToTopParent(accum, time, target_id, source_id, error_msg) == tf2_msgs::TF2Error::NO_ERROR)
00785 {
00786 return true;
00787 }
00788
00789 return false;
00790 }
00791
00792 bool BufferCore::canTransformInternal(CompactFrameID target_id, CompactFrameID source_id,
00793 const ros::Time& time, std::string* error_msg) const
00794 {
00795 boost::mutex::scoped_lock lock(frame_mutex_);
00796 return canTransformNoLock(target_id, source_id, time, error_msg);
00797 }
00798
00799 bool BufferCore::canTransform(const std::string& target_frame, const std::string& source_frame,
00800 const ros::Time& time, std::string* error_msg) const
00801 {
00802
00803 if (target_frame == source_frame)
00804 return true;
00805
00806 if (warnFrameId("canTransform argument target_frame", target_frame))
00807 return false;
00808 if (warnFrameId("canTransform argument source_frame", source_frame))
00809 return false;
00810
00811 boost::mutex::scoped_lock lock(frame_mutex_);
00812
00813 CompactFrameID target_id = lookupFrameNumber(target_frame);
00814 CompactFrameID source_id = lookupFrameNumber(source_frame);
00815
00816 if (target_id == 0 || source_id == 0)
00817 {
00818 if (error_msg)
00819 {
00820 if (target_id == 0)
00821 {
00822 *error_msg += std::string("canTransform: target_frame " + target_frame + " does not exist.");
00823 }
00824 if (source_id == 0)
00825 {
00826 if (target_id == 0)
00827 {
00828 *error_msg += std::string(" ");
00829 }
00830 *error_msg += std::string("canTransform: source_frame " + source_frame + " does not exist.");
00831 }
00832 }
00833 return false;
00834 }
00835 return canTransformNoLock(target_id, source_id, time, error_msg);
00836 }
00837
00838 bool BufferCore::canTransform(const std::string& target_frame, const ros::Time& target_time,
00839 const std::string& source_frame, const ros::Time& source_time,
00840 const std::string& fixed_frame, std::string* error_msg) const
00841 {
00842 if (warnFrameId("canTransform argument target_frame", target_frame))
00843 return false;
00844 if (warnFrameId("canTransform argument source_frame", source_frame))
00845 return false;
00846 if (warnFrameId("canTransform argument fixed_frame", fixed_frame))
00847 return false;
00848
00849 boost::mutex::scoped_lock lock(frame_mutex_);
00850 CompactFrameID target_id = lookupFrameNumber(target_frame);
00851 CompactFrameID source_id = lookupFrameNumber(source_frame);
00852 CompactFrameID fixed_id = lookupFrameNumber(fixed_frame);
00853
00854 if (target_id == 0 || source_id == 0 || fixed_id == 0)
00855 {
00856 if (error_msg)
00857 {
00858 if (target_id == 0)
00859 {
00860 *error_msg += std::string("canTransform: target_frame " + target_frame + " does not exist.");
00861 }
00862 if (source_id == 0)
00863 {
00864 if (target_id == 0)
00865 {
00866 *error_msg += std::string(" ");
00867 }
00868 *error_msg += std::string("canTransform: source_frame " + source_frame + " does not exist.");
00869 }
00870 if (source_id == 0)
00871 {
00872 if (target_id == 0 || source_id == 0)
00873 {
00874 *error_msg += std::string(" ");
00875 }
00876 *error_msg += std::string("fixed_frame: " + fixed_frame + "does not exist.");
00877 }
00878 }
00879 return false;
00880 }
00881 return canTransformNoLock(target_id, fixed_id, target_time, error_msg) && canTransformNoLock(fixed_id, source_id, source_time, error_msg);
00882 }
00883
00884
00885 tf2::TimeCacheInterfacePtr BufferCore::getFrame(CompactFrameID frame_id) const
00886 {
00887 if (frame_id >= frames_.size())
00888 return TimeCacheInterfacePtr();
00889 else
00890 {
00891 return frames_[frame_id];
00892 }
00893 }
00894
00895 CompactFrameID BufferCore::lookupFrameNumber(const std::string& frameid_str) const
00896 {
00897 CompactFrameID retval;
00898 M_StringToCompactFrameID::const_iterator map_it = frameIDs_.find(frameid_str);
00899 if (map_it == frameIDs_.end())
00900 {
00901 retval = CompactFrameID(0);
00902 }
00903 else
00904 retval = map_it->second;
00905 return retval;
00906 }
00907
00908 CompactFrameID BufferCore::lookupOrInsertFrameNumber(const std::string& frameid_str)
00909 {
00910 CompactFrameID retval = 0;
00911 M_StringToCompactFrameID::iterator map_it = frameIDs_.find(frameid_str);
00912 if (map_it == frameIDs_.end())
00913 {
00914 retval = CompactFrameID(frames_.size());
00915 frames_.push_back(TimeCacheInterfacePtr());
00916 frameIDs_[frameid_str] = retval;
00917 frameIDs_reverse.push_back(frameid_str);
00918 }
00919 else
00920 retval = frameIDs_[frameid_str];
00921
00922 return retval;
00923 }
00924
00925 const std::string& BufferCore::lookupFrameString(CompactFrameID frame_id_num) const
00926 {
00927 if (frame_id_num >= frameIDs_reverse.size())
00928 {
00929 std::stringstream ss;
00930 ss << "Reverse lookup of frame id " << frame_id_num << " failed!";
00931 throw tf2::LookupException(ss.str());
00932 }
00933 else
00934 return frameIDs_reverse[frame_id_num];
00935 }
00936
00937 void BufferCore::createConnectivityErrorString(CompactFrameID source_frame, CompactFrameID target_frame, std::string* out) const
00938 {
00939 if (!out)
00940 {
00941 return;
00942 }
00943 *out = std::string("Could not find a connection between '"+lookupFrameString(target_frame)+"' and '"+
00944 lookupFrameString(source_frame)+"' because they are not part of the same tree."+
00945 "Tf has two or more unconnected trees.");
00946 }
00947
00948 std::string BufferCore::allFramesAsString() const
00949 {
00950 boost::mutex::scoped_lock lock(frame_mutex_);
00951 return this->allFramesAsStringNoLock();
00952 }
00953
00954 std::string BufferCore::allFramesAsStringNoLock() const
00955 {
00956 std::stringstream mstream;
00957
00958 TransformStorage temp;
00959
00960
00961
00963 for (unsigned int counter = 1; counter < frames_.size(); counter ++)
00964 {
00965 TimeCacheInterfacePtr frame_ptr = getFrame(CompactFrameID(counter));
00966 if (frame_ptr == NULL)
00967 continue;
00968 CompactFrameID frame_id_num;
00969 if( frame_ptr->getData(ros::Time(), temp))
00970 frame_id_num = temp.frame_id_;
00971 else
00972 {
00973 frame_id_num = 0;
00974 }
00975 mstream << "Frame "<< frameIDs_reverse[counter] << " exists with parent " << frameIDs_reverse[frame_id_num] << "." <<std::endl;
00976 }
00977
00978 return mstream.str();
00979 }
00980
00981 struct TimeAndFrameIDFrameComparator
00982 {
00983 TimeAndFrameIDFrameComparator(CompactFrameID id)
00984 : id(id)
00985 {}
00986
00987 bool operator()(const P_TimeAndFrameID& rhs) const
00988 {
00989 return rhs.second == id;
00990 }
00991
00992 CompactFrameID id;
00993 };
00994
00995 int BufferCore::getLatestCommonTime(CompactFrameID target_id, CompactFrameID source_id, ros::Time & time, std::string * error_string) const
00996 {
00997
00998 if (source_id == 0 || target_id == 0) return tf2_msgs::TF2Error::LOOKUP_ERROR;
00999
01000 if (source_id == target_id)
01001 {
01002 TimeCacheInterfacePtr cache = getFrame(source_id);
01003
01004 if (cache)
01005 time = cache->getLatestTimestamp();
01006 else
01007 time = ros::Time();
01008 return tf2_msgs::TF2Error::NO_ERROR;
01009 }
01010
01011 std::vector<P_TimeAndFrameID> lct_cache;
01012
01013
01014
01015 CompactFrameID frame = source_id;
01016 P_TimeAndFrameID temp;
01017 uint32_t depth = 0;
01018 ros::Time common_time = ros::TIME_MAX;
01019 while (frame != 0)
01020 {
01021 TimeCacheInterfacePtr cache = getFrame(frame);
01022
01023 if (!cache)
01024 {
01025
01026 break;
01027 }
01028
01029 P_TimeAndFrameID latest = cache->getLatestTimeAndParent();
01030
01031 if (latest.second == 0)
01032 {
01033
01034 break;
01035 }
01036
01037 if (!latest.first.isZero())
01038 {
01039 common_time = std::min(latest.first, common_time);
01040 }
01041
01042 lct_cache.push_back(latest);
01043
01044 frame = latest.second;
01045
01046
01047 if (frame == target_id)
01048 {
01049 time = common_time;
01050 if (time == ros::TIME_MAX)
01051 {
01052 time = ros::Time();
01053 }
01054 return tf2_msgs::TF2Error::NO_ERROR;
01055 }
01056
01057 ++depth;
01058 if (depth > MAX_GRAPH_DEPTH)
01059 {
01060 if (error_string)
01061 {
01062 std::stringstream ss;
01063 ss<<"The tf tree is invalid because it contains a loop." << std::endl
01064 << allFramesAsStringNoLock() << std::endl;
01065 *error_string = ss.str();
01066 }
01067 return tf2_msgs::TF2Error::LOOKUP_ERROR;
01068 }
01069 }
01070
01071
01072 frame = target_id;
01073 depth = 0;
01074 common_time = ros::TIME_MAX;
01075 CompactFrameID common_parent = 0;
01076 while (true)
01077 {
01078 TimeCacheInterfacePtr cache = getFrame(frame);
01079
01080 if (!cache)
01081 {
01082 break;
01083 }
01084
01085 P_TimeAndFrameID latest = cache->getLatestTimeAndParent();
01086
01087 if (latest.second == 0)
01088 {
01089 break;
01090 }
01091
01092 if (!latest.first.isZero())
01093 {
01094 common_time = std::min(latest.first, common_time);
01095 }
01096
01097 std::vector<P_TimeAndFrameID>::iterator it = std::find_if(lct_cache.begin(), lct_cache.end(), TimeAndFrameIDFrameComparator(latest.second));
01098 if (it != lct_cache.end())
01099 {
01100 common_parent = it->second;
01101 break;
01102 }
01103
01104 frame = latest.second;
01105
01106
01107 if (frame == source_id)
01108 {
01109 time = common_time;
01110 if (time == ros::TIME_MAX)
01111 {
01112 time = ros::Time();
01113 }
01114 return tf2_msgs::TF2Error::NO_ERROR;
01115 }
01116
01117 ++depth;
01118 if (depth > MAX_GRAPH_DEPTH)
01119 {
01120 if (error_string)
01121 {
01122 std::stringstream ss;
01123 ss<<"The tf tree is invalid because it contains a loop." << std::endl
01124 << allFramesAsStringNoLock() << std::endl;
01125 *error_string = ss.str();
01126 }
01127 return tf2_msgs::TF2Error::LOOKUP_ERROR;
01128 }
01129 }
01130
01131 if (common_parent == 0)
01132 {
01133 createConnectivityErrorString(source_id, target_id, error_string);
01134 return tf2_msgs::TF2Error::CONNECTIVITY_ERROR;
01135 }
01136
01137
01138 {
01139 std::vector<P_TimeAndFrameID>::iterator it = lct_cache.begin();
01140 std::vector<P_TimeAndFrameID>::iterator end = lct_cache.end();
01141 for (; it != end; ++it)
01142 {
01143 if (!it->first.isZero())
01144 {
01145 common_time = std::min(common_time, it->first);
01146 }
01147
01148 if (it->second == common_parent)
01149 {
01150 break;
01151 }
01152 }
01153 }
01154
01155 if (common_time == ros::TIME_MAX)
01156 {
01157 common_time = ros::Time();
01158 }
01159
01160 time = common_time;
01161 return tf2_msgs::TF2Error::NO_ERROR;
01162 }
01163
01164 std::string BufferCore::allFramesAsYAML(double current_time) const
01165 {
01166 std::stringstream mstream;
01167 boost::mutex::scoped_lock lock(frame_mutex_);
01168
01169 TransformStorage temp;
01170
01171 if (frames_.size() ==1)
01172 mstream <<"{}";
01173
01174 mstream.precision(3);
01175 mstream.setf(std::ios::fixed,std::ios::floatfield);
01176
01177
01178 for (unsigned int counter = 1; counter < frames_.size(); counter ++)
01179 {
01180 CompactFrameID cfid = CompactFrameID(counter);
01181 CompactFrameID frame_id_num;
01182 TimeCacheInterfacePtr cache = getFrame(cfid);
01183 if (!cache)
01184 {
01185 continue;
01186 }
01187
01188 if(!cache->getData(ros::Time(), temp))
01189 {
01190 continue;
01191 }
01192
01193 frame_id_num = temp.frame_id_;
01194
01195 std::string authority = "no recorded authority";
01196 std::map<CompactFrameID, std::string>::const_iterator it = frame_authority_.find(cfid);
01197 if (it != frame_authority_.end()) {
01198 authority = it->second;
01199 }
01200
01201 double rate = cache->getListLength() / std::max((cache->getLatestTimestamp().toSec() -
01202 cache->getOldestTimestamp().toSec() ), 0.0001);
01203
01204 mstream << std::fixed;
01205 mstream.precision(3);
01206 mstream << frameIDs_reverse[cfid] << ": " << std::endl;
01207 mstream << " parent: '" << frameIDs_reverse[frame_id_num] << "'" << std::endl;
01208 mstream << " broadcaster: '" << authority << "'" << std::endl;
01209 mstream << " rate: " << rate << std::endl;
01210 mstream << " most_recent_transform: " << (cache->getLatestTimestamp()).toSec() << std::endl;
01211 mstream << " oldest_transform: " << (cache->getOldestTimestamp()).toSec() << std::endl;
01212 if ( current_time > 0 ) {
01213 mstream << " transform_delay: " << current_time - cache->getLatestTimestamp().toSec() << std::endl;
01214 }
01215 mstream << " buffer_length: " << (cache->getLatestTimestamp() - cache->getOldestTimestamp()).toSec() << std::endl;
01216 }
01217
01218 return mstream.str();
01219 }
01220
01221 std::string BufferCore::allFramesAsYAML() const
01222 {
01223 return this->allFramesAsYAML(0.0);
01224 }
01225
01226 TransformableCallbackHandle BufferCore::addTransformableCallback(const TransformableCallback& cb)
01227 {
01228 boost::mutex::scoped_lock lock(transformable_callbacks_mutex_);
01229 TransformableCallbackHandle handle = ++transformable_callbacks_counter_;
01230 while (!transformable_callbacks_.insert(std::make_pair(handle, cb)).second)
01231 {
01232 handle = ++transformable_callbacks_counter_;
01233 }
01234
01235 return handle;
01236 }
01237
01238 struct BufferCore::RemoveRequestByCallback
01239 {
01240 RemoveRequestByCallback(TransformableCallbackHandle handle)
01241 : handle_(handle)
01242 {}
01243
01244 bool operator()(const TransformableRequest& req)
01245 {
01246 return req.cb_handle == handle_;
01247 }
01248
01249 TransformableCallbackHandle handle_;
01250 };
01251
01252 void BufferCore::removeTransformableCallback(TransformableCallbackHandle handle)
01253 {
01254 {
01255 boost::mutex::scoped_lock lock(transformable_callbacks_mutex_);
01256 transformable_callbacks_.erase(handle);
01257 }
01258
01259 {
01260 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01261 V_TransformableRequest::iterator it = std::remove_if(transformable_requests_.begin(), transformable_requests_.end(), RemoveRequestByCallback(handle));
01262 transformable_requests_.erase(it, transformable_requests_.end());
01263 }
01264 }
01265
01266 TransformableRequestHandle BufferCore::addTransformableRequest(TransformableCallbackHandle handle, const std::string& target_frame, const std::string& source_frame, ros::Time time)
01267 {
01268
01269 if (target_frame == source_frame)
01270 {
01271 return 0;
01272 }
01273
01274 TransformableRequest req;
01275 req.target_id = lookupFrameNumber(target_frame);
01276 req.source_id = lookupFrameNumber(source_frame);
01277
01278
01279 if (canTransformInternal(req.target_id, req.source_id, time, 0))
01280 {
01281 return 0;
01282 }
01283
01284
01285 if (req.target_id && req.source_id)
01286 {
01287 ros::Time latest_time;
01288
01289
01290 getLatestCommonTime(req.target_id, req.source_id, latest_time, 0);
01291 if (!latest_time.isZero() && time + cache_time_ < latest_time)
01292 {
01293 return 0xffffffffffffffffULL;
01294 }
01295 }
01296
01297 req.cb_handle = handle;
01298 req.time = time;
01299 req.request_handle = ++transformable_requests_counter_;
01300 if (req.request_handle == 0 || req.request_handle == 0xffffffffffffffffULL)
01301 {
01302 req.request_handle = 1;
01303 }
01304
01305 if (req.target_id == 0)
01306 {
01307 req.target_string = target_frame;
01308 }
01309
01310 if (req.source_id == 0)
01311 {
01312 req.source_string = source_frame;
01313 }
01314
01315 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01316 transformable_requests_.push_back(req);
01317
01318 return req.request_handle;
01319 }
01320
01321 struct BufferCore::RemoveRequestByID
01322 {
01323 RemoveRequestByID(TransformableRequestHandle handle)
01324 : handle_(handle)
01325 {}
01326
01327 bool operator()(const TransformableRequest& req)
01328 {
01329 return req.request_handle == handle_;
01330 }
01331
01332 TransformableCallbackHandle handle_;
01333 };
01334
01335 void BufferCore::cancelTransformableRequest(TransformableRequestHandle handle)
01336 {
01337 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01338 V_TransformableRequest::iterator it = std::remove_if(transformable_requests_.begin(), transformable_requests_.end(), RemoveRequestByID(handle));
01339
01340 if (it != transformable_requests_.end())
01341 {
01342 transformable_requests_.erase(it, transformable_requests_.end());
01343 }
01344 }
01345
01346
01347
01348
01349 boost::signals2::connection BufferCore::_addTransformsChangedListener(boost::function<void(void)> callback)
01350 {
01351 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01352 return _transforms_changed_.connect(callback);
01353 }
01354
01355 void BufferCore::_removeTransformsChangedListener(boost::signals2::connection c)
01356 {
01357 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01358 c.disconnect();
01359 }
01360
01361
01362 bool BufferCore::_frameExists(const std::string& frame_id_str) const
01363 {
01364 boost::mutex::scoped_lock lock(frame_mutex_);
01365 return frameIDs_.count(frame_id_str);
01366 }
01367
01368 bool BufferCore::_getParent(const std::string& frame_id, ros::Time time, std::string& parent) const
01369 {
01370
01371 boost::mutex::scoped_lock lock(frame_mutex_);
01372 CompactFrameID frame_number = lookupFrameNumber(frame_id);
01373 TimeCacheInterfacePtr frame = getFrame(frame_number);
01374
01375 if (! frame)
01376 return false;
01377
01378 CompactFrameID parent_id = frame->getParent(time, NULL);
01379 if (parent_id == 0)
01380 return false;
01381
01382 parent = lookupFrameString(parent_id);
01383 return true;
01384 };
01385
01386 void BufferCore::_getFrameStrings(std::vector<std::string> & vec) const
01387 {
01388 vec.clear();
01389
01390 boost::mutex::scoped_lock lock(frame_mutex_);
01391
01392 TransformStorage temp;
01393
01394
01395 for (unsigned int counter = 1; counter < frameIDs_reverse.size(); counter ++)
01396 {
01397 vec.push_back(frameIDs_reverse[counter]);
01398 }
01399 return;
01400 }
01401
01402
01403
01404
01405 void BufferCore::testTransformableRequests()
01406 {
01407 boost::mutex::scoped_lock lock(transformable_requests_mutex_);
01408 V_TransformableRequest::iterator it = transformable_requests_.begin();
01409
01410 typedef boost::tuple<TransformableCallback&, TransformableRequestHandle, std::string,
01411 std::string, ros::Time&, TransformableResult&> TransformableTuple;
01412 std::vector<TransformableTuple> transformables;
01413
01414 for (; it != transformable_requests_.end();)
01415 {
01416 TransformableRequest& req = *it;
01417
01418
01419 if (req.target_id == 0)
01420 {
01421 req.target_id = lookupFrameNumber(req.target_string);
01422 }
01423
01424 if (req.source_id == 0)
01425 {
01426 req.source_id = lookupFrameNumber(req.source_string);
01427 }
01428
01429 ros::Time latest_time;
01430 bool do_cb = false;
01431 TransformableResult result = TransformAvailable;
01432
01433
01434 getLatestCommonTime(req.target_id, req.source_id, latest_time, 0);
01435 if (!latest_time.isZero() && req.time + cache_time_ < latest_time)
01436 {
01437 do_cb = true;
01438 result = TransformFailure;
01439 }
01440 else if (canTransformInternal(req.target_id, req.source_id, req.time, 0))
01441 {
01442 do_cb = true;
01443 result = TransformAvailable;
01444 }
01445
01446 if (do_cb)
01447 {
01448 {
01449 boost::mutex::scoped_lock lock2(transformable_callbacks_mutex_);
01450 M_TransformableCallback::iterator it = transformable_callbacks_.find(req.cb_handle);
01451 if (it != transformable_callbacks_.end())
01452 {
01453 transformables.push_back(boost::make_tuple(boost::ref(it->second),
01454 req.request_handle,
01455 lookupFrameString(req.target_id),
01456 lookupFrameString(req.source_id),
01457 boost::ref(req.time),
01458 boost::ref(result)));
01459 }
01460 }
01461
01462 if (transformable_requests_.size() > 1)
01463 {
01464 transformable_requests_[it - transformable_requests_.begin()] = transformable_requests_.back();
01465 }
01466
01467 transformable_requests_.erase(transformable_requests_.end() - 1);
01468 }
01469 else
01470 {
01471 ++it;
01472 }
01473 }
01474
01475
01476 lock.unlock();
01477
01478 BOOST_FOREACH (TransformableTuple tt, transformables)
01479 {
01480 tt.get<0>()(tt.get<1>(), tt.get<2>(), tt.get<3>(), tt.get<4>(), tt.get<5>());
01481 }
01482
01483
01484 _transforms_changed_();
01485 }
01486
01487
01488 std::string BufferCore::_allFramesAsDot(double current_time) const
01489 {
01490 std::stringstream mstream;
01491 mstream << "digraph G {" << std::endl;
01492 boost::mutex::scoped_lock lock(frame_mutex_);
01493
01494 TransformStorage temp;
01495
01496 if (frames_.size() == 1) {
01497 mstream <<"\"no tf data recieved\"";
01498 }
01499 mstream.precision(3);
01500 mstream.setf(std::ios::fixed,std::ios::floatfield);
01501
01502 for (unsigned int counter = 1; counter < frames_.size(); counter ++)
01503 {
01504 unsigned int frame_id_num;
01505 TimeCacheInterfacePtr counter_frame = getFrame(counter);
01506 if (!counter_frame) {
01507 continue;
01508 }
01509 if(!counter_frame->getData(ros::Time(), temp)) {
01510 continue;
01511 } else {
01512 frame_id_num = temp.frame_id_;
01513 }
01514 std::string authority = "no recorded authority";
01515 std::map<unsigned int, std::string>::const_iterator it = frame_authority_.find(counter);
01516 if (it != frame_authority_.end())
01517 authority = it->second;
01518
01519 double rate = counter_frame->getListLength() / std::max((counter_frame->getLatestTimestamp().toSec() -
01520 counter_frame->getOldestTimestamp().toSec()), 0.0001);
01521
01522 mstream << std::fixed;
01523 mstream.precision(3);
01524 mstream << "\"" << frameIDs_reverse[frame_id_num] << "\"" << " -> "
01525 << "\"" << frameIDs_reverse[counter] << "\"" << "[label=\""
01526
01527 << "Broadcaster: " << authority << "\\n"
01528 << "Average rate: " << rate << " Hz\\n"
01529 << "Most recent transform: " << (counter_frame->getLatestTimestamp()).toSec() <<" ";
01530 if (current_time > 0)
01531 mstream << "( "<< current_time - counter_frame->getLatestTimestamp().toSec() << " sec old)";
01532 mstream << "\\n"
01533
01534
01535
01536 << "Buffer length: " << (counter_frame->getLatestTimestamp()-counter_frame->getOldestTimestamp()).toSec() << " sec\\n"
01537 <<"\"];" <<std::endl;
01538 }
01539
01540 for (unsigned int counter = 1; counter < frames_.size(); counter ++)
01541 {
01542 unsigned int frame_id_num;
01543 TimeCacheInterfacePtr counter_frame = getFrame(counter);
01544 if (!counter_frame) {
01545 if (current_time > 0) {
01546 mstream << "edge [style=invis];" <<std::endl;
01547 mstream << " subgraph cluster_legend { style=bold; color=black; label =\"view_frames Result\";\n"
01548 << "\"Recorded at time: " << current_time << "\"[ shape=plaintext ] ;\n "
01549 << "}" << "->" << "\"" << frameIDs_reverse[counter] << "\";" << std::endl;
01550 }
01551 continue;
01552 }
01553 if (counter_frame->getData(ros::Time(), temp)) {
01554 frame_id_num = temp.frame_id_;
01555 } else {
01556 frame_id_num = 0;
01557 }
01558
01559 if(frameIDs_reverse[frame_id_num]=="NO_PARENT")
01560 {
01561 mstream << "edge [style=invis];" <<std::endl;
01562 mstream << " subgraph cluster_legend { style=bold; color=black; label =\"view_frames Result\";\n";
01563 if (current_time > 0)
01564 mstream << "\"Recorded at time: " << current_time << "\"[ shape=plaintext ] ;\n ";
01565 mstream << "}" << "->" << "\"" << frameIDs_reverse[counter] << "\";" << std::endl;
01566 }
01567 }
01568 mstream << "}";
01569 return mstream.str();
01570 }
01571
01572 std::string BufferCore::_allFramesAsDot() const
01573 {
01574 return _allFramesAsDot(0.0);
01575 }
01576
01577 void BufferCore::_chainAsVector(const std::string & target_frame, ros::Time target_time, const std::string & source_frame, ros::Time source_time, const std::string& fixed_frame, std::vector<std::string>& output) const
01578 {
01579 std::string error_string;
01580
01581 output.clear();
01582
01583 std::stringstream mstream;
01584 boost::mutex::scoped_lock lock(frame_mutex_);
01585
01586 TransformAccum accum;
01587
01588
01589 CompactFrameID source_id = lookupFrameNumber(source_frame);
01590 CompactFrameID fixed_id = lookupFrameNumber(fixed_frame);
01591 CompactFrameID target_id = lookupFrameNumber(target_frame);
01592
01593 std::vector<CompactFrameID> source_frame_chain;
01594 int retval = walkToTopParent(accum, source_time, fixed_id, source_id, &error_string, &source_frame_chain);
01595
01596 if (retval != tf2_msgs::TF2Error::NO_ERROR)
01597 {
01598 switch (retval)
01599 {
01600 case tf2_msgs::TF2Error::CONNECTIVITY_ERROR:
01601 throw ConnectivityException(error_string);
01602 case tf2_msgs::TF2Error::EXTRAPOLATION_ERROR:
01603 throw ExtrapolationException(error_string);
01604 case tf2_msgs::TF2Error::LOOKUP_ERROR:
01605 throw LookupException(error_string);
01606 default:
01607 logError("Unknown error code: %d", retval);
01608 assert(0);
01609 }
01610 }
01611
01612 std::vector<CompactFrameID> target_frame_chain;
01613 retval = walkToTopParent(accum, target_time, target_id, fixed_id, &error_string, &target_frame_chain);
01614
01615 if (retval != tf2_msgs::TF2Error::NO_ERROR)
01616 {
01617 switch (retval)
01618 {
01619 case tf2_msgs::TF2Error::CONNECTIVITY_ERROR:
01620 throw ConnectivityException(error_string);
01621 case tf2_msgs::TF2Error::EXTRAPOLATION_ERROR:
01622 throw ExtrapolationException(error_string);
01623 case tf2_msgs::TF2Error::LOOKUP_ERROR:
01624 throw LookupException(error_string);
01625 default:
01626 logError("Unknown error code: %d", retval);
01627 assert(0);
01628 }
01629 }
01630
01631 if (source_frame_chain.size() > 0 && target_frame_chain.size() > 0 &&
01632 source_frame_chain.back() == target_frame_chain.front())
01633 {
01634 source_frame_chain.pop_back();
01635 }
01636
01637 for (unsigned int i = 0; i < target_frame_chain.size(); ++i)
01638 {
01639 source_frame_chain.push_back(target_frame_chain[i]);
01640 }
01641
01642
01643
01644 for (unsigned int i = 0; i < source_frame_chain.size(); ++i)
01645 {
01646 output.push_back(lookupFrameString(source_frame_chain[i]));
01647 }
01648 }
01649
01650 int TestBufferCore::_walkToTopParent(BufferCore& buffer, ros::Time time, CompactFrameID target_id, CompactFrameID source_id, std::string* error_string, std::vector<CompactFrameID> *frame_chain) const
01651 {
01652 TransformAccum accum;
01653 return buffer.walkToTopParent(accum, time, target_id, source_id, error_string, frame_chain);
01654 }
01655
01656 }