How to Create a Workspace in ROS 2 Jazzy

In this tutorial, we will create a ROS 2 workspace.

In ROS 2, a workspace is a folder that is the central location for organizing and developing your robot software. It contains all the code, data files, and configuration scripts related to your specific robot project. 

The official instructions for creating a workspace are here, but I will walk you through the entire process, step by step.

Let’s get started!

Prerequisites

Directions

Open a terminal, and type the following command to create your workspace. We can name our workspace anything, but I will name it ros2_ws to stand for ROS 2 workspace.

mkdir -p ~/ros2_ws/src

The src folder that is inside your ROS 2 workspace is where all your code will go for your robot.

Move to the root of your new workspace using this command:

cd ~/ros2_ws/

We don’t have any code inside our workspace source folder yet, but when we do, we will need to run the command below to build the workspace. 

colcon build

This colcon build command needs to be run in the root of your workspace whenever you make additions or changes to the code for the robot.

‘colcon build’ takes all the different pieces of your robot’s software and puts them together. This makes the software ready for the robot to use.

Go ahead and run the colcon build command now.

colcon build

Now type this command:

dir

Here is what you should see:

1-colcon-build

There are three folders. These folders are automatically created when you run the colcon build command in your ROS 2 workspace:

  • build: This is where ROS 2 temporarily stores files while it’s putting your code together.
  • install: This is where the finished, ready-to-use parts of your robot’s software are placed.
  • log: This folder keeps track of what happened when you built your code, which is helpful for finding and fixing problems.

Now we need to run the following command to make sure our workspace can be found any time we open a new terminal window.

echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
source ~/.bashrc

Remember that ~/.bashrc file is a script that runs whenever a new terminal session is started.

You can see that we have a new entry in the bashrc file right at the bottom.

gedit ~/.bashrc
2-new-entry-bashrc

That’s it! You have now created a ROS 2 workspace. I’ll see you in the next tutorial. Keep building!

Understanding DDS and the ROS_DOMAIN_ID Variable

How DDS Works?

dds-overview

When you’re working with robots, you need a way for all the different parts of the robot to talk to each other. That’s where something called DDS comes in. DDS stands for Data Distribution Service, and it’s like a super-advanced messaging system for robots and computers.

Think of it like this: imagine you have a bunch of robots in a factory, and they all need to work together to build cars. Each robot has a specific job, like welding doors or painting bumpers. To do their jobs, they need to be able to send messages to each other, like “I’ve finished welding this door” or “I need more paint over here!”

DDS is what makes this communication possible. It is a set of rules that all the robots agree to follow so they can send messages quickly and reliably. It is kind of like a big chat room where robots can post and read messages, but instead of just being for fun, these messages contain important information that the robots need to do their jobs.

ROS 2 uses DDS under the hood to help all the different parts of a robot communicate. You can think of DDS as the glue that holds everything together in a ROS 2 system.

What is the ROS_DOMAIN_ID?

Now, here’s where something called the ROS_DOMAIN_ID comes in. In a DDS system, you can have multiple “chat rooms,” each with its own ID number. These “chat rooms” are called domains in DDS language. The ROS_DOMAIN_ID is just a number that tells ROS which domain to use.

By default, ROS uses 0 for the ROS_DOMAIN_ID. It is fine if we keep the default since we are working in simulation. However, in the real world, you might have a facility with multiple robots, all running ROS 2. If all these robots use the default settings, they’ll all be talking in the same “chat room” – domain 0. 

This is fine if you want all your robots to be able to communicate with each other. But let’s say you have two different teams of robots in your factory, and you don’t want them to get confused by hearing each other’s messages. You could put one team in domain 1 and the other team in domain 2. They’re all still using DDS to communicate, but the two teams can’t hear each other because they’re in different domains.

The easiest way to choose a ROS_DOMAIN_ID is to pick a number between 0 and 101, or between 215 and 232. These numbers are less likely to conflict with other programs that might be using DDS.

In my tutorials, we’ll be sticking with the default ROS_DOMAIN_ID of 0. This means all our robots will be able to communicate with each other. But if you ever need to work with multiple groups of robots that shouldn’t be talking to each other, remember that you can use different ROS_DOMAIN_IDs to keep their conversations separate.

If you did want to change the ROS_DOMAIN_ID, you can do it by typing this command:

export ROS_DOMAIN_ID=<your_chosen_number>

Replace <your_chosen_number> with the ROS_DOMAIN_ID you want to use. For example, if you want to use a ROS_DOMAIN_ID of 42, you would add in the terminal window before the commands you want to run:

export ROS_DOMAIN_ID=42

Remember, if you have multiple robots on the same WiFi network and you want them to be able to talk to each other, they should all have the same ROS_DOMAIN_ID. But if you have groups of robots that shouldn’t be communicating, give each group its own ROS_DOMAIN_ID.

Example

Let’s look at an example:

Open a new terminal, and type this:

ros2 run demo_nodes_cpp talker

