|Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.|
Learning about tf and time (Python)Description: This tutorial teaches you to use the waitForTransform function to wait for a transform to be available on the tf tree.
Tutorial Level: INTERMEDIATE
Next Tutorial: Time travel with tf (Python)
tf and Time
In the previous tutorials we learned about how tf keeps track of a tree of coordinate frames. This tree changes over time, and tf stores a time snapshot for every transform (for up to 10 seconds by default). Until now we used the lookupTransform() function to get access to the latest available transforms in that tf tree, without knowing at what time that transform was recorded. This tutorial will teach you how to get a transform at a specific time.
Edit nodes/turtle_tf_listener.py and change the lookupTransform() call and except statement to:
So, all of the sudden lookupTransform() is failing, telling you:
Traceback (most recent call last): File "~/ros/pkgs/wg-ros-pkg-trunk/sandbox/learning_tf/nodes/turtle_tf_listener.py", line 25, in <module> (trans,rot) = listener.lookupTransform('/turtle2', '/carrot1', now) tf.ExtrapolationException: Extrapolation Too Far in the future: target_time is 1253830476.460, but the closest tf data is at 1253830476.435 which is 0.024 seconds away.Extrapolation Too Far in the future: target_time is 1253830476.460, but the closest tf data is at 1253830476.459 which is 0.001 seconds away.Extrapolation Too Far from single value: target_time is 1253830476.460, but the closest tf data is at 1253830476.459 which is 0.001 seconds away. See http://pr.willowgarage.com/pr-docs/ros-packages/tf/html/faq.html for more info. When trying to transform between /carrot1 and /turtle2. See http://www.ros.org/wiki/tf#Frequently_Asked_Questions
Or if you're using electric, message might look something like this:
Traceback (most recent call last): File "/home/rosGreat/ROS_tutorial/learning_tf/nodes/turtle_tf_listener.py", line 28, in <module> (trans,rot) = listener.lookupTransform('/turtle2', '/carrot1', now) tf.ExtrapolationException: Lookup would require extrapolation into the future. Requested time 1319591145.491288900 but the latest data is at time 1319591145.490932941, when looking up transform from frame [/carrot1] to frame [/turtle2]
Why is that? Well, each listener has a buffer where it stores all the coordinate transforms coming from the different tf broadcasters. When a broadcaster sends out a transform, it takes some time before that transform gets into the buffer (usually a couple of milliseconds). So, when you request a frame transform at time "now", you should wait a few milliseconds for that information to arrive.
Wait for transforms
tf provides a nice tool that will wait until a transform becomes available. Let's look at what the code would look like:
The waitForTransform() takes four arguments:
- Wait for the transform from this frame...
- ... to this frame,
- at this time, and
- timeout: don't wait for longer than this maximum duration
So waitForTransform() will actually block until the transform between the two turtles becomes available (this will usually take a few milli-seconds), OR --if the transform does not become available-- until the timeout has been reached.
So why the two waitForTransform() calls? At the beginning of code we spawned turtle2 but tf may have not ever seen the /turtle2 frame before waiting for the transform. The first waitForTransform() will wait until the /turtle2 frame is broadcast on tf before trying to waitForTransform() at time now.
Checking the results
Now once again you should be able to simply drive around the first turtle using the arrow keys (make sure your terminal window is active, not your simulator window), and you'll see the second turtle following the first turtle!
So, you noticed there is no noticeable difference in the turtle behavior. That is because the actual timing difference is only a few milliseconds. But then why did we make this change from Time(0) to now()? Just to teach you about the tf buffer and the time delays that are associated with it. For real tf use cases, it is often perfectly fine to use Time(0).