From b09faf2ec9246d2decb3369301ea6308be97373e Mon Sep 17 00:00:00 2001 From: Joseph Mirabel <jmirabel@laas.fr> Date: Thu, 16 Jan 2020 17:30:49 +0100 Subject: [PATCH] [TF2] Add a signal that says whether the transform is available. --- src/ros_tf_listener.cpp | 56 +++++++++++++++++++++++++---------------- src/ros_tf_listener.hh | 28 +++++++++++++++------ 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/ros_tf_listener.cpp b/src/ros_tf_listener.cpp index 5511783..e130779 100644 --- a/src/ros_tf_listener.cpp +++ b/src/ros_tf_listener.cpp @@ -5,18 +5,45 @@ namespace dynamicgraph { namespace internal { -sot::MatrixHomogeneous& TransformListenerData::getTransform(sot::MatrixHomogeneous& res, int time) { +sot::MatrixHomogeneous& TransformListenerData::getTransform(sot::MatrixHomogeneous& res, int time) +{ + availableSig.recompute(time); + + bool available = availableSig.accessCopy(); + + if (!available) { + failbackSig.recompute(time); + res = failbackSig.accessCopy(); + return res; + } + + const geometry_msgs::TransformStamped::_transform_type::_rotation_type& + quat = transform.transform.rotation; + const geometry_msgs::TransformStamped::_transform_type::_translation_type& + trans = transform.transform.translation; + res.linear() = sot::Quaternion(quat.w, quat.x, quat.y, quat.z).matrix(); + res.translation() << trans.x, trans.y, trans.z; + return res; +} + +bool& TransformListenerData::isAvailable(bool& available, int time) +{ static const ros::Time origin(0); - bool useFailback = false; + available = false; ros::Duration elapsed; std::string msg; if (buffer.canTransform(toFrame, fromFrame, origin, &msg)) { transform = buffer.lookupTransform(toFrame, fromFrame, origin); - elapsed = ros::Time::now() - transform.header.stamp; - useFailback = elapsed > max_elapsed; + if (transform.header.stamp == origin) { + // This is likely a TF2 static transform. + available = true; + } else { + elapsed = ros::Time::now() - transform.header.stamp; + available = (elapsed <= max_elapsed); + } - if (useFailback) { + if (!available) { std::ostringstream oss; oss << "Use failback " << signal.getName() << " at time " << time << ". Time since last update of the transform: " << elapsed; @@ -27,24 +54,11 @@ sot::MatrixHomogeneous& TransformListenerData::getTransform(sot::MatrixHomogeneo oss << "Unable to get transform " << signal.getName() << " at time " << time << ": " << msg; entity->SEND_WARNING_STREAM_MSG(oss.str()); - useFailback = true; - } - - if (useFailback) - { - failbackSig.recompute(time); - res = failbackSig.accessCopy(); - return res; + available = false; } - - const geometry_msgs::TransformStamped::_transform_type::_rotation_type& - quat = transform.transform.rotation; - const geometry_msgs::TransformStamped::_transform_type::_translation_type& - trans = transform.transform.translation; - res.linear() = sot::Quaternion(quat.w, quat.x, quat.y, quat.z).matrix(); - res.translation() << trans.x, trans.y, trans.z; - return res; + return available; } + } // namespace internal DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(RosTfListener, "RosTfListener"); diff --git a/src/ros_tf_listener.hh b/src/ros_tf_listener.hh index 799a683..85b7e80 100644 --- a/src/ros_tf_listener.hh +++ b/src/ros_tf_listener.hh @@ -18,16 +18,18 @@ class RosTfListener; namespace internal { struct TransformListenerData { - typedef SignalTimeDependent<sot::MatrixHomogeneous, int> signal_t; - typedef SignalPtr<sot::MatrixHomogeneous, int> signalIn_t; + typedef SignalTimeDependent<bool, int> AvailableSignal_t; + typedef SignalTimeDependent<sot::MatrixHomogeneous, int> MatrixSignal_t; + typedef SignalPtr<sot::MatrixHomogeneous, int> DefaultSignal_t; RosTfListener* entity; tf2_ros::Buffer& buffer; const std::string toFrame, fromFrame; geometry_msgs::TransformStamped transform; ros::Duration max_elapsed; - signal_t signal; - signalIn_t failbackSig; + AvailableSignal_t availableSig; + MatrixSignal_t signal; + DefaultSignal_t failbackSig; TransformListenerData(RosTfListener* e, tf2_ros::Buffer& b, const std::string& to, const std::string& from, @@ -37,16 +39,24 @@ struct TransformListenerData { , toFrame(to) , fromFrame(from) , max_elapsed(0.5) + , availableSig(signame+"_available") , signal(signame) , failbackSig(NULL, signame+"_failback") { signal.setFunction( boost::bind(&TransformListenerData::getTransform, this, _1, _2)); + + availableSig.setFunction( + boost::bind(&TransformListenerData::isAvailable, this, _1, _2)); + availableSig.setNeedUpdateFromAllChildren(true); + failbackSig.setConstant (sot::MatrixHomogeneous::Identity()); - signal.addDependency(failbackSig); + signal.addDependencies(failbackSig << availableSig); } sot::MatrixHomogeneous& getTransform(sot::MatrixHomogeneous& res, int time); + + bool& isAvailable(bool& isAvailable, int time); }; } // namespace internal @@ -82,11 +92,13 @@ class RosTfListener : public Entity { addCommand("setMaximumDelay", command::makeCommandVoid2(*this, &RosTfListener::setMaximumDelay, docstring)); } - ~RosTfListener() { + ~RosTfListener() + { for (Map_t::const_iterator _it = listenerDatas.begin(); _it != listenerDatas.end(); ++_it) delete _it->second; } - void add(const std::string& to, const std::string& from, const std::string& signame) { + void add(const std::string& to, const std::string& from, const std::string& signame) + { if (listenerDatas.find(signame) != listenerDatas.end()) throw std::invalid_argument("A signal " + signame + " already exists in RosTfListener " + getName()); @@ -95,7 +107,7 @@ class RosTfListener : public Entity { TransformListenerData* tld = new TransformListenerData(this, buffer, to, from, signalName.str()); - signalRegistration(tld->signal << tld->failbackSig); + signalRegistration(tld->signal << tld->availableSig << tld->failbackSig); listenerDatas[signame] = tld; } -- GitLab