From bbd382639830d90bfc74033d02f1a374f40e2576 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 16 Sep 2021 10:04:03 +0200 Subject: [PATCH] tf2 tutorials: Consistency fixes in Python and C++ tutorials (#1936) (#1954) * check and update consistency in Writing-A-Tf2-Static-Broadcaster Python and C++ tutorials * check and update consistency in Writing-A-Tf2-Broadcaster Python and C++ tutorials * check and update consistency in Writing-A-Tf2-Listener Python and C++ tutorials and update code snippet to match update in geopmetry_tutorials * check and update consistency in Adding-A-Frame Python and C++ tutorials * check and update consistency in Time-Travel-With-Tf2 Python and C++ tutorials * use lowercase in titles in Introduction-To-Tf2 tutorial * lowercase in title in Tf2-Main * update tutorial time estimation in Adding-A-Frame tutorials * update depend type in package.xml snippet * update title Tf2 introduction * update colon in Time-Travel-With-Tf2 * update text in Writing-A-Tf2-Static-Broadcaster * move all images to folder and update links (cherry picked from commit d2ec42e968ae0f4da35f12fba57a01445e649ecf) Co-authored-by: kurshakuz --- source/Tutorials/Tf2/Adding-A-Frame-Cpp.rst | 10 +- source/Tutorials/Tf2/Adding-A-Frame-Py.rst | 92 ++++++++++++++---- .../Tutorials/Tf2/Debugging-Tf2-Problems.rst | 4 +- source/Tutorials/Tf2/Introduction-To-Tf2.rst | 18 ++-- source/Tutorials/Tf2/Tf2-Main.rst | 12 +-- .../Tf2/Time-Travel-With-Tf2-Cpp.rst | 6 +- .../Tutorials/Tf2/Time-Travel-With-Tf2-Py.rst | 6 +- .../Tf2/Writing-A-Tf2-Broadcaster-Cpp.rst | 5 +- .../Tf2/Writing-A-Tf2-Broadcaster-Py.rst | 56 ++++++----- .../Tf2/Writing-A-Tf2-Listener-Cpp.rst | 14 +-- .../Tf2/Writing-A-Tf2-Listener-Py.rst | 10 +- .../Writing-A-Tf2-Static-Broadcaster-Cpp.rst | 24 +++-- .../Writing-A-Tf2-Static-Broadcaster-Py.rst | 83 +++++++--------- .../Tf2/{ => images}/carrot_dynamic.png | Bin .../Tf2/{ => images}/carrot_static.png | Bin .../Tf2/{ => images}/turtlesim_broadcast.png | Bin .../Tf2/{ => images}/turtlesim_delay1.png | Bin .../Tf2/{ => images}/turtlesim_delay2.png | Bin .../Tf2/{ => images}/turtlesim_follow1.png | Bin .../Tf2/{ => images}/turtlesim_follow2.png | Bin .../Tf2/{ => images}/turtlesim_frames.png | Bin .../{ => images}/turtlesim_frames_carrot.png | Bin .../Tf2/{ => images}/turtlesim_rviz.png | Bin 23 files changed, 195 insertions(+), 145 deletions(-) rename source/Tutorials/Tf2/{ => images}/carrot_dynamic.png (100%) rename source/Tutorials/Tf2/{ => images}/carrot_static.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_broadcast.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_delay1.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_delay2.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_follow1.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_follow2.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_frames.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_frames_carrot.png (100%) rename source/Tutorials/Tf2/{ => images}/turtlesim_rviz.png (100%) diff --git a/source/Tutorials/Tf2/Adding-A-Frame-Cpp.rst b/source/Tutorials/Tf2/Adding-A-Frame-Cpp.rst index 3146e318d5..a2721c7e69 100644 --- a/source/Tutorials/Tf2/Adding-A-Frame-Cpp.rst +++ b/source/Tutorials/Tf2/Adding-A-Frame-Cpp.rst @@ -7,7 +7,7 @@ Adding a frame (C++) **Tutorial level:** Intermediate -**Time:** 10 minutes +**Time:** 15 minutes .. contents:: Contents :depth: 3 @@ -34,7 +34,7 @@ Currently, our tf2 tree contains three frames: ``world``, ``turtle1`` and ``turt The two turtle frames are children of the ``world`` frame. If we want to add a new frame to tf2, one of the three existing frames needs to be the parent frame, and the new one will become its child frame. -.. image:: turtlesim_frames.png +.. image:: images/turtlesim_frames.png Tasks ----- @@ -211,7 +211,7 @@ Rebuild the package and start the turtle broadcaster demo: You should notice that the new ``carrot1`` frame appeared in the transformation tree. -.. image:: turtlesim_frames_carrot.png +.. image:: images/turtlesim_frames_carrot.png 1.4 Checking the results ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -240,7 +240,7 @@ To do so, open the ``turtle_tf2_fixed_frame_demo.launch.py`` file, and add the ` Now just rebuild the package, restart the ``turtle_tf2_fixed_frame_demo.launch.py``, and you'll see the second turtle following the carrot instead of the first turtle! -.. image:: carrot_static.png +.. image:: images/carrot_static.png 2 Write the dynamic frame broadcaster ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ To test this code, create a new launch file ``turtle_tf2_dynamic_frame_demo.laun Rebuild the package, and start the ``turtle_tf2_dynamic_frame_demo.launch.py`` launch file, and now you’ll see that the second turtle is following the carrot's position that is constantly changing. -.. image:: carrot_dynamic.png +.. image:: images/carrot_dynamic.png Summary ------- diff --git a/source/Tutorials/Tf2/Adding-A-Frame-Py.rst b/source/Tutorials/Tf2/Adding-A-Frame-Py.rst index 3f091004a5..bc1675152d 100644 --- a/source/Tutorials/Tf2/Adding-A-Frame-Py.rst +++ b/source/Tutorials/Tf2/Adding-A-Frame-Py.rst @@ -7,7 +7,7 @@ Adding a frame (Python) **Tutorial level:** Intermediate -**Time:** 10 minutes +**Time:** 15 minutes .. contents:: Contents :depth: 3 @@ -17,27 +17,24 @@ Background ---------- In previous tutorials, we recreated the turtle demo by writing a :ref:`tf2 broadcaster ` and a :ref:`tf2 listener `. -This tutorial will teach you how to add an extra frame to the transformation tree. +This tutorial will teach you how to add extra fixed and dynamic frames to the transformation tree. In fact, adding a frame in tf2 is very similar to creating the tf2 broadcaster, but this example will show you some additional features of tf2. -1 Why add frames? -^^^^^^^^^^^^^^^^^ - For many tasks related to transformations, it is easier to think inside a local frame. For example, it is easiest to reason about laser scan measurements in a frame at the center of the laser scanner. tf2 allows you to define a local frame for each sensor, link, or joint in your system. When transforming from one frame to another, tf2 will take care of all the hidden intermediate frame transformations that are introduced. -2 Where to add frames -^^^^^^^^^^^^^^^^^^^^^ +tf2 tree +-------- -tf2 builds up a tree structure of frames, and thus does not allow a closed loop in the frame structure. +tf2 builds up a tree structure of frames and, thus, does not allow a closed loop in the frame structure. This means that a frame only has one single parent, but it can have multiple children. Currently, our tf2 tree contains three frames: ``world``, ``turtle1`` and ``turtle2``. The two turtle frames are children of the ``world`` frame. If we want to add a new frame to tf2, one of the three existing frames needs to be the parent frame, and the new one will become its child frame. -.. image:: turtlesim_frames.png +.. image:: images/turtlesim_frames.png Tasks ----- @@ -49,7 +46,37 @@ In our turtle example, we'll add a new frame ``carrot1``, which will be the chil This frame will serve as the goal for the second turtle. Let's first create the source files. Go to the ``learning_tf2_py`` package we created in the previous tutorials. -Fire up your favorite editor and paste the following code into a new file called ``fixed_frame_tf2_broadcaster.py``. +Download the fixed frame broadcaster code by entering the following command: + +.. tabs:: + + .. group-tab:: Linux + + .. code-block:: console + + wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/fixed_frame_tf2_broadcaster.py + + .. group-tab:: macOS + + .. code-block:: console + + wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/fixed_frame_tf2_broadcaster.py + + .. group-tab:: Windows + + In a Windows command line prompt: + + .. code-block:: console + + curl -sk https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/fixed_frame_tf2_broadcaster.py -o fixed_frame_tf2_broadcaster.py + + Or in powershell: + + .. code-block:: console + + curl https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/fixed_frame_tf2_broadcaster.py -o fixed_frame_tf2_broadcaster.py + +Now open the file called ``fixed_frame_tf2_broadcaster.py``. .. code-block:: python @@ -150,7 +177,7 @@ With your text editor, create a new file called ``turtle_tf2_fixed_frame_demo.la ]) -This launch file first imports the required packages, then creates a ``demo_nodes`` variable that will store nodes that we created in the previous tutorial's launch file. +This launch file imports the required packages and then creates a ``demo_nodes`` variable that will store nodes that we created in the previous tutorial's launch file. The last part of the code will add our fixed ``carrot1`` frame to the turtlesim world using our ``fixed_frame_tf2_broadcaster`` node. @@ -165,7 +192,7 @@ The last part of the code will add our fixed ``carrot1`` frame to the turtlesim 1.3 Build and run ~~~~~~~~~~~~~~~~~ -Rebuild the package, and start the turtle broadcaster demo: +Rebuild the package and start the turtle broadcaster demo: .. code-block:: console @@ -173,13 +200,13 @@ Rebuild the package, and start the turtle broadcaster demo: You should notice that the new ``carrot1`` frame appeared in the transformation tree. -.. image:: turtlesim_frames_carrot.png +.. image:: images/turtlesim_frames_carrot.png 1.4 Checking the results ~~~~~~~~~~~~~~~~~~~~~~~~ If you drive the first turtle around, you should notice that the behavior didn't change from the previous tutorial, even though we added a new frame. -That's because adding an extra frame does not affect the other frames, and our listener is still using the previously defined frames. +That's because adding an extra frame does not affect the other frames and our listener is still using the previously defined frames. Therefore if we want our second turtle to follow the carrot instead of the first turtle, we need to change value of the ``target_frame``. This can be done two ways. @@ -202,7 +229,7 @@ To do so, open the ``turtle_tf2_fixed_frame_demo.launch.py`` file, and add the ` Now just rebuild the package, restart the ``turtle_tf2_fixed_frame_demo.launch.py``, and you'll see the second turtle following the carrot instead of the first turtle! -.. image:: carrot_static.png +.. image:: images/carrot_static.png 2 Write the dynamic frame broadcaster ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,8 +237,37 @@ Now just rebuild the package, restart the ``turtle_tf2_fixed_frame_demo.launch.p The extra frame we published in this tutorial is a fixed frame that doesn't change over time in relation to the parent frame. However, if you want to publish a moving frame you can code the broadcaster to change the frame over time. Let's change our ``carrot1`` frame so that it changes relative to ``turtle1`` frame over time. +Now download the dynamic frame broadcaster code by entering the following command: + +.. tabs:: + + .. group-tab:: Linux + + .. code-block:: console + + wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/dynamic_frame_tf2_broadcaster.py + + .. group-tab:: macOS + + .. code-block:: console + + wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/dynamic_frame_tf2_broadcaster.py + + .. group-tab:: Windows + + In a Windows command line prompt: + + .. code-block:: console + + curl -sk https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/dynamic_frame_tf2_broadcaster.py -o dynamic_frame_tf2_broadcaster.py + + Or in powershell: + + .. code-block:: console + + curl https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/dynamic_frame_tf2_broadcaster.py -o dynamic_frame_tf2_broadcaster.py -Create the file called ``dynamic_frame_tf2_broadcaster.py``: +Now open the file called ``dynamic_frame_tf2_broadcaster.py``: .. code-block:: python @@ -314,10 +370,10 @@ To test this code, create a new launch file ``turtle_tf2_dynamic_frame_demo.laun Rebuild the package, and start the ``turtle_tf2_dynamic_frame_demo.launch.py`` launch file, and now you’ll see that the second turtle is following the carrot's position that is constantly changing. -.. image:: carrot_dynamic.png +.. image:: images/carrot_dynamic.png Summary ------- In this tutorial, you learned about the tf2 transformation tree, its structure, and its features. -You also learned how to add extra fixed and dynamic frames to tf2. +You also learned that it is easiest to think inside a local frame, and learned to add extra fixed and dynamic frames for that local frame. diff --git a/source/Tutorials/Tf2/Debugging-Tf2-Problems.rst b/source/Tutorials/Tf2/Debugging-Tf2-Problems.rst index 1cde5ac168..30675eea2c 100644 --- a/source/Tutorials/Tf2/Debugging-Tf2-Problems.rst +++ b/source/Tutorials/Tf2/Debugging-Tf2-Problems.rst @@ -195,7 +195,7 @@ If you like to get a graphical representation of this, use ``view_frames`` tool. Open the generated ``frames.pdf`` file to see the following output: -.. image:: turtlesim_frames.png +.. image:: images/turtlesim_frames.png So obviously the problem is that we are requesting transform from frame ``turtle3``, which does not exist. To fix this bug, just replace ``turtle3`` with ``turtle2`` in line 67. @@ -265,7 +265,7 @@ Stop the demo, build and run: And you should finally see the turtle move! -.. image:: turtlesim_follow1.png +.. image:: images/turtlesim_follow1.png That last fix we made is not really what you want to do, it was just to make sure that was our problem. The real fix would look like this: diff --git a/source/Tutorials/Tf2/Introduction-To-Tf2.rst b/source/Tutorials/Tf2/Introduction-To-Tf2.rst index b72f30f136..032a1bcb7d 100644 --- a/source/Tutorials/Tf2/Introduction-To-Tf2.rst +++ b/source/Tutorials/Tf2/Introduction-To-Tf2.rst @@ -13,7 +13,7 @@ Introduction to tf2 :depth: 2 :local: -Installing the Demo +Installing the demo ------------------- Let's start by installing the demo package and its dependencies. @@ -39,7 +39,7 @@ Additionally, install a ``transforms3d`` package, which provides the quaternion pip3 install transforms3d -Running the Demo +Running the demo ---------------- Now that we've installed the ``turtle_tf2_py`` tutorial package let's run the demo. @@ -52,7 +52,7 @@ Then run the following command: You will see the turtlesim start with two turtles. -.. image:: turtlesim_follow1.png +.. image:: images/turtlesim_follow1.png In the second terminal window type the following command: @@ -63,17 +63,17 @@ In the second terminal window type the following command: Once the turtlesim is started you can drive the central turtle around in the turtlesim using the keyboard arrow keys, select the second terminal window so that your keystrokes will be captured to drive the turtle. -.. image:: turtlesim_follow2.png +.. image:: images/turtlesim_follow2.png You can see that one turtle continuously moves to follow the turtle you are driving around. -What is Happening ------------------ +What is happening? +------------------ This demo is using the tf2 library to create three coordinate frames: a ``world`` frame, a ``turtle1`` frame, and a ``turtle2`` frame. This tutorial uses a tf2 broadcaster to publish the turtle coordinate frames and a tf2 listener to compute the difference in the turtle frames and move one turtle to follow the other. -tf2 Tools +tf2 tools --------- Now let's look at how tf2 is being used to create this demo. @@ -98,7 +98,7 @@ You will see: Here a tf2 listener is listening to the frames that are being broadcasted over ROS and drawing a tree of how the frames are connected. To view the tree, open the resulting ``frames.pdf`` with your favorite PDF viewer. -.. image:: turtlesim_frames.png +.. image:: images/turtlesim_frames.png Here we can see three frames that are broadcasted by tf2: ``world``, ``turtle1``, and ``turtle2``. The ``world`` here is the parent of the ``turtle1`` and ``turtle2`` frames. @@ -146,6 +146,6 @@ Let's start rviz with the ``turtle_rviz.rviz`` configuration file using the ` ros2 run rviz2 rviz2 -d $(ros2 pkg prefix --share turtle_tf2_py)/rviz/turtle_rviz.rviz -.. image:: turtlesim_rviz.png +.. image:: images/turtlesim_rviz.png In the side bar you will see the frames broadcasted by tf2. As you drive the turtle around you will see the frames move in rviz. diff --git a/source/Tutorials/Tf2/Tf2-Main.rst b/source/Tutorials/Tf2/Tf2-Main.rst index 02b1258b26..45604c1d6b 100644 --- a/source/Tutorials/Tf2/Tf2-Main.rst +++ b/source/Tutorials/Tf2/Tf2-Main.rst @@ -5,8 +5,7 @@ tf2 Tutorials Many of the tf2 tutorials are available for both C++ and Python. The tutorials are streamlined to complete either the C++ track or the Python track. -If you want to learn both C++ and Python, you should go through the tutorials -once for C++ and once for Python. +If you want to learn both C++ and Python, you should go through the tutorials once for C++ and once for Python. .. contents:: Contents :depth: 2 @@ -30,19 +29,18 @@ once for C++ and once for Python. Time-Travel-With-Tf2-Cpp Debugging-Tf2-Problems -Workspace Setup +Workspace setup --------------- -If you have not yet created a workspace in which to complete the tutorials, -:ref:`follow this tutorial `. +If you have not yet created a workspace in which to complete the tutorials, :ref:`follow this tutorial `. Learning tf2 ------------ #. :ref:`Introduction to tf2 `. - This tutorial will give you a good idea of what tf2 can do for you. It - shows off some of the tf2 power in a multi-robot example using turtlesim. + This tutorial will give you a good idea of what tf2 can do for you. + It shows off some of the tf2 power in a multi-robot example using turtlesim. This also introduces using ``tf2_echo``, ``view_frames``, and ``rviz``. #. Writing a tf2 static broadcaster :ref:`(Python) ` :ref:`(C++) `. diff --git a/source/Tutorials/Tf2/Time-Travel-With-Tf2-Cpp.rst b/source/Tutorials/Tf2/Time-Travel-With-Tf2-Cpp.rst index 4e3b6f25f3..9fad92592d 100644 --- a/source/Tutorials/Tf2/Time-Travel-With-Tf2-Cpp.rst +++ b/source/Tutorials/Tf2/Time-Travel-With-Tf2-Cpp.rst @@ -30,7 +30,7 @@ First, let's go back to where we ended in the previous tutorial :ref:`Learning a Go to your ``learning_tf2_cpp`` package. 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. -Edit the ``lookupTransform()`` call in ``turtle_tf2_listener.cpp`` file to: +Edit the ``lookupTransform()`` call in ``turtle_tf2_listener.cpp`` file to .. code-block:: C++ @@ -48,7 +48,7 @@ But what happens after these 5 seconds? Let's just give it a try: ros2 launch learning_tf2_cpp turtle_tf2_fixed_frame_demo.launch.py -.. image:: turtlesim_delay1.png +.. image:: images/turtlesim_delay1.png You should now notice that your turtle is driving around uncontrollably like in this screenshot. Let's try to understand reason behind that behavior. @@ -103,7 +103,7 @@ Let's run the simulation again, this time with the advanced time-travel API: ros2 launch learning_tf2_cpp turtle_tf2_fixed_frame_demo.launch.py -.. image:: turtlesim_delay2.png +.. image:: images/turtlesim_delay2.png And yes, the second turtle is directed to where the first carrot was 5 seconds ago! diff --git a/source/Tutorials/Tf2/Time-Travel-With-Tf2-Py.rst b/source/Tutorials/Tf2/Time-Travel-With-Tf2-Py.rst index f686fde063..64fbbd3c46 100644 --- a/source/Tutorials/Tf2/Time-Travel-With-Tf2-Py.rst +++ b/source/Tutorials/Tf2/Time-Travel-With-Tf2-Py.rst @@ -30,7 +30,7 @@ First, let's go back to where we ended in the previous tutorial :ref:`Learning a Go to your ``learning_tf2_py`` package. 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. -Edit the code with ``lookup_transform()`` call in the ``turtle_tf2_listener.py`` file to: +Edit the ``lookup_transform()`` call in ``turtle_tf2_listener.py`` file to .. code-block:: python @@ -48,7 +48,7 @@ But what happens after these 5 seconds? Let's just give it a try: ros2 launch learning_tf2_py turtle_tf2_fixed_frame_demo.launch.py -.. image:: turtlesim_delay1.png +.. image:: images/turtlesim_delay1.png You should now notice that your turtle is driving around uncontrollably like in this screenshot. Let's try to understand reason behind that behavior. @@ -102,7 +102,7 @@ Let's run the simulation again, this time with the advanced time-travel API: ros2 launch learning_tf2_py turtle_tf2_fixed_frame_demo.launch.py -.. image:: turtlesim_delay2.png +.. image:: images/turtlesim_delay2.png And yes, the second turtle is directed to where the first carrot was 5 seconds ago! diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Cpp.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Cpp.rst index 6803d1a9f2..9044f8c76e 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Cpp.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Cpp.rst @@ -252,7 +252,8 @@ Finally, add the ``install(TARGETS…)`` section so ``ros2 run`` can find your e 2 Write the launch file ^^^^^^^^^^^^^^^^^^^^^^^ -Now create a launch file for this demo. With your text editor, create a new file called ``turtle_tf2_demo.launch.py`` in the ``launch`` folder, and add the following lines: +Now create a launch file for this demo. +With your text editor, create a new file called ``turtle_tf2_demo.launch.py`` in the ``launch`` folder, and add the following lines: .. code-block:: python @@ -375,7 +376,7 @@ In the second terminal window type the following command: You will now see that the turtlesim simulation have started with one turtle that you can control. -.. image:: turtlesim_broadcast.png +.. image:: images/turtlesim_broadcast.png Now, use the ``tf2_echo`` tool to check if the turtle pose is actually getting broadcast to tf2: diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Py.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Py.rst index ade50e64ee..b4cdb11215 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Py.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Broadcaster-Py.rst @@ -17,7 +17,7 @@ Background ---------- In the next two tutorials we will write the code to reproduce the demo from the :ref:`Introduction to tf2 ` tutorial. -After that, the following tutorials focus on extending the demo with more advanced tf2 features. +After that, following tutorials focus on extending the demo with more advanced tf2 features, including the usage of timeouts in transformation lookups and time travel. Prerequisites ------------- @@ -162,7 +162,7 @@ Afterward, the node subscribes to topic ``turtleX/pose`` and runs function ``han self.handle_turtle_pose, 1) -Now, we create a Transform object and give it the appropriate metadata. +Now, we create a ``TransformStamped`` object and give it the appropriate metadata. #. We need to give the transform being published a timestamp, and we'll just stamp it with the current time by calling ``self.get_clock().now()``. This will return the current time used by the ``Node``. @@ -174,6 +174,10 @@ The handler function for the turtle pose message broadcasts this turtle's transl .. code-block:: python + t = TransformStamped() + + # Read message content and assign it to + # corresponding tf variables t.header.stamp = self.get_clock().now().to_msg() t.header.frame_id = 'world' t.child_frame_id = self.turtlename @@ -210,30 +214,13 @@ Finally we take the transform that we constructed and pass it to the ``sendTrans The static transforms will be published on the ``/tf_static`` topic and will be sent only when required, not periodically. For more details see :ref:`here `. -1.2 Add dependencies -~~~~~~~~~~~~~~~~~~~~ - -Navigate one level back to the ``src/learning_tf2_py`` directory, where the ``setup.py``, ``setup.cfg``, and ``package.xml`` files are located. - -Open ``package.xml`` with your text editor. -Add the following dependencies corresponding to your node's import statements: - -.. code-block:: xml - - launch - launch_ros - -This declares the additional required ``launch`` and ``launch_ros`` dependencies when its code is executed. - -Make sure to save the file. - -1.3 Add an entry point +1.2 Add an entry point ~~~~~~~~~~~~~~~~~~~~~~ To allow the ``ros2 run`` command to run your node, you must add the entry point to ``setup.py`` (located in the ``src/learning_tf2_py`` directory). -Add the following line between the ``'console_scripts':`` brackets: +Finally, add the following line between the ``'console_scripts':`` brackets: .. code-block:: python @@ -244,8 +231,8 @@ Add the following line between the ``'console_scripts':`` brackets: 2 Write the launch file ^^^^^^^^^^^^^^^^^^^^^^^ -Now create a launch file for this demo. With your text editor, create a new -file called ``turtle_tf2_demo.launch.py``, and add the following lines: +Now create a launch file for this demo. +With your text editor, create a new file called ``turtle_tf2_demo.launch.py`` in the ``launch`` folder, and add the following lines: .. code-block:: python @@ -299,7 +286,24 @@ Now we run our nodes that start the turtlesim simulation and broadcast ``turtle1 ] ), -2.2 Update setup.py +2.2 Add dependencies +~~~~~~~~~~~~~~~~~~~~ + +Navigate one level back to the ``src/learning_tf2_py`` directory, where the ``setup.py``, ``setup.cfg``, and ``package.xml`` files are located. + +Open ``package.xml`` with your text editor. +Add the following dependencies corresponding to your launch file's import statements: + +.. code-block:: xml + + launch + launch_ros + +This declares the additional required ``launch`` and ``launch_ros`` dependencies when its code is executed. + +Make sure to save the file. + +2.3 Update setup.py ~~~~~~~~~~~~~~~~~~~ Reopen ``setup.py`` and add the line so that the launch files from the ``launch/`` folder would be installed. @@ -351,7 +355,7 @@ In the second terminal window type the following command: You will now see that the turtlesim simulation have started with one turtle that you can control. -.. image:: turtlesim_broadcast.png +.. image:: images/turtlesim_broadcast.png Now, use the ``tf2_echo`` tool to check if the turtle pose is actually getting broadcast to tf2: @@ -384,5 +388,5 @@ However, as soon as we add the second turtle in the next tutorial, the pose of ` Summary ------- -In this tutorial you learned how to broadast state of the robot to tf2 and how to use the ``tf2_echo`` tool. +In this tutorial you learned how to broadcast the pose of the robot (position and orientation of the turtle) to tf2 and how to use the ``tf2_echo`` tool. To actually use the transforms broadcasted to tf2, you should move on to the next tutorial about creating a :ref:`tf2 listener `. diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Cpp.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Cpp.rst index 7d29d3ee7c..f7afd5f9df 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Cpp.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Cpp.rst @@ -24,7 +24,7 @@ Prerequisites ------------- This tutorial assumes you have completed the :ref:`tf2 broadcaster tutorial (C++) `. -In previous tutorial, we created a ``learning_tf2_cpp`` package, which is where we will continue working from. +In the previous tutorial, we created a ``learning_tf2_cpp`` package, which is where we will continue working from. Tasks ----- @@ -152,7 +152,7 @@ Open the file using your preferred text editor. publisher_->publish(msg); } else { - RCLCPP_INFO(this->get_logger(), "Successfully spawned %s", result_.get()->name.c_str()); + RCLCPP_INFO(this->get_logger(), "Successfully spawned"); turtle_spawned_ = true; } } else { @@ -177,7 +177,7 @@ Open the file using your preferred text editor. RCLCPP_ERROR(this->get_logger(), "Service callback result mismatch"); } }; - result_ = spawner_->async_send_request(request, response_received_callback); + auto result = spawner_->async_send_request(request, response_received_callback); } else { RCLCPP_INFO(this->get_logger(), "Service is not ready"); } @@ -188,7 +188,6 @@ Open the file using your preferred text editor. bool turtle_spawning_service_ready_; // if the turtle was successfully spawned bool turtle_spawned_; - rclcpp::Client::SharedFuture result_; rclcpp::Client::SharedPtr spawner_{nullptr}; rclcpp::TimerBase::SharedPtr timer_{nullptr}; rclcpp::Publisher::SharedPtr publisher_{nullptr}; @@ -232,8 +231,8 @@ Finally, we query the listener for a specific transformation. We call ``lookup_t #. The time at which we want to transform -Providing ``tf2::TimePoint()`` will just get us the latest available transform. -All this is wrapped in a try-except block to catch possible exceptions. +Providing ``tf2::TimePointZero()`` will just get us the latest available transform. +All this is wrapped in a try-catch block to handle possible exceptions. .. code-block:: C++ @@ -244,7 +243,8 @@ All this is wrapped in a try-except block to catch possible exceptions. 2 Build and run ^^^^^^^^^^^^^^^ -With your text editor, open the launch file called ``turtle_tf2_demo.launch.py``, and add the following lines after your first ``turtle1`` broadcaster node: +With your text editor, open the launch file called ``turtle_tf2_demo.launch.py``, and add the following lines after your first ``turtle1`` broadcaster node. +Additionally, include the imports of ``DeclareLaunchArgument`` and ``LaunchConfiguration`` in the beginning of the file: .. code-block:: python diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Py.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Py.rst index c431db3d28..17a1834a2b 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Py.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Listener-Py.rst @@ -23,7 +23,7 @@ In this tutorial we'll create a tf2 listener to start using tf2. Prerequisites ------------- -This tutorial assumes you have completed the writing a :ref:`tf2 broadcaster tutorial (Python) `. +This tutorial assumes you have completed the :ref:`tf2 broadcaster tutorial (Python) `. In the previous tutorial, we created a ``learning_tf2_py`` package, which is where we will continue working from. Tasks @@ -202,7 +202,7 @@ Finally, we query the listener for a specific transformation. We call ``lookup_t #. The time at which we want to transform Providing ``rclpy.time.Time()`` will just get us the latest available transform. -All this is wrapped in a try-except block to catch possible exceptions. +All this is wrapped in a try-except block to handle possible exceptions. .. code-block:: python @@ -215,13 +215,15 @@ All this is wrapped in a try-except block to catch possible exceptions. 2 Build and run ^^^^^^^^^^^^^^^ -With your text editor, open the launch file called ``turtle_tf2_demo.launch.py`` and add the following lines after your first ``turtle1`` broadcaster node. Additionally, include the imports of ``DeclareLaunchArgument`` and ``LaunchConfiguration`` in the beginning of the file: +With your text editor, open the launch file called ``turtle_tf2_demo.launch.py``, and add the following lines after your first ``turtle1`` broadcaster node. +Additionally, include the imports of ``DeclareLaunchArgument`` and ``LaunchConfiguration`` in the beginning of the file: .. code-block:: python from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration + from launch_ros.actions import Node def generate_launch_description(): @@ -272,4 +274,4 @@ Summary ------- In this tutorial you learned how to use tf2 to get access to frame transformations. -You also have finished writing your own turtlesim demo that you have tried in the :ref:`Introduction to tf2 ` tutorial. +You also have finished writing your own turtlesim demo that you first tried in :ref:`Introduction to tf2 ` tutorial. diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Cpp.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Cpp.rst index fe8c086be4..a8845f7514 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Cpp.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Cpp.rst @@ -113,7 +113,7 @@ Open the file using your preferred text editor. private: void make_transforms(char * transformation[]) { - rclcpp::Time now; + rclcpp::Time now = this->get_clock()->now(); geometry_msgs::msg::TransformStamped t; t.header.stamp = now; @@ -170,7 +170,7 @@ Open the file using your preferred text editor. Now let's look at the code that is relevant to publishing the static turtle pose to tf2. The first lines include the required header files. -We include ``geometry_msgs/msg/transform_stamped.hpp`` to access the ``TransformStamped`` message type, which we will publish to the transformation tree. +First we include ``geometry_msgs/msg/transform_stamped.hpp`` to access the ``TransformStamped`` message type, which we will publish to the transformation tree. .. code-block:: C++ @@ -191,7 +191,7 @@ We also include ``tf2_ros/static_transform_broadcaster.h`` to use the ``StaticTr #include The ``StaticFramePublisher`` class constructor initializes the node with the name ``static_turtle_tf2_broadcaster``. -Then, ``StaticTransformBroadcaster`` is created that will send one static transformation upon the startup. +Then, ``StaticTransformBroadcaster`` is created, which will send one static transformation upon the startup. .. code-block:: C++ @@ -199,10 +199,10 @@ Then, ``StaticTransformBroadcaster`` is created that will send one static transf this->make_transforms(transformation); -Here we create a ``TransformStamped`` object which will be the message we will send over once populated. +Here we create a ``TransformStamped`` object, which will be the message we will send over once populated. Before passing the actual transform values we need to give it the appropriate metadata. -#. We need to give the transform being published a timestamp and we'll just stamp it with the current time, ``rclcpp::Time`` +#. We need to give the transform being published a timestamp and we'll just stamp it with the current time, ``this->get_clock()->now()`` #. Then we need to set the name of the parent frame of the link we're creating, in this case ``world`` @@ -210,7 +210,7 @@ Before passing the actual transform values we need to give it the appropriate me .. code-block:: C++ - rclcpp::Time now; + rclcpp::Time now = this->get_clock()->now(); geometry_msgs::msg::TransformStamped t; t.header.stamp = now; @@ -251,7 +251,7 @@ As mentioned in the :ref:`Creating your first ROS 2 package tutorial .. code-block:: xml - Examples of static transform broadcaster using rclcpp + Learning tf2 with rclcpp Your Name Apache License 2.0 @@ -307,8 +307,7 @@ Finally, add the ``install(TARGETS…)`` section so ``ros2 run`` can find your e 3 Build and run ^^^^^^^^^^^^^^^ -It's good practice to run ``rosdep`` in the root of your workspace to -check for missing dependencies before building: +It's good practice to run ``rosdep`` in the root of your workspace to check for missing dependencies before building: .. tabs:: @@ -417,8 +416,8 @@ This tutorial aimed to show how ``StaticTransformBroadcaster`` can be used to pu In your real development process you shouldn't have to write this code yourself and should use the dedicated ``tf2_ros`` tool to do so. ``tf2_ros`` provides an executable named ``static_transform_publisher`` that can be used either as a commandline tool or a node that you can add to your launchfiles. -Publish a static coordinate transform to tf2 using an x/y/z offset in meters and yaw/pitch/roll in radians. -(yaw is rotation about Z, pitch is rotation about Y, and roll is rotation about X). +Publish a static coordinate transform to tf2 using an x/y/z offset in meters and roll/pitch/yaw in radians. +In our case, roll/pitch/yaw refers to rotation about the x/y/z-axis, respectively. .. code-block:: console @@ -430,8 +429,7 @@ Publish a static coordinate transform to tf2 using an x/y/z offset in meters and ros2 run tf2_ros static_transform_publisher x y z qx qy qz qw frame_id child_frame_id -``static_transform_publisher`` is designed both as a command-line tool for manual use, as well as -for use within ``launch`` files for setting static transforms. For example: +``static_transform_publisher`` is designed both as a command-line tool for manual use, as well as for use within ``launch`` files for setting static transforms. For example: .. code-block:: console diff --git a/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst b/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst index fecf8809e8..fc2a9da045 100644 --- a/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst +++ b/source/Tutorials/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst @@ -16,18 +16,20 @@ Writing a tf2 static broadcaster (Python) Background ---------- -In this tutorial we will write code to publish static transforms to tf2. -This is a standalone tutorial covering the basics of static transforms. +Publishing static transforms is useful to define the relationship between a robot base and its sensors or non-moving parts. +For example, it is easiest to reason about laser scan measurements in a frame at the center of the laser scanner. -In the next two tutorials we will write the code to reproduce the demo -from the :ref:`Introduction to tf2 ` tutorial. After that, -the following tutorials focus on extending the demo with more advanced tf2 features. +This is a standalone tutorial covering the basics of static transforms, which consists of two parts. +In the first part we will write code to publish static transforms to tf2. +In the second part we will explain how to use the commandline ``static_transform_publisher`` executable tool in ``tf2_ros``. + +In the next two tutorials we will write the code to reproduce the demo from the :ref:`Introduction to tf2 ` tutorial. +After that, the following tutorials focus on extending the demo with more advanced tf2 features. Prerequisites ------------- -In previous tutorials, you learned how to :ref:`create a workspace ` -and :ref:`create a package `. +In previous tutorials, you learned how to :ref:`create a workspace ` and :ref:`create a package `. Tasks ----- @@ -35,10 +37,9 @@ Tasks 1 Create a package ^^^^^^^^^^^^^^^^^^ -First we will create a package that will be used for this tutorial -and the following ones. The package called ``learning_tf2_py`` will depend on -``rclpy``, ``tf2_ros``, ``geometry_msgs``, and ``turtlesim``. Code for this tutorial is stored -`here `_. +First we will create a package that will be used for this tutorial and the following ones. +The package called ``learning_tf2_py`` will depend on ``rclpy``, ``tf2_ros``, ``geometry_msgs``, and ``turtlesim``. +Code for this tutorial is stored `here `_. Open a new terminal and :ref:`source your ROS 2 installation ` so that ``ros2`` commands will work. Navigate to workspace's ``src`` folder and create a new package: @@ -47,8 +48,7 @@ Navigate to workspace's ``src`` folder and create a new package: ros2 pkg create --build-type ament_python learning_tf2_py -Your terminal will return a message verifying the creation of your package ``learning_tf2_py`` -and all its necessary files and folders. +Your terminal will return a message verifying the creation of your package ``learning_tf2_py`` and all its necessary files and folders. 2 Write the static broadcaster node ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,10 +163,8 @@ Open the file using your preferred text editor. ~~~~~~~~~~~~~~~~~~~~ Now let's look at the code that is relevant to publishing the static turtle pose to tf2. -The first lines import required packages.` -First we import the ``TransformStamped`` from the ``geometry_msgs``, -that provides us a template for the message that we will -publish to the transformation tree. +The first lines import required packages. +First we import the ``TransformStamped`` from the ``geometry_msgs``, which provides us a template for the message that we will publish to the transformation tree. .. code-block:: python @@ -179,10 +177,9 @@ Afterward, ``rclpy`` is imported so its ``Node`` class can be used. import rclpy from rclpy.node import Node -The ``tf2_ros`` package provides a ``StaticTransformBroadcaster`` to make the publishing of -static transforms easy. To use the ``StaticTransformBroadcaster``, we need to import it from the -``tf2_ros`` module. ``tf_transformations`` provides functions to convert euler angles to quaternions -and vice versa. +The ``tf2_ros`` package provides a ``StaticTransformBroadcaster`` to make the publishing of static transforms easy. +To use the ``StaticTransformBroadcaster``, we need to import it from the ``tf2_ros`` module. +``tf_transformations`` provides functions for converting Euler angles to quaternions and vice versa. .. code-block:: python @@ -190,19 +187,18 @@ and vice versa. import tf_transformations -The ``StaticFramePublisher`` class constructor initializes the node with the name -``static_turtle_tf2_broadcaster``. Then, ``StaticTransformBroadcaster`` -is created that will send one static transformation upon the startup. +The ``StaticFramePublisher`` class constructor initializes the node with the name ``static_turtle_tf2_broadcaster``. +Then, ``StaticTransformBroadcaster`` is created, which will send one static transformation upon the startup. .. code-block:: python self._tf_publisher = StaticTransformBroadcaster(self) self.make_transforms(transformation) -Here we create a ``TransformStamped`` object which will be the message we will send over once -populated. Before passing the actual transform values we need to give it the appropriate metadata. +Here we create a ``TransformStamped`` object, which will be the message we will send over once populated. +Before passing the actual transform values we need to give it the appropriate metadata. -#. We need to give the transform being published a timestamp and we'll just stamp it with the current time, ``get_clock().now()`` +#. We need to give the transform being published a timestamp and we'll just stamp it with the current time, ``self.get_clock().now()`` #. Then we need to set the name of the parent frame of the link we're creating, in this case ``world`` @@ -229,7 +225,7 @@ Here we populate the 6D pose (translation and rotation) of the turtle. static_transformStamped.transform.rotation.z = quat[2] static_transformStamped.transform.rotation.w = quat[3] -Finally we broadcast static transform using the ``sendTransform()`` function. +Finally, we broadcast static transform using the ``sendTransform()`` function. .. code-block:: python @@ -246,7 +242,7 @@ As mentioned in the :ref:`Creating your first ROS 2 package tutorial .. code-block:: xml - Examples of minimal publisher/subscriber using rclpy + Learning tf2 with rclpy Your Name Apache License 2.0 @@ -267,10 +263,9 @@ Make sure to save the file. 2.3 Add an entry point ~~~~~~~~~~~~~~~~~~~~~~ -To allow the ``ros2 run`` command to run your node, you must add the entry point -to ``setup.py`` (located in the ``src/learning_tf2_py`` directory). +To allow the ``ros2 run`` command to run your node, you must add the entry point to ``setup.py`` (located in the ``src/learning_tf2_py`` directory). -Add the following line between the ``'console_scripts':`` brackets: +Finally, add the following line between the ``'console_scripts':`` brackets: .. code-block:: python @@ -279,8 +274,7 @@ Add the following line between the ``'console_scripts':`` brackets: 3 Build and run ^^^^^^^^^^^^^^^ -It's good practice to run ``rosdep`` in the root of your workspace to -check for missing dependencies before building: +It's good practice to run ``rosdep`` in the root of your workspace to check for missing dependencies before building: .. tabs:: @@ -385,15 +379,12 @@ If everything went well you should see a single static transform The proper way to publish static transforms ------------------------------------------- -This tutorial aimed to show how ``StaticTransformBroadcaster`` can be used to publish static -transforms. In your real development process you shouldn't have to write this code yourself -and should privilege the use of the dedicated ``tf2_ros`` tool to do so. ``tf2_ros`` provides an -executable named ``static_transform_publisher`` that can be used either as a commandline tool -or a node that you can add to your launchfiles. +This tutorial aimed to show how ``StaticTransformBroadcaster`` can be used to publish static transforms. +In your real development process you shouldn't have to write this code yourself and should use the dedicated ``tf2_ros`` tool to do so. +``tf2_ros`` provides an executable named ``static_transform_publisher`` that can be used either as a commandline tool or a node that you can add to your launchfiles. -Publish a static coordinate transform to tf2 using an x/y/z offset in meters and -yaw/pitch/roll in radians. (yaw is rotation about Z, pitch is rotation about Y, -and roll is rotation about X). +Publish a static coordinate transform to tf2 using an x/y/z offset in meters and roll/pitch/yaw in radians. +In our case, roll/pitch/yaw refers to rotation about the x/y/z-axis, respectively. .. code-block:: console @@ -405,8 +396,7 @@ Publish a static coordinate transform to tf2 using an x/y/z offset in meters and ros2 run tf2_ros static_transform_publisher x y z qx qy qz qw frame_id child_frame_id -``static_transform_publisher`` is designed both as a command-line tool for manual use, as well as -for use within ``launch`` files for setting static transforms. For example: +``static_transform_publisher`` is designed both as a command-line tool for manual use, as well as for use within ``launch`` files for setting static transforms. For example: .. code-block:: console @@ -425,5 +415,6 @@ for use within ``launch`` files for setting static transforms. For example: Summary ------- -In this tutorial you learned how to write your own node to publish static transforms to tf2. -In addition, you learned how to publish required static transformations using ``static_transform_publisher`` and launch files. +In this tutorial you learned how static transforms are useful to define static relationships between frames, like ``mystaticturtle`` in relation to the ``world`` frame. +In addition, you learned how static transforms can be useful for understanding sensor data, such as from laser scanners, by relating the data to a common coordinate frame. +Finally, you wrote your own node to publish static transforms to tf2 and learned how to publish required static transformations using ``static_transform_publisher`` executable and launch files. diff --git a/source/Tutorials/Tf2/carrot_dynamic.png b/source/Tutorials/Tf2/images/carrot_dynamic.png similarity index 100% rename from source/Tutorials/Tf2/carrot_dynamic.png rename to source/Tutorials/Tf2/images/carrot_dynamic.png diff --git a/source/Tutorials/Tf2/carrot_static.png b/source/Tutorials/Tf2/images/carrot_static.png similarity index 100% rename from source/Tutorials/Tf2/carrot_static.png rename to source/Tutorials/Tf2/images/carrot_static.png diff --git a/source/Tutorials/Tf2/turtlesim_broadcast.png b/source/Tutorials/Tf2/images/turtlesim_broadcast.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_broadcast.png rename to source/Tutorials/Tf2/images/turtlesim_broadcast.png diff --git a/source/Tutorials/Tf2/turtlesim_delay1.png b/source/Tutorials/Tf2/images/turtlesim_delay1.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_delay1.png rename to source/Tutorials/Tf2/images/turtlesim_delay1.png diff --git a/source/Tutorials/Tf2/turtlesim_delay2.png b/source/Tutorials/Tf2/images/turtlesim_delay2.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_delay2.png rename to source/Tutorials/Tf2/images/turtlesim_delay2.png diff --git a/source/Tutorials/Tf2/turtlesim_follow1.png b/source/Tutorials/Tf2/images/turtlesim_follow1.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_follow1.png rename to source/Tutorials/Tf2/images/turtlesim_follow1.png diff --git a/source/Tutorials/Tf2/turtlesim_follow2.png b/source/Tutorials/Tf2/images/turtlesim_follow2.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_follow2.png rename to source/Tutorials/Tf2/images/turtlesim_follow2.png diff --git a/source/Tutorials/Tf2/turtlesim_frames.png b/source/Tutorials/Tf2/images/turtlesim_frames.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_frames.png rename to source/Tutorials/Tf2/images/turtlesim_frames.png diff --git a/source/Tutorials/Tf2/turtlesim_frames_carrot.png b/source/Tutorials/Tf2/images/turtlesim_frames_carrot.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_frames_carrot.png rename to source/Tutorials/Tf2/images/turtlesim_frames_carrot.png diff --git a/source/Tutorials/Tf2/turtlesim_rviz.png b/source/Tutorials/Tf2/images/turtlesim_rviz.png similarity index 100% rename from source/Tutorials/Tf2/turtlesim_rviz.png rename to source/Tutorials/Tf2/images/turtlesim_rviz.png