ROS2 Week Day 3
ROS2 Week Day 3
August 1, 2024
1 PRESENTS
3 Related Courses
And that’s it! You should be able to see the simulation and control everything as if it was the real
robot if you go to the Gazebo button in the bottom left side of your screen:
Wait around 30 seconds maximum for the simulation to start and you should see this simulation
now:
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.1</span>
<span class="">What is ROS2? </span>
</h1>
It is possible you took this course to answer this question: ”What is ROS2?” For now, however,
it will be more helpful to experience what ROS2 can do.
1
<h1 align=”center”;>
<h2 class="text-center">
<span class="text-primary">1.1.1</span>
<span class="">Move a Robot with ROS2 </span>
</h2>
On the simulation window, you have your first simulated robot: the ROSBot XL. Let´s move
that robot now!
How do you move the ROSBot XL?
The simplest method is to control the robot using an existing ROS2 program. The executables
created during the compilation of a ROS2 program are used to run it. Later in this guide, you’ll
learn more about compilation.
You will launch a previously-made ROS2 program (executable) that allows you to move the robot
using the keyboard since it already exists in this workspace.
- Example 1.1 -
You will need to do some preliminary work before attempting to run the executable. Don’t think
about the meanings of the commands below; you’ll learn how to use them during this tutorial.
So, let’s get on with it. To source your working space, execute the following commands in a Shell:
Execute in Shell
[ ]: source /opt/ros/jazzy/setup.bash
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args --remap cmd_vel:
,→=/rosbot_xl_base_controller/cmd_vel
CONGRATULATIONS! You just launched your first ROS2 program! In this second terminal,
you should have received a message similar to the following:
Shell Output
Now, you can use the keys indicated in the Webshell Output to move the robot around.
Okay. Try to move the robot around now!
REMEMBER, you need to focus on the terminal (shell) where you launched the program for the
keys to take effect. You know you have correctly focused when the cursor starts blinking.
When you get tired of playing with the robot, you can press Ctrl+c to stop the program’s execution
(remember to have the focus). If you want, you can close Webshell #1 and Webshell #2 to continue
the tutorial.
Let’s take a look back at what you’ve learned so far. The ros2 keyword is used for all the ROS2
commands. Therefore, for launching programs, you will have two options:
• Launch the ROS2 program by directly running the executable file.
• Launch the ROS2 program by starting a launch file.
2
It may seem easier to use the run command to launch executables, but you will later understand
why the launch command is useful as well.
For now, you can directly run the executable file. The structure of the command is as follows:
[ ]: ros2 run <package_name> <executable_file>
As you can see, the command has two parameters: the first parameter is the name of the package
that contains the executable file. The second parameter is the name of the executable file
(which is stored inside the package).
For using a launch file, the structure of the command would go as follows:
[ ]: ros2 launch <package_name> <launch_file>
As you can see, this command also has two parameters: the first parameter is the name of the
package that contains the launch file. The second parameter is the name of the launch file
(which is stored in the package).
- End of Example 1.1 -
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.2</span>
<span class="">What is a Package? </span>
</h1>
ROS2 uses packages to organize its programs. You can think of a package as all the files that a
specific ROS2 program contains; all its CPP files, Python files, configuration files, compilation
files, launch files, and parameters files. Also, organizing your ROS2 programs in packages makes
sharing them with other developers/users much easier.
In ROS2, you can create two types of packages: Python packages and CMake (C++) packages.
For this course, though, we will focus on the first ones. Python packages will contain Python
executables.
Every Python package will have the following structure of files and folders:
• package.xml - File containing meta-information about the package (maintainer of the pack-
age, dependencies, etc.).
• setup.py - File containing instructions for how to compile the package.
• setup.cfg - File that defines where the scripts will be installed.
3
• /<package_name> - This directory will always have the same name as your package. You will
put all your Python scripts inside this folder. It already contains an empty __init__.py file
by default.
Some packages might contain extra folders. For instance, the launch folder contains the package’s
launch files (you will read more about it later).
To summarize, you should remember the following:
• Every ROS2 program that you want to execute is organized in a package.
• Every ROS2 program you create must be organized in a package.
• Packages are the primary organization system for ROS2 programs.
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.3</span>
<span class=""> Create a Package </span>
</h1>
Until now, you’ve been inspecting the layout of an existing build package. Now, it’s time to make
your own.
When you want to create packages, you need to work in a particular ROS workspace known as ROS
workspace. The ROS2 workspace is the directory in your hard disk where your ROS2 packages
reside to be usable by ROS2. Usually, the ROS2 workspace directory is called ros2_ws.
- Example 1.2 -
First, source ROS2 on our Shell so that we can use the ROS2 command-line tools.
Execute in Shell
[ ]: source /opt/ros/jazzy/setup.bash
4
At this point, you are finally ready to create your own package! To do that, type the following into
your webshell:
[ ]: ros2 pkg create --build-type ament_python my_package --dependencies rclpy
The package_name is the name of the package you want to create, and the pack-
age_dependencies are the names of other ROS packages that your package depends on.
Note also that we are specifying ament_python as the build type. This indicates that we are
creating a Python package.
- End of Example 1.2 -
- Example 1.3 -
To confirm that your package has been created successfully, use some ROS commands related to
packages. For example, type the following:
Execute in Shell
[ ]: ros2 pkg list
ros2 pkg list | grep my_package
ros2 pkg list: Gives you a list with all packages in your ROS system.
ros2 pkg list | grep my_package: Filters, from all of the packages located in the ROS system,
the package is named my_package.
You can also see the package created and its contents by opening it through the IDE:
If the above commands have not shown you anything in the terminal, don’t panic, it’s normal. If
you have worked with code before, you should remember that you must first compile your code to
get executables, so let’s get on with it in the next section.
- End of Example 1.3 -
- Notes -
Packages are organized inside workspaces. Each workspace can contain as many packages as you
want. For this course, your workspace is named ros2_ws. So, the overall structure would look as
follows:
- End of Notes -
<h1 align=”center”;>
5
<h1 class="text-center">
<span class="text-primary">1.4</span>
<span class=""> Compile a Package </span>
</h1>
When you create a package, you need to compile it to make it work. The command used by ROS2
to compile is the following:
[ ]: colcon build
This command will compile your whole src directory, and it needs to be issued in your ros2_ws
directory to work. Please, remember this!
- Example 1.4 -
Go to your ros2_ws directory and compile your source folder. You can do so by typing the
following:
Execute in Shell
[ ]: cd ~/ros2_ws
colcon build
Alse, after compiling, you have to source the workspace to make sure that the latest modifica-
tions/updates are taken into account:
Execute in Shell
[ ]: source install/setup.bash
Sometimes (for large projects), you will not want to compile all of your packages. This would take
such a long time. You can use the following command to compile only the packages where you’ve
made changes:
[ ]: colcon build --packages-select <package_name>
This command will only compile the packages specified and their dependencies.
Now, try to compile your package named my_package with this command.
Execute in Shell
[ ]: colcon build --packages-select my_package
6
You’ve seen how ROS2 can run programs from launch files. But, how do they work? Let’s take a
look at it.
- Example 1.5 -
In Example 1.1, you used the command ros2 run to start the teleop_keyboard executable file.
But you’ve also seen that you can run executables by using what you know as launch files.
How do they operate? Let’s take a look at an example. If you want to use a launch file to start the
teleop_keyboard executable, you’d need to write something similar to the Python script below:
[ ]: from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='teleop_twist_keyboard',
executable='teleop_twist_keyboard_node',
output='screen'),
])
Don’t worry! You don’t need to write these lines of code in your workspace. You’ll just use them
to review some concepts.
Okay. As you can see, the launch file structure is quite simple. First, you import some modules
from the launch and launch_ros packages.
[ ]: from launch import LaunchDescription
import launch_ros.actions
Within the LaunchDescription object, generate a node where you will provide the following param-
eters:
1. package='package_name' Name of the package that contains the code of the ROS2 program
to execute
2. executable='python_executable_name' Name of the Python executable file that you want
to execute
3. output='type_of_output' Through which channel you will print the output of the program
- End of Example 1.5 -
7
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.6</span>
<span class=""> It's Time for Your First ROS2 Program </span>
</h1>
You should now have your first package built, and you must do something about it! Let’s get
started with your first ROS2 program!
- Example 1.6 -
1. Create a Python file that will be executed in the my_package (all Python scripts) directory
inside my_package folder. (I know, very confusing, but trust me for a moment). For this exercise,
copy this simple Python code simple.py. You can create it directly by RIGHT clicking on the
IDE in the my_package directory of your package and select New File.
Now, copy the content of simple.py into the new file.
simple.py
[ ]: import rclpy
# import the Node module from ROS2 python library
from rclpy.node import Node
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# print a message to the terminal
print("Help me Obi-Wan Kenobi! You're my only hope!")
# shutdown the ROS communication
rclpy.shutdown()
if __name__ == '__main__':
main() #call the main function
2. Create a launch directory inside the package named my_package, created in Example 1.2.
Execute in Shell
[ ]: cd ~/ros2_ws/src/my_package
mkdir launch
You can also create the launch directory through the IDE, as you have seen before, but try practicing
with the terminal.
3. Create a new launch file inside the launch directory.
Execute in Shell
[ ]: cd ~/ros2_ws/src/my_package/launch
8
[ ]: touch my_package_launch_file.launch.py
[ ]: chmod +x my_package_launch_file.launch.py
def generate_launch_description():
return LaunchDescription([
Node(
package='my_package',
executable='simple',
output='screen'),
])
package_name = 'my_package'
9
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name), glob('launch/*.launch.py'))
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='somebody very awesome',
maintainer_email='[email protected]',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'simple_node = my_package.simple:main'
],
},
)
7. Finally, the time has come. Now you must execute it. Run the following command (that you
already know) in the Webshell to launch your program.
Execute in Shell
[ ]: ros2 launch my_package my_package_launch_file.launch.py
Shell Output
- End of Example 1.6 -
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.7</span>
<span class=""> Modifying the setup.py File </span>
</h1>
10
The setup.py file contains all the necessary instructions for properly compiling your package.
In the previous exercise, you had the following file:
setup.py
[ ]: from setuptools import setup
import os
from glob import glob
package_name = 'my_package'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name), glob('launch/*.launch.py'))
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='somebody very awesome',
maintainer_email='[email protected]',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'simple_node = my_package.simple:main'
],
},
)
The main objective of this code is to generate an executable from the script you created a few
moments ago. To do that, you work with a dictionary named entry_points. Inside it, you find
an array called console_scripts.
[ ]: import os
from glob import glob
from setuptools import setup
package_name = 'my_package'
setup(
11
#code
...
#code
entry_points={
'console_scripts': [
'simple_node = my_package.simple:main'
],
},
#code
...
With these lines, you are adding an entry point to the script you wrote earlier, simple.py. For
example, you can see this line as follows:
[ ]: '<executable_name> = <package_name>.<script_name>:main'
So, in this case, you are generating a new executable node named simple_node. This executable
is generated using a script named simple.py inside a package named my_package.
Additionally, there are other things that you can define in a setup.py file.
For colcon to find the launch files during the compilation process, you need to inform Python’s
setup tools of your launch files using the data_files parameter of the setup.py file.
Have a look at the data_files array:
[ ]: import os
from glob import glob
from setuptools import setup
package_name = 'my_package'
setup(
#code
...
#code
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name), glob('launch/*.launch.py'))
],
12
#code
...
#code
The objective of this code is to install the launch files. For example, with the pack-
age named my_package, this will install all the launch files from the launch/ folder, into
~/ros2_ws/install/my_package/share/my_package/.
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.8</span>
<span class=""> ROS2 Nodes </span>
</h1>
In ROS2, each node should be responsible for a single module (e.g., one node for controlling wheel
motors, one for controlling a laser range-finder, etc.). Each node can communicate with other nodes
through different methods.
The animated image is taken from the official ROS2 documentation
For the moment, don’t worry about understanding everything you see in the picture. Look at
the nodes and how they connect to each other. Think that a full robotic system is comprised of
many nodes working together. In ROS2, a single executable (a C++ or Python program, etc.) can
contain one or more nodes.
Okay. Let’s see what you can do with these nodes!
In the previous code, you started a node. What is a node? ROS nodes are essentially ROS programs.
To list all the nodes running on a system, use the ROS2 command:
[ ]: ros2 node list
Shell Output
The nodes you see right now are all related to the Gazebo simulation. Follow the next example to
run and visualize your own node.
- Example 1.7 -
First, update your Python file simple.py with the following code:
13
[ ]: import rclpy
from rclpy.node import Node
class MyNode(Node):
def __init__(self):
# call super() in the constructor in order to initialize the Node object
# the parameter we pass is the node name
super().__init__('obi_wan')
# create a timer sending two parameters:
# - the duration between 2 callbacks (0.2 seeconds)
# - the timer function (timer_callback)
self.create_timer(0.2, self.timer_callback)
def timer_callback(self):
# print a ROS2 log on the terminal with a great message!
self.get_logger().info("Help me Obi-Wan Kenobi! You're my only hope!")
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# declare the node constructor
node = MyNode()
# pause the program execution, waits for a request to kill the node (ctrl+c)
rclpy.spin(node)
# shutdown the ROS communication
rclpy.shutdown()
if __name__ == '__main__':
main()
Have a quick look at the new code. First, create a MyNode class, which inherits from Node.
[ ]: class MyNode(Node):
The class has two methods: __init__ (the constructor of the class) and timer_callback.
Inside the __init__ method, you are initializing a node named obi_wan:
[ ]: super().__init__('obi_wan')
This timer object will trigger the timer_callback method every 0.2 seconds.
- Notes -
Timer objects are useful in ROS2. You will get more familiar with them as you use them during
the course.
14
- End of Notes -
Inside the timer_callback method, you sent a message to the node’s log.
[ ]: self.get_logger().info("Help me Obi-Wan Kenobi! You're my only hope!")
Finally, in your main function, create an instance of the class MyNode and spin it.
node = MyNode()
rclpy.spin(node)
As you can see in the code comments, spin() will keep the node alive and running until someone
shuts it down (by pressing Ctrl+C).
The node will keep publishing the log messages until you stop it.
Recompile it once you have made some changes to your code.
Execute in Shell
[ ]: cd ~/ros2_ws
colcon build
source ~/ros2_ws/install/setup.bash
Shell Output
As you can see, now the /obi_wan node appears in the list!
To see information about your node, you can use the following command:
[ ]: ros2 node info <node_name>
This command shows you information about all the connections that your node has.
Execute in Shell
[ ]: ros2 node info /obi_wan
Shell Output
Don’t be concerned about the command’s performance for the time being. As you progress through
the next lesson, you can gain a better understanding.
- End of Example 1.7 -
15
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.9</span>
<span class=""> Client Libraries </span>
</h1>
You used the rclpy client library in the previous exercise. What exactly is this? In a nutshell, ROS
client libraries allow nodes written in various programming languages to communicate. A core
ROS client library (RCL) implements the standard functionality needed by various ROS APIs.
This makes it easier to write language-specific client libraries.
The ROS2 team currently maintains the following client libraries:
• rclcpp = C++ client library
• rclpy = Python client library
Additionally, other client libraries have been developed by the ROS community. You can check out
the following article for more details: here.
<h1 align=”center”;>
<h1 class="text-center">
<span class="text-primary">1.10</span>
<span class=""> We Are Here! So, What is ROS2? </span>
</h1>
ROS2 is the platform that helps you do everything you’ve seen so far in this unit. It provides the
foundation for managing all of these processes and their interactions. You’ve just scratched the
surface of ROS2’s fundamental principles in this tutorial.
ROS2 is a very powerful tool, sometimes difficult, but powerful. So, if you take your lessons and
continue on your ninja way to learn ROS2, at some point, you will be able to do wonderful things
with fantastic robots.
4 Related Courses
16