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

Written by Ernest Cheong

16/02/2024

 

This tutorial is created by Rosbotics Ambassador 010 Ernest

Rosbotics Ambassador Program https://www.theconstruct.ai/rosbotics-ambassador/)

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

List of resources used in this post:

  1. Use the rosject: https://app.theconstructsim.com/l/5e01d324/
  2. Question from the Robotics StackExchange that is answered in this post: https://robotics.stackexchange.com/questions/88149/ros2-c-and-python-in-same-package-is-it-possible
  3. Similar tutorial that this is based on: https://roboticsbackend.com/ros2-package-for-both-python-and-cpp-nodes/#ROS2_Package_architecture_with_both_Python_and_Cpp_nodes_–_final

Overview

  • Is it possible to have Python and C++ node in the same package? Yes! In this tutorial I’ll show you how to create and configure your Python and Cpp nodes in the same package.
  • You should ideally be familiar with how to create a standard C++ package because the method I’ll use is essentially creating a standard C++ package with additional setup and configurations to include Python libraries and nodes.
  • I’ll be using The Construct’s ROS development studio and doing it in a new ROS2 Humble workspace.

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).

Video Tutorial

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

Check Out These Related Posts

0 Comments

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