ROS2 C++ Package Creation Guide | ROS2 Tutorial

How to create a ROS2 C++ package

Written by Ruben Alves


What we are going to learn

  1. How to create a ROS2 package
  2. How to create a package with some dependencies
  3. How to create many packages in a ros project
  4. How to compile a ros2 workspace

List of resources used in this post

  1. Use this rosject:
  2. The Construct:
  3. ROS2 Courses –▸
    1. ROS2 Basics in 5 Days Humble (Python):
    2. ROS2 Basics in 5 Days Humble (C++):


ROS (Robot Operating System) is becoming the de facto standard “framework” for programming robots. In this post, let’s learn how to create a ROS2 package, essential for giving instruction to robots, using the ros2 command.

ROS Inside!

ROS Inside

ROS Inside

Before anything else, if you want to use the logo above on your own robot or computer, feel free to download it and attach it to your robot. It is really free. Find it in the link below:

ROS Inside logo

Opening the rosject

In order to follow this tutorial, we need to have ROS2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject for that:

Just by copying the rosject (clicking the link above), you will have a setup already prepared for you.

After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject (below you have a rosject example).

Learn ROS2 Parameters - Run rosject

ROS2 package creation  – Run rosject (example of the RUN button)


After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.

Creating a ros2 package

In order to create a ROS2 package, we need to have a ROS2 Workspace, and for that, we need a terminal.

Let’s open a terminal by clicking the Open a new terminal button.


Open a new Terminal

Open a new Terminal


Once inside the first terminal, let’s first run a command that shows the list of available options for ros2:

ros2 -h
the following output should be produced:
ros2 is an extensible command-line tool for ROS 2.
  -h, --help            show this help message and exit

  action     Various action related sub-commands
  bag        Various rosbag related sub-commands
  component  Various component related sub-commands
  daemon     Various daemon related sub-commands
  doctor     Check ROS setup and other potential issues
  interface  Show information about ROS interfaces
  launch     Run a launch file
  lifecycle  Various lifecycle related sub-commands
  multicast  Various multicast related sub-commands
  node       Various node related sub-commands
  param      Various param related sub-commands
  pkg        Various package related sub-commands
  run        Run a package specific executable
  security   Various security related sub-commands
  service    Various service related sub-commands
  topic      Various topic related sub-commands
  wtf        Use `wtf` as alias to `doctor`

  Call `ros2 <command> -h` for more detailed usage.

As we can see in the output above, we have a command called pkg, and we can also get help with the ros2 pkg -h command. Let’s try it:
ros2 pkg -h
Running that command produces the following:
Various package related sub-commands
  -h, --help            show this help message and exit

  create       Create a new ROS 2 package
  executables  Output a list of package specific executables
  list         Output a list of available packages
  prefix       Output the prefix path of a package
  xml          Output the XML of the package manifest or a specific tag

Since what we want to do is create a package, we could ask for help with the create command shown above. Let’s try it:
ros2 pkg create -h
That gives us the following:
usage: ros2 pkg create [-h] [--package-format {2,3}] [--description DESCRIPTION] [--license LICENSE] [--destination-directory DESTINATION_DIRECTORY] [--build-type {cmake,ament_cmake,ament_python}]
                       [--dependencies DEPENDENCIES [DEPENDENCIES ...]] [--maintainer-email MAINTAINER_EMAIL] [--maintainer-name MAINTAINER_NAME] [--node-name NODE_NAME] [--library-name LIBRARY_NAME]

Create a new ROS 2 package

positional arguments:
  package_name          The package name

  -h, --help            show this help message and exit
  --package-format {2,3}, --package_format {2,3}
                        The package.xml format.
  --description DESCRIPTION
                        The description given in the package.xml
  --license LICENSE     The license attached to this package; this can be an arbitrary string, but a LICENSE file will only be generated if it is one of the supported licenses (pass '?' to get a list)
  --destination-directory DESTINATION_DIRECTORY
                        Directory where to create the package directory
  --build-type {cmake,ament_cmake,ament_python}
                        The build type to process the package with
  --dependencies DEPENDENCIES [DEPENDENCIES ...]
                        list of dependencies
  --maintainer-email MAINTAINER_EMAIL
                        email address of the maintainer of this package
  --maintainer-name MAINTAINER_NAME
                        name of the maintainer of this package
  --node-name NODE_NAME
                        name of the empty executable
  --library-name LIBRARY_NAME
                        name of the empty library

Ok, according to the instructions, we should be able to create a package just using ros2 pkg create PKG_NAME. Let’s try to create a package named my_superbot inside the ros2_ws/src folder.
cd ~/ros2_ws/src

ros2 pkg create my_superbot

Assuming that everything went as expected, we should see something like this:

