CREATING PUBLISHER AND SUBSCRIBER NODE USING C++

 


Introduction.

In ROS2(Robot Operating System 2), a node is the smallest executable unit that performs computation. It is essentially a process that communicates with other nodes to exchange data (via topics, services, or actions) and perform tasks in a robotic system. ROS 2 publishers and subscribers are the basic communication mechanism between nodes using topics. They can be created by either using python or C++ language. In this blog we will be creating using C++.

 

Info

Prerequisites

Publisher-Subscriber Node in C++

1. Create a ROS 2 Package

cd ~ros2_ws/src ros2 pkg create --build-type ament_cmake cpp_pubsub --dependencies rclcpp std_msgs

This creates a new C++ package named cpp_pubsub.

2. Add Publisher and Subscriber code

Navigate into the package:

cd ~/ros2_ws/src/cpp_pubsub/src

Create the following files in the src/ directory:

  • src/talker.cpp

Key in the code below in the opened file above:

#include <chrono> // For time intervals like 500ms #include <memory> // For shared_ptr #include "rclcpp/rclcpp.hpp" // Core ROS 2 C++ client library #include "std_msgs/msg/string.hpp" // Message type used in the publisher using namespace std::chrono_literals; // Enables use of 500ms directly class Talker : public rclcpp::Node { public: Talker() : Node("talker_node"), count_(0) { publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10); timer_ = this->create_wall_timer(500ms, std::bind(&Talker::publish_message, this)); } private: void publish_message() { auto message = std_msgs::msg::String(); message.data = "Hello ROS2! Count: " + std::to_string(count_++); RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str()); publisher_->publish(message); } rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_; rclcpp::TimerBase::SharedPtr timer_; int count_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); // Initialize ROS rclcpp::spin(std::make_shared<Talker>()); // Run node rclcpp::shutdown(); // Clean up return 0; }
  • src/listener.cpp

Key in the code below in the opened file above:

#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" class Listener : public rclcpp::Node { public: Listener() : Node("listener_node") { subscription_ = this->create_subscription<std_msgs::msg::String>( "chatter", 10, [this](const std_msgs::msg::String::SharedPtr msg) { RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str()); }); } private: rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<Listener>()); rclcpp::shutdown(); return 0; }

3. Update CMakeLists.txt

Update CMakeLists.txt and add to make:

cmake_minimum_required(VERSION 3.8) project(cpp_pubsub) 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(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}) if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) set(ament_cmake_copyright_FOUND TRUE) set(ament_cmake_cpplint_FOUND TRUE) ament_lint_auto_find_test_dependencies() endif() ament_package()

4. Update package.xml

Update the code to have:

<?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_pubsub</name> <version>0.1.0</version> <description>TODO: Package description</description> <maintainer email="wambuacaleb253@gmail.com">caleb253</maintainer> <license>MIT</license> <buildtool_depend>ament_cmake</buildtool_depend> <depend>rclcpp</depend> <depend>std_msgs</depend> //Test dependencies <test_depend>ament_lint_auto</test_depend> <test_depend>ament_lint_common</test_depend> <export> <build_type>ament_cmake</build_type> </export> </package>

Ensure to include the dependencies if you did not include when creating the package.

<depend>rclcpp</depend> <depend>std_msgs</depend>

5. Build the Package.

From your workspace root:

cd ~/ros2_ws colcon build --packages-select cpp_pubsub

Then source your setup file:

source install/setup.bash

6. Run the Publisher and Subscriber.

In two separate terminals:

Terminal 1 (Publisher):
source ~/ros2_ws/install/setup.bash ros2 run cpp_pubsub talker

Terminal 2 (Subscriber):

source ~/ros2_ws/install/setup.bash ros2 run cpp_pubsub listener

You should be able to generate the results as shown below:

image-20250610-211821.png



To stop the runs you should press Ctrl+c

Common Errors in ROS 2 C++ Publisher/Subscriber Nodes


1. Build Fails: Missing Dependency

Error

fatal error: rclcpp/rclcpp.hpp: No such file or directory

Cause

You didn’t declare the dependency on rclcpp in CMakeLists.txt or package.xml.

Fix

In CMakeLists.txt:

find_package(rclcpp REQUIRED) target_link_libraries(your_node_name rclcpp::rclcpp)

In package.xml:

<build_depend>rclcpp</build_depend> <exec_depend>rclcpp</exec_depend>

2. Build Succeeds, but Node Crashes at Runtime

Symptom

Segmentation fault when running the node.

Common Causes

  • You forgot to initialize ROS before using the node.

  • You used a raw pointer without initializing it.

  • Missing rclcpp::spin(…) in main().

Fix

Always structure main() like this:

int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<MyNode>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }

3. Topic Mismatch: No Messages Received

Causes

  • Topic names differ ("chatter" vs "chat").

  • Mismatched message types.

  • Publisher or subscriber not active when tested.

Fix

Double-check both:

// Publisher this->create_publisher<std_msgs::msg::String>("chatter", 10); // Subscriber this->create_subscription<std_msgs::msg::String>("chatter", 10, callback);

 

Use ros2 topic list and ros2 topic info to inspect topic state.


4. CMake Errors: Target Not Found

Error

CMake Error: Target "talker" not found

Cause

You forgot to define the executable or link libraries.

Fix in CMakeLists.txt:

add_executable(talker src/talker.cpp) ament_target_dependencies(talker rclcpp std_msgs) install(TARGETS talker DESTINATION lib/${PROJECT_NAME})

5. "Could not find package configuration file"

Error

Could not find a package configuration file provided by "rclcpp"

Cause

Your environment isn't sourced properly.

Fix

source /opt/ros/humble/setup.bash source ~/ros2_ws/install/setup.bash

6. Nothing Is Published or Logged

Cause

  • rclcpp::TimerBase::SharedPtr not retained — it gets garbage-collected.

  • You forgot to create the timer or use rclcpp::spin().

Fix

In your class:

rclcpp::TimerBase::SharedPtr timer_; // define in class timer_ = this->create_wall_timer( std::chrono::seconds(1), std::bind(&Talker::timer_callback, this));

7. Missing #include Statements

Error

‘cout’ was not declared in this scope

Cause

You’re using standard C++ things (like std::cout) but forgot the includes.

Fix

#include <iostream>

Similarly, always include:

#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp"

8. Publisher Not Publishing

Cause

You forgot to store the publisher as a class member.

Fix

rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_; publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);

If you declare the publisher inside a function (local scope), it will go out of scope and stop working.


9. Wrong ament_target_dependencies Syntax

Error

Unknown CMake command: ament_target_dependencies

Cause

  • You didn’t call find_package() before using ament_target_dependencies.

  • Typos in dependency names.

Fix

find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED)

ament_target_dependencies(your_node rclcpp std_msgs)

References

Comments

Popular posts from this blog

Getting Started with ROS2 Humble: Workspace, Packages, and Nodes

Introduction to ROS 2: The Future of Robotics Software

CREATING A PUBLISHER AND SUBSCRIBER NODES USING PYTHON