The demo_nodes_cpp package is part of the ROS 2 demo packages, often used as examples for demonstrating ROS 2 concepts in C++. The default demo_nodes_cpp is pre-installed and pre-built, so it doesn’t require building unless you modify it

https://docs.ros.org/en/rolling/p/demo_nodes_cpp/

File Structure

Here’s a typical directory structure for demo_nodes_cpp:

demo_nodes_cpp/
β”œβ”€β”€ CMakeLists.txt
β”œβ”€β”€ package.xml
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ talker.cpp
β”‚   └── listener.cpp
└── launch/
    └── demo_nodes_cpp_launch.py

CMakeLists.txt

This file contains the build configuration for the ROS 2 package

cmake_minimum_required(VERSION 3.5)
project(demo_nodes_cpp)
 
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
 
add_executable(talker src/talker.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
 
add_executable(listener src/listener.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
 
install(TARGETS
  talker
  listener
  DESTINATION lib/${PROJECT_NAME}
)
 
ament_package()

package.xml

This file defines the metadata for the ROS 2 package

<?xml version="1.0"?>
<package format="3">
  <name>demo_nodes_cpp</name>
  <version>0.0.1</version>
  <description>ROS 2 demo package for talker and listener</description>
  <maintainer email="ros2@example.com">Your Name</maintainer>
  <license>Apache-2.0</license>
  
  <buildtool_depend>ament_cmake</buildtool_depend>
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

src/talker.cpp

The actual executable that publishes a message on a topic. Here’s a basic version of talker.cpp:

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
 
using namespace std::chrono_literals;
 
class Talker : public rclcpp::Node
{
public:
  Talker()
  : Node("talker")
  {
    publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);
    timer_ = this->create_wall_timer(
      500ms, std::bind(&Talker::timer_callback, this));
  }
 
private:
  void timer_callback()
  {
    auto message = std_msgs::msg::String();
    message.data = "Hello, ROS 2!";
    publisher_->publish(message);
    RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
  }
  
  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
};
 
int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<Talker>());
  rclcpp::shutdown();
  return 0;
}

This file defines a Talker class that creates a publisher for a std_msgs/msg/String message on the "chatter" topic. The message is published every 500ms.

launch/topics/talker_listener.launch.py

"""Launch a talker and a listener."""
 
from launch import LaunchDescription
import launch_ros.actions
 
 
def generate_launch_description():
    return LaunchDescription([
        launch_ros.actions.Node(
            package='demo_nodes_cpp', executable='talker', output='screen'),
        launch_ros.actions.Node(
            package='demo_nodes_cpp', executable='listener', output='screen'),
    ])
  • Launch a talker and a listener
    ros2 launch demo_nodes_cpp talker_listener.launch.py

Run Basic Talker & Listener

Run a basic ROS 2 publisher and subscriber that exchanges the string message Hello World: <count_> with an incrementing integer

  • Run talker node
ros2 run demo_nodes_cpp talker
[INFO] [1735955684.018815006] [talker]: Publishing: 'Hello World: 1'
[INFO] [1735955685.018882451] [talker]: Publishing: 'Hello World: 2'
[INFO] [1735955686.018849702] [talker]: Publishing: 'Hello World: 3'
[INFO] [1735955687.018847096] [talker]: Publishing: 'Hello World: 4'
  • Run listener node
# Open new terminal
ros2 run demo_nodes_cpp listener
[INFO] [1735955688.803900442] [listener]: I heard: [Hello World: 5]
[INFO] [1735955689.019115784] [listener]: I heard: [Hello World: 6]
[INFO] [1735955690.019214378] [listener]: I heard: [Hello World: 7]

Run Talker & Listener on separate machines