|
| 1 | +.. _TimeTravelWithTf2Py: |
| 2 | + |
| 3 | +Time travel with tf2 (Python) |
| 4 | +============================= |
| 5 | + |
| 6 | +**Goal:** Learn about advanced time travel features of tf2. |
| 7 | + |
| 8 | +**Tutorial level:** Advanced |
| 9 | + |
| 10 | +**Time:** 10 minutes |
| 11 | + |
| 12 | +.. contents:: Contents |
| 13 | + :depth: 2 |
| 14 | + :local: |
| 15 | + |
| 16 | +Background |
| 17 | +---------- |
| 18 | + |
| 19 | +In the previous tutorial, we discussed the :ref:`basics of tf2 and time <LearningAboutTf2AndTimePy>`. |
| 20 | +This tutorial will take us one step further and expose a powerful tf2 trick: the time travel. |
| 21 | +In short, one of the key features of tf2 library is that it is able to transform data in time as well as in space. |
| 22 | + |
| 23 | +This tf2 time travel feature can be useful for various tasks, like monitoring the state of the robot for long period of time or building a follower robot that will follow the "steps" of the leader. |
| 24 | +We will use that time travel feature to look up for the transforms back in time and program the ``turtle1`` follow 5 seconds behind the ``turtle2``. |
| 25 | + |
| 26 | +Time travel |
| 27 | +----------- |
| 28 | + |
| 29 | +First, let's go back to where we ended in the previous tutorial `Learning about tf2 and time <LearningAboutTf2AndTimePy>`. |
| 30 | +Go to your ``learning_tf2_py`` package. |
| 31 | + |
| 32 | +Now, instead of making the second turtle go to where the carrot is now, we will make the second turtle go to where the first carrot was 5 seconds ago. |
| 33 | +Edit the code on lines 75-80 in the ``turtle_tf2_listener.py`` file to: |
| 34 | + |
| 35 | +.. code-block:: python |
| 36 | +
|
| 37 | + when = self.get_clock().now() - rclpy.time.Duration(seconds=5.0) |
| 38 | + trans = self._tf_buffer.lookup_transform( |
| 39 | + to_frame_rel, |
| 40 | + from_frame_rel, |
| 41 | + when, |
| 42 | + timeout=Duration(seconds=1.0)) |
| 43 | +
|
| 44 | +Now if you run this, during the first 5 seconds, the second turtle would not know where to go because we do not yet have a 5-second history of the first turtle. |
| 45 | +But what after these 5 seconds? Let's just give it a try: |
| 46 | + |
| 47 | +.. code-block:: console |
| 48 | +
|
| 49 | + ros2 launch learning_tf2_py turtle_tf2_demo.launch.py |
| 50 | +
|
| 51 | +.. image:: turtlesim_delay1.png |
| 52 | + |
| 53 | +You should now notice that your turtle is driving around uncontrollably like in this screenshot. Let's try to understand reason behind that behavior. |
| 54 | + |
| 55 | +#. In our code we asked tf2 the following question: "What was the pose of ``carrot1`` 5 seconds ago, relative to ``turtle2`` 5 seconds ago?". This means we are controlling the second turtle based on where it was 5 seconds ago as well as where the first turtle was 5 seconds ago. |
| 56 | + |
| 57 | +#. However, what we really want to ask is: "What was the pose of ``carrot1`` 5 seconds ago, relative to the current position of the ``turtle2``?". |
| 58 | + |
| 59 | +Advanced API for lookup_transform |
| 60 | +--------------------------------- |
| 61 | + |
| 62 | +To ask the tf2 that particular question, we will use an advanced API that gives us the power to say explicitly when to acquire the specified transformations. |
| 63 | +This is done by calling the ``lookup_transform_full`` method with additional parameters. |
| 64 | +Your code now would look like this: |
| 65 | + |
| 66 | +.. code-block:: python |
| 67 | +
|
| 68 | + when = self.get_clock().now() - rclpy.time.Duration(seconds=5.0) |
| 69 | + trans = self._tf_buffer.lookup_transform_full( |
| 70 | + target_frame=to_frame_rel,turtle1 |
| 71 | + target_time=rclpy.time.Time(), |
| 72 | + source_frame=from_frame_rel, |
| 73 | + source_time=when, |
| 74 | + fixed_frame='world', |
| 75 | + timeout=Duration(seconds=1.0)) |
| 76 | +
|
| 77 | +The advanced API for ``lookup_transform_full()`` takes six arguments: |
| 78 | + |
| 79 | +#. Target frame |
| 80 | + |
| 81 | +#. The time to transform to |
| 82 | + |
| 83 | +#. Source frame |
| 84 | + |
| 85 | +#. The time at which source frame will be evaluated |
| 86 | + |
| 87 | +#. The time at which we want to transform |
| 88 | + |
| 89 | +#. Frame that does not change over time, in this case the ``world`` frame |
| 90 | + |
| 91 | +#. Time to wait for the target frame to become available |
| 92 | + |
| 93 | +To sum up, tf2 does the following in the background. |
| 94 | +In the past, it computes the transform from the ``carrot1`` to the ``world``. |
| 95 | +In the ``world`` frame, tf2 time travels from the past to now. |
| 96 | +And at the current time, tf2 computes the transform from the ``world`` to the ``turtle2``. |
| 97 | + |
| 98 | +Checking the results |
| 99 | +-------------------- |
| 100 | + |
| 101 | +Let's run the simulation again, this time with the advanced time-travel API: |
| 102 | + |
| 103 | +.. code-block:: console |
| 104 | +
|
| 105 | + ros2 launch learning_tf2_py turtle_tf2_demo.launch.py |
| 106 | +
|
| 107 | +.. image:: turtlesim_delay2.png |
| 108 | + |
| 109 | +And yes, the second turtle is directed to where the first carrot was 5 seconds ago! |
| 110 | + |
| 111 | +Summary |
| 112 | +------- |
| 113 | + |
| 114 | +In this tutorial, you have seen one of the advanced features of tf2. |
| 115 | +You learned that tf2 can transform data in time and learned how to do that with turtlesim example. |
| 116 | +tf2 allowed you to go back in time and make frame transformations between old and current states of turtles by using the advanced ``lookup_transform_full`` API. |
0 commit comments