How to Create a ROS2 C++ Publisher – Iron


In this tutorial, we will go over how to create a C++ publisher for ROS 2.

In ROS 2 (Robot Operating System 2), a C++ publisher is a program (written in C++) that sends messages across the ROS network to other parts of the system.

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

We will be following the ROS 2 C++ Style Guide.

Let’s get started!



Open a terminal, and type these commands to open VS Code.

cd ~/ros2_ws
code .

Go to View -> Extensions

Search for the “Doxygen Documentation Generator” extension.


Install it.

Write the Code

Go back to the Explorer (Ctrl + Shift + E).

Right-click on the src folder to create a new file called “minimal_cpp_publisher.cpp”.

Type the following code inside minimal_cpp_publisher.cpp:

 * @file minimal_cpp_publisher.cpp
 * @brief Demonstrates publishing string messages to a ROS 2 topic.
 * Description: Demonstrates the basics of publishing messages within the ROS 2 framework. 
 * The core functionality of this publisher is to repeatedly send out string messages
 * at a fixed frequency.
 * -------
 * Subscription Topics:
 *   None
 * -------
 * Publishing Topics:
 *   String message
 *   /topic_cpp - std_msgs/String
 * -------
 * @author Addison Sears-Collins
 * @date 2024-02-12

#include "rclcpp/rclcpp.hpp" // ROS 2 C++ client library for node creation and management
#include "std_msgs/msg/string.hpp" // Standard message type for string messages

using namespace std::chrono_literals; // Enables the specification of a time duration

 * @class MinimalPublisher
 * @brief Defines a minimal ROS 2 publisher node.
 * This class inherits from rclcpp::Node and demonstrates creating a publisher,
 * publishing messages, and using a timer callback in ROS 2.
class MinimalPublisher : public rclcpp::Node
     * @brief Constructs a MinimalPublisher node.
     * Sets up a publisher for 'std_msgs::msg::String' messages on the "topic_cpp" topic
     * and initializes a timer to call the timerCallback method.
    MinimalPublisher() : Node("minimal_publisher"), count_(0) 
        // Create a publisher object for sending string messages on the "topic_cpp" topic 
        // with a queue size of 10.
        publisher_ = create_publisher<std_msgs::msg::String>("topic_cpp", 10);
	    // Set up a timer to call the timerCallback function 
	    timer_ = create_wall_timer(500ms, std::bind(&MinimalPublisher::timerCallback, this));
        RCLCPP_INFO(get_logger(), "Publishing at 2 Hz");

     * @brief Timer callback function.
     * This method is called at a fixed interval. It publishes a string message
     * containing "Hello World" followed by a sequence number.
     *  @return Void.
    void timerCallback() 
        // Create a new String message object.
        auto message = std_msgs::msg::String(); = "Hello World! " +  std::to_string(count_++);
		// Publish the message
    // Member variables.
    size_t count_; // A counter to keep track of the number of messages published.
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_; // The publisher object.
    rclcpp::TimerBase::SharedPtr timer_; // Timer for scheduling the publishing task.

 * @brief Main function.
 * Initializes the ROS 2 system and runs the minimal_publisher node. It keeps the node
 * alive until it is manually terminated.
int main(int argc, char * argv[])

  // Initialize ROS 2.
  rclcpp::init(argc, argv); 
  // Create an instance of the MinimalPublisher node and keep it running.
  auto minimal_publisher_node = std::make_shared<MinimalPublisher>();

  // Shutdown ROS 2 upon node termination.

  // End of program.
  return 0; 

Configure CMakeLists.txt

Now we need to modify the CMakeLists.txt file inside the package so that the ROS 2 system will be able to find the cost we just wrote.

Open up the CMakeLists.txt file that is inside the package.

Make it look like this:

cmake_minimum_required(VERSION 3.8)

# Check if the compiler being used is GNU's C++ compiler (g++) or Clang.
# Add compiler flags for all targets that will be defined later in the 
# CMakeLists file. These flags enable extra warnings to help catch
# potential issues in the code.
# Add options to the compilation process
  add_compile_options(-Wall -Wextra -Wpedantic)

# Locate and configure packages required by the project.
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclpy REQUIRED)
find_package(std_msgs REQUIRED)

# Define a CMake variable named dependencies that lists all
# ROS 2 packages and other dependencies the project requires.

# Add the specified directories to the list of paths that the compiler
# uses to search for header files. This is important for C++
# projects where you have custom header files that are not located
# in the standard system include paths.

# Tells CMake to create an executable target named minimal_cpp_publisher
# from the source file src/minimal_cpp_publisher.cpp. Also make sure CMake
# knows about the program's dependencies.
add_executable(minimal_cpp_publisher src/minimal_cpp_publisher.cpp)
ament_target_dependencies(minimal_cpp_publisher ${dependencies})

add_executable(minimal_cpp_subscriber src/minimal_cpp_subscriber.cpp)
ament_target_dependencies(minimal_cpp_subscriber ${dependencies})

# Copy necessary files to designated locations in the project
install (
  DIRECTORY cobot_arm_examples scripts

  DIRECTORY include/

# Install cpp executables

# Install Python modules for import

# Install Python executables

# Automates the process of setting up linting for the package, which
# is the process of running tools that analyze the code for potential
# errors, style issues, and other discrepancies that do not adhere to
# specified coding standards or best practices.
  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)

# Used to export include directories of a package so that they can be easily
# included by other packages that depend on this package.

# Generate and install all the necessary CMake and environment hooks that 
# allow other packages to find and use this package.

Configure package.xml

Now we need to configure the package.xml file.

Open the package.xml file, and make sure it looks like this:

<?xml version="1.0"?>
<?xml-model href="" schematypens=""?>
<package format="3">
  <description>Basic examples demonstrating ROS 2</description>
  <maintainer email="">Addison Sears-Collins</maintainer>

  <!--Specify build tools that are needed to compile the package-->

  <!--Declares package dependencies that are required for building the package-->

  <!--Specifies dependencies that are only needed for testing the package-->


Build the Workspace

cd ~/ros2_ws
colcon build
source ~/.bashrc

Run the Node

ros2 run cobot_arm_examples minimal_cpp_publisher 

Let’s check out the list of topics.

ros2 topic list

Let’s check out the data coming over the topic_cpp topic.

ros2 topic echo /topic_cpp 
ros2 topic hz /topic_cpp
ros2 topic info /topic_cpp --verbose