frame_manager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "frame_manager.h"
31 #include "display.h"
32 #include "properties/property.h"
33 
34 #include <ros/ros.h>
37 
38 #include <std_msgs/Float32.h>
39 
40 namespace rviz
41 {
42 FrameManager::FrameManager(std::shared_ptr<tf2_ros::Buffer> tf_buffer,
43  std::shared_ptr<tf2_ros::TransformListener> tf_listener)
44 {
45  assert(!tf_listener || tf_buffer); // tf_listener implies tf_buffer to defined too
46  tf_buffer_ =
47  tf_buffer ? std::move(tf_buffer) : std::make_shared<tf2_ros::Buffer>(ros::Duration(10 * 60));
48  tf_listener_ = tf_listener ?
49  std::move(tf_listener) :
50  std::make_shared<tf2_ros::TransformListener>(*tf_buffer_, ros::NodeHandle(), true);
51 
53  setPause(false);
54 }
55 
57 {
58 }
59 
61 {
62  if (pause_)
63  return;
64  else
65  {
66  boost::mutex::scoped_lock lock(cache_mutex_);
67  cache_.clear();
68  switch (sync_mode_)
69  {
70  case SyncOff: // always use latest time
72  break;
73  case SyncExact: // sync to external source
74  // sync_time_ set via syncTime()
75  break;
76  case SyncApprox:
77  // sync_delta is a sliding average of current_delta_, i.e.
78  // approximating the average delay of incoming sync messages w.r.t. current time
79  sync_delta_ = 0.7 * sync_delta_ + 0.3 * current_delta_;
80  // date back sync_time_ to ensure finding TFs that are as old as now() - sync_delta_
82  break;
83  case SyncFrame: // sync to current time
84  // date back sync_time_ to ensure finding TFs that are as old as now() - sync_delta_
86  break;
87  }
88  }
89 }
90 
91 void FrameManager::setFixedFrame(const std::string& frame)
92 {
93  bool should_emit = false;
94  {
95  boost::mutex::scoped_lock lock(cache_mutex_);
96  if (fixed_frame_ != frame)
97  {
98  fixed_frame_ = frame;
99  cache_.clear();
100  should_emit = true;
101  }
102  }
103  if (should_emit)
104  {
105  // This emission must be kept outside of the mutex lock to avoid deadlocks.
106  Q_EMIT fixedFrameChanged();
107  }
108 }
109 
110 void FrameManager::setPause(bool pause)
111 {
112  pause_ = pause;
113 }
114 
116 {
117  sync_mode_ = mode;
118  sync_time_ = ros::Time(0);
119  sync_delta_ = 0;
120  current_delta_ = 0;
121 }
122 
124 {
125  switch (sync_mode_)
126  {
127  case SyncOff:
128  case SyncFrame:
129  break;
130  case SyncExact:
131  sync_time_ = time;
132  break;
133  case SyncApprox:
134  if (time == ros::Time(0))
135  {
136  current_delta_ = 0;
137  return;
138  }
139  if (ros::Time::now() >= time) // avoid exception due to negative time
140  {
141  // estimate delay of sync message w.r.t. current time
142  current_delta_ = (ros::Time::now() - time).toSec();
143  }
144  else
145  {
147  }
148  break;
149  }
150 }
151 
153 {
154  // we only need to act if we get a zero timestamp, which means "latest"
155  if (time != ros::Time())
156  return;
157 
158  switch (sync_mode_)
159  {
160  case SyncOff:
161  break;
162  case SyncFrame:
163  case SyncExact:
164  case SyncApprox:
165  time = sync_time_;
166  break;
167  }
168 }
169 
170 
171 bool FrameManager::getTransform(const std::string& frame,
172  ros::Time time,
173  Ogre::Vector3& position,
174  Ogre::Quaternion& orientation)
175 {
176  adjustTime(time);
177 
178  boost::mutex::scoped_lock lock(cache_mutex_);
179 
180  position = Ogre::Vector3(9999999, 9999999, 9999999);
181  orientation = Ogre::Quaternion::IDENTITY;
182 
183  if (fixed_frame_.empty())
184  {
185  return false;
186  }
187 
188  M_Cache::iterator it = cache_.find(CacheKey(frame, time));
189  if (it != cache_.end())
190  {
191  position = it->second.position;
192  orientation = it->second.orientation;
193  return true;
194  }
195 
196  geometry_msgs::Pose pose;
197  pose.orientation.w = 1.0f;
198 
199  if (!transform(frame, time, pose, position, orientation))
200  {
201  return false;
202  }
203 
204  cache_.insert(std::make_pair(CacheKey(frame, time), CacheEntry(position, orientation)));
205 
206  return true;
207 }
208 
209 bool FrameManager::transform(const std::string& frame,
210  ros::Time time,
211  const geometry_msgs::Pose& pose_msg,
212  Ogre::Vector3& position,
213  Ogre::Quaternion& orientation)
214 {
215  adjustTime(time);
216 
217  position = Ogre::Vector3::ZERO;
218  orientation = Ogre::Quaternion::IDENTITY;
219 
220  geometry_msgs::Pose pose = pose_msg;
221  if (pose.orientation.x == 0.0 && pose.orientation.y == 0.0 && pose.orientation.z == 0.0 &&
222  pose.orientation.w == 0.0)
223  pose.orientation.w = 1.0;
224 
225  // convert pose into fixed_frame_
226  try
227  {
228  tf2::doTransform(pose, pose, tf_buffer_->lookupTransform(fixed_frame_, frame, time));
229  }
230  catch (const tf2::ExtrapolationException& e)
231  {
232  if (sync_mode_ == SyncApprox)
233  return false;
234  // We don't have tf info for sync_time_. Reset sync_time_ to latest available time of frame
235  auto tf = tf_buffer_->lookupTransform(frame, frame, ros::Time());
236  if (sync_time_ > tf.header.stamp && tf.header.stamp != ros::Time())
237  {
238  sync_delta_ += (sync_time_ - tf.header.stamp).toSec(); // increase sync delta by observed amount
239  sync_time_ = tf.header.stamp;
240  }
241  return false;
242  }
243  catch (const std::runtime_error& e)
244  {
245  ROS_DEBUG("Error transforming from frame '%s' to frame '%s': %s", frame.c_str(),
246  fixed_frame_.c_str(), e.what());
247  return false;
248  }
249 
250  position = Ogre::Vector3(pose.position.x, pose.position.y, pose.position.z);
251  orientation =
252  Ogre::Quaternion(pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
253 
254  return true;
255 }
256 
257 bool FrameManager::frameHasProblems(const std::string& frame, ros::Time /*time*/, std::string& error)
258 {
259  if (!tf_buffer_->_frameExists(frame))
260  {
261  error = "Frame [" + frame + "] does not exist";
262  if (frame == fixed_frame_)
263  {
264  error = "Fixed " + error;
265  }
266  return true;
267  }
268 
269  return false;
270 }
271 
272 bool FrameManager::transformHasProblems(const std::string& frame, ros::Time time, std::string& error)
273 {
274  adjustTime(time);
275 
276  std::string tf_error;
277  bool transform_succeeded = tf_buffer_->canTransform(fixed_frame_, frame, time, &tf_error);
278  if (transform_succeeded)
279  {
280  return false;
281  }
282 
283  bool ok = true;
284  ok = ok && !frameHasProblems(fixed_frame_, time, error);
285  ok = ok && !frameHasProblems(frame, time, error);
286 
287  if (ok)
288  {
289  std::stringstream ss;
290  ss << "No transform to fixed frame [" << fixed_frame_ << "]. TF error: [" << tf_error << "]";
291  error = ss.str();
292  ok = false;
293  }
294 
295  {
296  std::stringstream ss;
297  ss << "For frame [" << frame << "]: " << error;
298  error = ss.str();
299  }
300 
301  return !ok;
302 }
303 
304 std::string getTransformStatusName(const std::string& caller_id)
305 {
306  std::stringstream ss;
307  ss << "Transform [sender=" << caller_id << "]";
308  return ss.str();
309 }
310 
311 std::string FrameManager::discoverFailureReason(const std::string& frame_id,
312  const ros::Time& stamp,
313  const std::string& /*caller_id*/,
315 {
317  {
318  std::stringstream ss;
319  ss << "Message removed because it is too old (frame=[" << frame_id << "], stamp=[" << stamp << "])";
320  return ss.str();
321  }
322  else
323  {
324  std::string error;
325  if (transformHasProblems(frame_id, stamp, error))
326  {
327  return error;
328  }
329  }
330 
331  return "Unknown reason for transform failure (frame=[" + frame_id + "])";
332 }
333 
334 void FrameManager::messageArrived(const std::string& /*frame_id*/,
335  const ros::Time& /*stamp*/,
336  const std::string& caller_id,
337  Display* display)
338 {
339  display->setStatusStd(StatusProperty::Ok, getTransformStatusName(caller_id), "Transform OK");
340 }
341 
342 void FrameManager::messageFailedImpl(const std::string& caller_id,
343  const std::string& status_text,
344  Display* display)
345 {
346  std::string status_name = getTransformStatusName(caller_id);
347 
348  display->setStatusStd(StatusProperty::Error, status_name, status_text);
349 }
350 
351 } // namespace rviz
rviz::FrameManager::FrameManager
FrameManager(std::shared_ptr< tf2_ros::Buffer > tf_buffer=std::shared_ptr< tf2_ros::Buffer >(), std::shared_ptr< tf2_ros::TransformListener > tf_listener=std::shared_ptr< tf2_ros::TransformListener >())
Constructor, will create a TransformListener (and Buffer) automatically if not provided.
Definition: frame_manager.cpp:42
rviz::FrameManager::cache_
M_Cache cache_
Definition: frame_manager.h:305
rviz::FrameManager::messageArrived
void messageArrived(const std::string &frame_id, const ros::Time &stamp, const std::string &caller_id, Display *display)
Definition: frame_manager.cpp:334
frame_manager.h
rviz::FrameManager::cache_mutex_
boost::mutex cache_mutex_
Definition: frame_manager.h:304
rviz::FrameManager::setFixedFrame
void setFixedFrame(const std::string &frame)
Set the frame to consider "fixed", into which incoming data is transformed.
Definition: frame_manager.cpp:91
rviz::StatusProperty::Error
@ Error
Definition: status_property.h:46
rviz::FrameManager::fixedFrameChanged
void fixedFrameChanged()
Emitted whenever the fixed frame changes.
ros.h
property.h
rviz::FrameManager::adjustTime
void adjustTime(ros::Time &time)
Definition: frame_manager.cpp:152
tf2_ros::filter_failure_reasons::FilterFailureReason
FilterFailureReason
rviz::FrameManager::sync_time_
ros::Time sync_time_
Definition: frame_manager.h:316
ok
ROSCPP_DECL bool ok()
rviz::FrameManager::SyncOff
@ SyncOff
Definition: frame_manager.h:70
rviz::FrameManager::sync_mode_
SyncMode sync_mode_
Definition: frame_manager.h:313
rviz::FrameManager::setSyncMode
void setSyncMode(SyncMode mode)
Set synchronization mode (off/exact/approximate)
Definition: frame_manager.cpp:115
rviz::Display
Definition: display.h:63
rviz::FrameManager::current_delta_
double current_delta_
Definition: frame_manager.h:319
rviz::FrameManager::tf_listener_
std::shared_ptr< tf2_ros::TransformListener > tf_listener_
Definition: frame_manager.h:308
ROS_DEBUG
#define ROS_DEBUG(...)
rviz::FrameManager::messageFailedImpl
void messageFailedImpl(const std::string &caller_id, const std::string &status_text, Display *display)
Definition: frame_manager.cpp:342
rviz
Definition: add_display_dialog.cpp:54
tf2::ExtrapolationException
rviz::StatusProperty::Ok
@ Ok
Definition: status_property.h:44
rviz::FrameManager::~FrameManager
~FrameManager() override
Destructor.
Definition: frame_manager.cpp:56
rviz::FrameManager::fixed_frame_
std::string fixed_frame_
Definition: frame_manager.h:309
rviz::FrameManager::frameHasProblems
bool frameHasProblems(const std::string &frame, ros::Time time, std::string &error)
Check to see if a frame exists in our tf buffer.
Definition: frame_manager.cpp:257
rviz::FrameManager::sync_delta_
double sync_delta_
Definition: frame_manager.h:320
tf2_ros::filter_failure_reasons::OutTheBack
OutTheBack
rviz::FrameManager::syncTime
void syncTime(ros::Time time)
Synchronize with given time.
Definition: frame_manager.cpp:123
rviz::FrameManager::CacheEntry
Definition: frame_manager.h:293
rviz::FrameManager::SyncMode
SyncMode
Definition: frame_manager.h:68
rviz::FrameManager::SyncApprox
@ SyncApprox
Definition: frame_manager.h:72
transform_listener.h
rviz::FrameManager::getTransform
bool getTransform(const Header &header, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
Return the pose for a header, relative to the fixed frame, in Ogre classes.
Definition: frame_manager.h:125
display.h
rviz::Display::setStatusStd
void setStatusStd(StatusProperty::Level level, const std::string &name, const std::string &text)
Show status level and text, using a std::string. Convenience function which converts std::string to Q...
Definition: display.h:163
rviz::FrameManager::SyncFrame
@ SyncFrame
Definition: frame_manager.h:73
ros::Time
tf2::doTransform
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
tf_buffer
tf2_ros::Buffer * tf_buffer
rviz::FrameManager::transform
bool transform(const Header &header, const geometry_msgs::Pose &pose, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
Transform a pose from a frame into the fixed frame.
Definition: frame_manager.h:148
tf2_geometry_msgs.h
rviz::FrameManager::update
void update()
Clear the internal cache.
Definition: frame_manager.cpp:60
tf
rviz::getTransformStatusName
std::string getTransformStatusName(const std::string &caller_id)
Definition: frame_manager.cpp:304
ros::Duration
rviz::FrameManager::transformHasProblems
bool transformHasProblems(const std::string &frame, ros::Time time, std::string &error)
Check to see if a transform is known between a given frame and the fixed frame.
Definition: frame_manager.cpp:272
rviz::FrameManager::tf_buffer_
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
Definition: frame_manager.h:307
rviz::FrameManager::setPause
void setPause(bool pause)
Enable/disable pause mode.
Definition: frame_manager.cpp:110
rviz::FrameManager::CacheKey
Definition: frame_manager.h:273
ros::NodeHandle
rviz::FrameManager::discoverFailureReason
std::string discoverFailureReason(const std::string &frame_id, const ros::Time &stamp, const std::string &caller_id, tf2_ros::FilterFailureReason reason)
Definition: frame_manager.cpp:311
rviz::FrameManager::pause_
bool pause_
Definition: frame_manager.h:311
ros::Time::now
static Time now()
rviz::FrameManager::SyncExact
@ SyncExact
Definition: frame_manager.h:71


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust, William Woodall
autogenerated on Thu May 16 2024 02:30:48