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 <ros/assert.h>
00038 #include <ros/console.h>
00039 #include "tf2/LinearMath/btTransform.h"
00040
00041
00042
00043
00044
00045 namespace tf2
00046 {
00047
00048
00049
00050
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);
00180 frameIDs_reverse.push_back("NO_PARENT");
00181 }
00182
00183 BufferCore::~BufferCore()
00184 {
00185
00186 }
00187
00188 void BufferCore::clear()
00189 {
00190
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
00209
00210
00211
00212
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
00302 if (source_id == target_id)
00303 {
00304 f.finalize(Identity, time);
00305 return tf2_msgs::TF2Error::NO_ERROR;
00306 }
00307
00308
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
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
00329 top_parent = frame;
00330 break;
00331 }
00332
00333 CompactFrameID parent = f.gather(cache, time, 0);
00334 if (parent == 0)
00335 {
00336
00337 top_parent = frame;
00338 break;
00339 }
00340
00341
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
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
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
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
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);
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
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
00833 time = ros::Time();
00834 return tf2_msgs::TF2Error::NO_ERROR;
00835 }
00836
00837 lct_cache_.clear();
00838
00839
00840
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
00852 break;
00853 }
00854
00855 P_TimeAndFrameID latest = cache->getLatestTimeAndParent();
00856
00857 if (latest.second == 0)
00858 {
00859
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
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
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())
00925 {
00926 common_parent = it->second;
00927 break;
00928 }
00929
00930 frame = latest.second;
00931
00932
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
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
01004 for (unsigned int counter = 1; counter < frames_.size(); counter ++)
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;
01030 mstream.precision(3);
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
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
01096 if (canTransformInternal(req.target_id, req.source_id, time, 0))
01097 {
01098 return 0;
01099 }
01100
01101
01102 if (req.target_id && req.source_id)
01103 {
01104 ros::Time latest_time;
01105
01106
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
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
01186
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 }