This “talker” program publishes messages to the ROS 2 system. 

Open another terminal window, and type:

ros2 run demo_nodes_py listener

You can see both programs are able to talk to each other freely because they have the same ROS_DOMAIN_IDs.

1-talk-freely

Now close both nodes by pressing CTRL+C in both terminal windows.

Now in a the first terminal window, type this:

export ROS_DOMAIN_ID=8

In that same terminal window, type:

ros2 run demo_nodes_cpp talker

Now in your second terminal window, type:

ros2 run demo_nodes_py listener

You can see this node can’t receive messages from the other node.

2-node-cannot-receive-messages

You can now close this listener using CTRL + C.

Now set the ROS_DOMAIN_ID to match our publisher node.

export ROS_DOMAIN_ID=8
ros2 run demo_nodes_py listener

You can see now that, since these nodes have the same ROS_DOMAIN_ID, they can now communicate with each other. 

3-same-ros-domain-id

That’s it. I’ll see you in the next tutorial. Keep building!

How to Install ROS 2 Jazzy

In this tutorial, we will install ROS 2 Jazzy.

By the end of this tutorial, you will be running your first ROS 2 programs.

You Will Need

In order to complete this tutorial, you will need:

  • A computer or virtual machine running Ubuntu 24.04. If you followed my previous tutorial, you already have that setup.

Set the Locale

The official steps for installing ROS are at this link at ROS.org, but let’s go through this entire process together.

Follow along with me click by click, keystroke by keystroke.

We will begin by installing ROS 2 Jazzy via Debian Packages. Debian packages are software files used to install programs and applications on Ubuntu.

Open a new terminal window.

Type this command inside a terminal window.

locale

A locale is a set of variables that define the language, country, and character encoding settings. These settings are used by applications to determine how to display text, dates, times, and other information.

Now type the following command:

sudo apt update && sudo apt install locales

“sudo apt update” updates the package index list. This list is a database of all the software packages available for your version of Ubuntu.

“sudo apt install locales” installs the locales package, which provides support for different languages and regions.

Now type the following commands into the terminal window to generate locale definition files. After each command, press Enter only your keyboard:

sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

In this case, these commands are generating locale definition files for the English (United States) locale and the English (United States) UTF-8 locale. The UTF-8 locale is a special locale that supports the UTF-8 character encoding, which is the standard encoding for most languages.

Now we need to verify the settings by typing:

locale

Here is what you should see:

1-locale

Enable the Required Repositories

Let’s add the ROS 2 apt repository to our system. APT stands for “Advanced Package Repository”. This repository provides a convenient way to install and manage ROS 2 packages without having to clone packages to your computer from GitHub and build them from that source code.  

Open a terminal window, and type the following two commands:

sudo apt install software-properties-common
sudo add-apt-repository universe

Press Enter.

The software-properties-common package provides a number of tools for managing software sources on Ubuntu and Debian systems. 

The universe repository is a software repository that contains a wide variety of software packages, including many that are not included in the default Ubuntu and Debian repositories. 

Now we need to add the ROS 2 GPG key with apt. The ROS 2 GPG key makes sure the software packages you are installing are from a trusted source.

Type these two commands:

sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

Add the repository to your sources list (copy and paste all of this below):

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2-testing/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

Type the following command to install ROS 2 development tools.

sudo apt update && sudo apt install ros-dev-tools

Now update the apt repository:

sudo apt update -y

Upgrade the packages on your system to make sure you have the newest versions.

sudo apt upgrade -y

Install ROS 2

Now for the fun part. Here is where we get to install ROS 2 Jazzy. 

Open a terminal window, and type this command:

sudo apt install ros-jazzy-desktop

Set Up the Environment Variables

Once jazzy has finished installing, you need to set up the important environment variables. Environment variables are settings that tell your computer how to find and use ROS 2 commands and packages.

Open a terminal window, and type this command:

echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc

When you run this command, it appends the line source /opt/ros/jazzy/setup.bash to your ~/.bashrc file

What does this do? Each time you open a new terminal window, you are starting what is called a bash session. The bash session needs to know what version of ROS 2 you are using. 

By adding this line (echo “source /opt/ros/jazzy/setup.bash”) to your ~/.bashrc file, you ensure the necessary environment variables and paths for ROS 2 Jazzy are properly set up each time you open a new terminal window, allowing you to use ROS 2 commands and tools without having to manually run the setup.bash script every time.

For the changes to take effect, you now need to open a new terminal window, or you can type this command in the current terminal:

source ~/.bashrc

You can verify that line was added by typing:

sudo apt-get install gedit -y
gedit ~/.bashrc

Close the gedit window.

2-verify-bash-alias

Check Your ROS 2 Version

Now let’s see what ROS 2 version we are using using:

printenv ROS_DISTRO

You should see “jazzy”.

You can also type:

env | grep ROS
3-env-grep-ros

Finally, you can also type:

echo $ROS_DISTRO