going to create a new package
package name: my_superbot
destination directory: /root/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['root <root@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./my_superbot
creating ./my_superbot/package.xml
creating source and include folder
creating folder ./my_superbot/src
creating folder ./my_superbot/include/my_superbot
creating ./my_superbot/CMakeLists.txt
According to the log messages, we now have a package called my_superbot, with some files inside the my_superbot folder. The most important files are ./my_superbot/package.xml and ./my_superbot/CMakeLists.txt. The former (package.xml) because it defines the package name, and the latter (CMakeLists.txt) because it contains the “instructions” on how to compile our package.
If you now run the ls command, you should be able to see the my_superbot folder, which is essentially your ROS2 package.
Also, if you run the “tree .  command, you should see the folder structure.:
tree .
The package structure:
└── my_superbot
    ├── CMakeLists.txt
    ├── include
    │   └── my_superbot
    ├── package.xml
    └── src

4 directories, 2 files
This is the simplest and easiest way of creating a ROS2 package.
If  you don’t have the tree command installed, you can install it using the commands below:
sudo apt-get update

sudo apt-get install -y tree

Creating a ros2 package with some dependencies

Most of the times, when we create a package, we basically want to reuse or leverage existing tools (or packages).

Let’s remove the package we just created, and create it again, but at this time, specifying some dependencies:
cd ~/ros2_ws/src

rm -rfv my_superbot
Okay, we just removed the package we created earlier. If you remember, previous we executed the “ros2 pkg create -h“, which provided us with some help with dependencies:

     list of dependencies

Let’s now create the package with the same name, but at this time, specifying rclcpp and std_msgs dependencies:
cd ~/ros2_ws/src

ros2 pkg create my_superbot --dependencies rclcpp std_msgs
If you use the “ls” or “tree” commands, like before, you will see that the package has been successfully created. The main differences are in the contents of the package.xml and CMakeLists.txt files.

tree .

Creating many ros2 packages

There is a principle in Software Development called DRY (Don’t repeat yourself). It basically tells us that we have to reuse code, making code easier to maintain.

There is also the Separation of Concerns (SoC) design principle that manages complexity by partitioning the software system so that each partition is responsible for a separate concern, minimizing the overlap of concerns as much as possible.

In a robotics project, we should ideally have different packages for different purposes. Let’s remove again the package we just created, and rather than creating the package directly on the ros2_ws/src folder, let’s create a project folder there, and then create the packages inside that project folder. Start by removing the existing package:

cd ~/ros2_ws/src

rm -rfv my_superbot
Now, let’s create a folder called superbot_project:
cd ~/ros2_ws/src

mkdir superbot_project

Inside the project folder, we can now create different packages.

cd superbot_project

ros2 pkg create superbot_description

ros2 pkg create superbot_detection

ros2 pkg create superbot_audio
We created 3 packages.  If we run “tree .” or “ls -l“, we should be able to see the three packages there:
tree .
The output of the tree command:
├── superbot_audio
│   ├── CMakeLists.txt
│   ├── include
│   ├── package.xml
│   └── src
├── superbot_description
│   ├── CMakeLists.txt
│   ├── include
│   │   └── superbot_description
│   ├── package.xml
│   └── src
└── superbot_detection
    ├── CMakeLists.txt
    ├── include
    │   └── superbot_detection
    ├── package.xml
    └── src

12 directories, 6 files

Building our ros2 packages

Now that we have created the packages, even though they don’t contain any meaning code, let’s learn how to compile the workspace, which contains the packages.

For that, we use the “colcon build” command on the main workspace folder:

cd ~/ros2_ws/

colcon build
source install/setup.bash
Assuming that everything worked nicely, the output should be similar to the following:
Starting >>> superbot_audio
Starting >>> superbot_description
Starting >>> superbot_detection
Finished <<< superbot_description [0.67s]                                                                                            
Finished <<< superbot_audio [0.69s]
Finished <<< superbot_detection [0.68s]

Summary: 3 packages finished [0.83s]
If we now run the “ls” command, we should see three new folders there: devel, install, log, in addition to the src folder that we created.

# build  install  log  src
When you compile your workspace, if you want to make ROS2 aware that your packages are compiled and ready to use, you have to tell it where to find the packages using the “source” command. That is why we used it after the “colcon build” command.

Congratulations. Now you know how to create your own packages in ROS2, and how to compile them.

We hope this post was really helpful to you. If you want a live version of this post with more details, please check the video in the next section.

Youtube video

So this is the post for today. Remember that we have the live version of this post on YouTube. If you liked the content, please consider subscribing to our YouTube channel. We are publishing new content ~every day.

Keep pushing your ROS Learning.

Related Courses & Training

If you want to learn more about ROS and ROS2, we recommend the following courses:

Get ROS2 Industrial Ready- Hands-On Training by The Construct cover.png

Get ROS2 Industrial Ready- Hands-On Training by The Construct cover.png

Topics: build | colcon | package | ros2 | ros2_ws
Masterclass 2023 batch2 blog banner

Check Out These Related Posts


Pin It on Pinterest

Share This