How to use C++ and Python in the same ROS 2 package – English ROS 2 Tutorial

Written by Ernest Cheong

16/02/2024

What we are going to learn:

  1. How to set up the package architecture to accommodate C++ and Python in the same package
  2. How to configure this package (by modifying package.xml and CMakeLists.txt)
  3. How to compile and run Python and C++ nodes from this package

If you want to learn ROS 2 Python in a practical, hands-on way, check out the course
ROS 2 Basics in 5 Days: https://app.theconstruct.ai/courses/132

In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.

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: https://app.theconstructsim.com/l/5e01d324/

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 ( see this example).

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

In order to interact with ROS2, we need a terminal.

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

Open a new Terminal

 

Setup the package architecture

Create a standard C++ package


With dependencies on rclpy and rclcpp:

With dependencies on rclpy:

cd ~/ros2_ws/src/
ros2 pkg create cpp_py_pkg –build-type ament_cmake –dependencies rclpy rclcpp

Run the “tree . command to see the folder structure. If you don’t have the command installed, you can install it using:

sudo apt-get update
sudo apt-get install -y tree

You should be able to see this structure which you are already familiar with:

cpp_py_pkg/
├── CMakeLists.txt
├── include
│ └── cpp_py_pkg
├── package.xml
└── src

Add a C++ node and header

cd cpp_py_pkg/
touch src/cpp_node.cpp
touch include/cpp_py_pkg/cpp_header.hpp

In order to compile the package later, we need at least a main function in the C++ node. For this tutorial for simplicity, we can just add this minimal code to the cpp_node.cpp file:

#include “rclcpp/rclcpp.hpp”
// Include your header file to use it
#include “cpp_py_pkg/cpp_header.hpp”
int main(int argc, char **argv)
{
// Initiate ROS communications
    rclcpp::init(argc, argv);
// Instantiate the node
    auto node = std::make_shared<rclcpp::Node>(“my_node_name”);
// Make the node spin
    rclcpp::spin(node);
// Shutdown ROS communications
    rclcpp::shutdown();
    return 0;
}


Add a Python node and module to import

For Python, we need to create additional folders first:

mkdir cpp_py_pkg
touch cpp_py_pkg/__init__.py
mkdir scripts

Then we can add the files:

touch cpp_py_pkg/module_to_import.py
touch scripts/py_node.py


You have to add a shebang line first thing in the py_node.py file otherwise you will get an error when trying to run the node:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
# Import a specific function/class from your module
# from cpp_py_pkg.module_to_import import …
def main(args=None):
# Initiate ROS communications
    rclpy.init(args=args)
# Instantiate the node
    node = Node(‘my_node_name’)
# Make the node spin
    rclpy.spin(node)
# Shutdown ROS communications
    rclpy.shutdown()
if __name__ == ‘__main__’:
    main()

 

Final package architecture

Run the “tree . command to see the folder structure. I have added additional comments and files to make it clearer:

cpp_py_pkg/
# –> package info, configuration, and compilation
├── CMakeLists.txt
├── package.xml
# Python stuff
# –> empty init file & any python library or module files we want to import
├── cpp_py_pkg
│ ├── __init__.py
│ └── module_to_import.py
│ └── another_module_to_import.py
# –> python executables/nodes
├── scripts
│ └── py_node.py
# Cpp stuff
# –> cpp header files
├── include
│ └── cpp_py_pkg
│ └── cpp_header.hpp
│ └── another_cpp_header.hpp
# –> cpp executables/nodes
└── src
└── cpp_node.cpp

The CMakeLists.txt and package.xml will be shared by Python and C++, which is what we will edit in the next section to configure the package for both Python and C++.

Configure the package

package.xml


Add a buildtool_depend tag for ament_cmake_python:

<buildtool_depend>ament_cmake_python</buildtool_depend>

So your package.xml should look like this:

<?xml version=”1.0″?>
<?xml-model href=”http://download.ros.org/schema/package_format3.xsd” schematypens=”http://www.w3.org/2001/XMLSchema”?>
<package format=”3″>
<name>cpp_py_pkg</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email=”user@todo.todo”>user</maintainer>
<license>TODO: License declaration</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>ament_cmake_python</buildtool_depend>

<depend>rclpy</depend>
<depend>rclcpp</depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>

cd ~/ros2_ws/
colcon build –packages-select py_pkg

 

CMakeLists.txt

Add this external dependency:

find_package(ament_cmake_python REQUIRED)

Add this for C++:

# Include Cpp “include” directory
include_directories(include)

# Create Cpp executable and link with dependencies
add_executable(cpp_executable src/cpp_node.cpp)
ament_target_dependencies(cpp_executable rclcpp)

# Install Cpp executables in the ros2_ws/install/cpp_py_pkg/lib/cpp_py_pkg/ folder
install(TARGETS
cpp_executable
DESTINATION lib/${PROJECT_NAME}
)

Add this for Python:

# Install Python modules
ament_python_install_package(${PROJECT_NAME})

# Install Python executables in the ros2_ws/install/cpp_py_pkg/lib/cpp_py_pkg/ folder
install(PROGRAMS
scripts/py_node.py
DESTINATION lib/${PROJECT_NAME}
)

So your CMakeLists.txt should look like this:

source ~/.bashrc # . ~/.bashrc

So your CMakeLists.txt should look like this:

cmake_minimum_required(VERSION 3.8)
project(cpp_py_pkg)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES “Clang”)
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclpy REQUIRED)
find_package(rclcpp REQUIRED)
find_package(ament_cmake_python REQUIRED)

# Include Cpp “include” directory
include_directories(include)

# Create Cpp executable and link with dependencies
add_executable(cpp_executable src/cpp_node.cpp)
ament_target_dependencies(cpp_executable rclcpp)

# Install Cpp executables in the ros2_ws/install/cpp_py_pkg/lib/cpp_py_pkg/ folder
install(TARGETS
cpp_executable
DESTINATION lib/${PROJECT_NAME}
)

# Install Python modules
ament_python_install_package(${PROJECT_NAME})

# Install Python executables in the ros2_ws/install/cpp_py_pkg/lib/cpp_py_pkg/ folder
install(PROGRAMS
scripts/py_node.py
DESTINATION lib/${PROJECT_NAME}
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()

ament_package()

Compile package, then run C++ node and Python node

cd ~/ros2_ws/
colcon build –packages-select cpp_py_pkg

Source ROS2 environment and start C++ node in one terminal:

source ~/ros2_ws/install/setup.bash
ros2 run cpp_py_pkg cpp_executable

Source ROS2 environment and start Python node in another terminal:

source ~/ros2_ws/install/setup.bash
ros2 run cpp_py_pkg py_node.py

That’s it! If there are no errors when you run the nodes then it means that it was successful (remember that our nodes do not do anything except spin).

Congratulations. You now know how to use C++ and Python in the same ROS 2 package.

To learn more about ROS 2, have a look at the course below:

We hope this post was really helpful to you.

This tutorial is created by Robotics Ambassador Ernest.

Video Tutorial

Topics: C++ | python | ros2
Masterclass 2023 batch2 blog banner

Check Out These Related Posts

129. ros2ai

129. ros2ai

I would like to dedicate this episode to all the ROS Developers who believe that ChatGPT or...

read more

3 Comments

  1. Name

    Comment

    Reply
  2. Name

    e6yfpXvx

    Reply

Submit a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Pin It on Pinterest

Share This