Set up the system to manage ROS package dependencies.

sudo rosdep init
rosdep update

Install Gazebo and Other Useful Packages

Let’s install some other useful packages like pip (the Python package manager), Gazebo, a simulation software for robotics, and NumPy, a scientific computing library for Python.

sudo apt-get install python3 python3-pip -y
sudo apt-get install ros-${ROS_DISTRO}-ros-gz -y
sudo apt-get install python3-numpy

Test Your Gazebo Installation

If you want to run an example Gazebo simulation world now, you can type:

LIBGL_ALWAYS_SOFTWARE=1 QT_QPA_PLATFORM=xcb gz sim -v 4 shapes.sdf

These environment variables here “LIBGL_ALWAYS_SOFTWARE=1 QT_QPA_PLATFORM=xcb” help you avoid the following nasty error which happens by default when you try to launch Gazebo from a fresh ROS 2 Jazzy installation:

[GUI] [Err] [Ogre2RenderEngine.cc:1301]  Unable to create the rendering window: OGRE EXCEPTION(3:RenderingAPIException): currentGLContext was specified with no current GL context in GLXWindow::create at ./.obj-x86_64-linux-gnu/gz_ogre_next_vendor-prefix/src/gz_ogre_next_vendor/RenderSystems/GL3Plus/src/windowing/GLX/OgreGLXWindow.cpp (line 165)

You can see the error, if you open a new terminal window, and type:

gz sim -v 4 shapes.sdf

Let’s make these environment variables permanent. Open a terminal window, and type these commands, one after the other:

echo 'export LIBGL_ALWAYS_SOFTWARE=1' >> ~/.bashrc
echo 'export QT_QPA_PLATFORM=xcb' >> ~/.bashrc
source ~/.bashrc

Now test your Gazebo installation again by typing the following command:

gz sim

You should see this screen.

4-see-this-screen

Click on the NAO Joint Control simulation, and click Run.

5-nao-simulation

Close the simulation by typing CTRL + C in the terminal window.

Now try the Panda Joint Control World.

gz sim

Click on the Panda Joint Control World simulation, and click Run. It might take up to 30 seconds to load.

6-panda-joint-control-world

Close the simulation by typing CTRL + C in the terminal window.

Now run another example:

gz sim shapes.sdf -v 4

Close the simulation by typing CTRL + C in the terminal window.

Now let’s run the same shapes example using a ros2 command (source: official Gazebo ROS 2 GitHub repository):

ros2 launch ros_gz_sim gz_sim.launch.py gz_args:="shapes.sdf"
7-shapes-sdf

Close the simulation by typing CTRL + C in the terminal window.

Test Your ROS 2 Installation

Now that we have tested Gazebo, let’s test our ROS 2 installation by running some sample programs.

Open a terminal window, and type:

ros2 run demo_nodes_cpp talker
9-talker

This command runs a pre-built program called “talker” that comes with ROS 2. The “talker” program publishes messages to the ROS 2 system in string format. 

Open another terminal window, and type:

ros2 run demo_nodes_py listener
10-listener

If your output looks similar to the images above, you have installed ROS 2 successfully. 

To close these programs, press CTRL + C on your keyboard in both terminal windows.

So what did we just do here, and what do these two hello world programs we just ran have to do with real robots?

So imagine you’re building a robot that needs to navigate through a room. The “talker” program is like a sensor on the robot (e.g., a depth camera for example) that constantly sends out information about what it sees. 

The “listener” program, on the other hand, receives the information that was published by the talker program. This listener program, in a real robot, could do something with that data like stop the wheels if an obstacle is detected by the camera.

The talker program is what we call in ROS 2, a publisher. The listener program is called a subscriber. Remember those two terms. Those are the two most important terms in all of ROS 2. 

A ROS 2 publisher sends data, and a subscriber receives data. 

In future tutorials, we will create our own publishers and subscribers for actual robots. 

Publishers and subscribers are the main way programs exchange information with each other inside a robot.

So, again, just remember this…publishers are programs that send data to other programs, and subscribers are programs that receive data from other programs. All these programs are usually written in either Python or C++.

Collectively, publishers and subscribers in ROS 2 are called nodes. You just saw how to run a publisher node named talker and a subscriber node named listener.

The term node is the third most important term in all of ROS 2. So remember it because you will be using that term again and again over the course of your work with ROS 2.

To close out this tutorial, let me show you a cool program that enables you to show multiple terminal windows in a single window.

The program is called terminator.

Open a terminal window, and type:

sudo apt-get install terminator -y

Now type:

terminator

Right-click on the screen, and click “Split Horizontally”.

11-split-horizontally

On the top panel, type:

ros2 run demo_nodes_cpp talker

On the bottom panel, type:

ros2 run demo_nodes_py listener

Now, press Enter in both terminals.

Here is what you should get:

12-terminator

Press CTRL + C in both terminal windows to close everything.

That’s it! Keep building! I’ll see you in the next tutorial.