In this tutorial, we’ll learn how to create a simple ROS node using C++ that sends text messages to a topic.
This is one of the fundamental skills in the ROS ecosystem — allowing different programs (called nodes) to talk to each other via topics.
In ROS (Robot Operating System), software is organized into small, independent processes called nodes.
Nodes communicate by publishing and subscribing to topics — named channels that carry specific types of data.
For example:
A camera node might publish images on /camera/image_raw
A motor controller might subscribe to /cmd_vel
to receive movement commands.
Nodes and topics decouple your software, so different parts of your robot can evolve independently and work together via message passing.
We’ll:
Create a new C++ package inside an existing ROS workspace
Write a publisher node in C++
Build and run it
Monitor its output via ROS command-line tools
The node will:
Publish a string message on a topic named /chatter
Run in a loop at a fixed frequency
Display a counter alongside the message
If you haven’t created a ROS workspace yet, follow this clear tutorial first:
How to Create a ROS2 Workspace
Once your workspace is ready and sourced, continue from here.
Inside your workspace’s src
folder:
cd ~/ros_cpp_ws/src
catkin_create_pkg tutorial_publisher roscpp std_msgs
Explanation:
tutorial_publisher
is the package name.
roscpp
is the C++ client library for ROS.
std_msgs
provides standard message types like strings and numbers.
Now your project structure looks like:
Let’s create a new C++ file inside src/
:
cd ~/ros_cpp_ws/src/tutorial_publisher/src
touch simple_publisher.cpp
Open it in your text editor, and paste the following code:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include
int main(int argc, char **argv)
{
ros::init(argc, argv, "simple_publisher_cpp");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise("chatter", 10);
ros::Rate loop_rate(10);
int counter = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "Hello world " << counter;
msg.data = ss.str();
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++counter;
}
return 0;
}
Let’s carefully go through this code line by line.
Include Required Headers
#include "ros/ros.h"
#include "std_msgs/String.h"
#include
ros/ros.h
→ core ROS C++ library.
Provides functions for initializing ROS, creating publishers, setting rates, etc.
std_msgs/String.h
→ defines a simple message type for sending strings.
<sstream>
→ C++ standard library class for creating string streams.
Used to format the message string with a counter.
Main Function
int main(int argc, char **argv)
This is the starting point of any C++ program.
The parameters argc
and argv
are used by ROS to process command-line arguments.
Initialize the ROS Node
ros::init(argc, argv, "simple_publisher_cpp");
Initializes the ROS node.
"simple_publisher_cpp"
is the unique name of this node within the ROS system.
Create a NodeHandle
ros::NodeHandle nh;
A NodeHandle is your connection to the ROS network.
You use it to create publishers, subscribers, and interact with the parameter server.
Define a Publisher
ros::Publisher pub = nh.advertise("chatter", 10);
Creates a publisher object called pub
.
It will send messages on a topic named "chatter"
with message type std_msgs::String
.
The 10
is the queue size: how many messages to buffer if the subscriber is too slow.
Set the Loop Rate
ros::Rate loop_rate(10);
Controls the frequency of the loop.
10
means the loop runs 10 times per second (10Hz).
Initialize a Counter
int counter = 0;
Tracks the number of messages published.
Added to the message text so each message is unique.
Main Publishing Loop
while (ros::ok())
Runs as long as ROS is active.
Exits cleanly if the node is shut down with Ctrl+C
or rosnode kill
.
Inside the loop:
Create a Message
std_msgs::String msg;
Declares a message object of type std_msgs::String
.
Prepare the Message Text
std::stringstream ss;
ss << "Hello world " << counter;
msg.data = ss.str();
Uses a stringstream to build the message text by appending the counter.
Assigns the final string to the message’s data
field.
Publish the Message
pub.publish(msg);
Sends the message out on the "chatter"
topic.
Process ROS Callbacks
ros::spinOnce();
Checks for any incoming messages or service callbacks.
Not strictly necessary for a simple publisher with no subscribers, but good practice.
Sleep to Maintain Loop Rate
loop_rate.sleep();
Waits to ensure the loop runs exactly at 10Hz.
Increment the Counter
++counter;
Increases the counter by 1 for the next message.
Exit the Program
return 0;
Cleanly exits the program when the loop finishes.
Open your CMakeLists.txt
and add:
add_executable(simple_cpp_publisher src/simple_publisher.cpp)
target_link_libraries(simple_cpp_publisher
${catkin_LIBRARIES}
)
This tells CMake how to build your program and link it with ROS libraries.
From your workspace root:
cd ~/ros_cpp_ws
catkin_make
source devel/setup.bash
First, start the ROS master:
roscore
Then, in a new terminal:
source ~/ros_cpp_ws/devel/setup.bash
rosrun tutorial_publisher simple_cpp_publisher
In another terminal:
rostopic list
Then, in a new terminal:
/chatter
/rosout
Check the messages being published:
rostopic echo /chatter
You’ll see:
data: "Hello world 0"
data: "Hello world 1"
...
Check topic information:
rostopic info /chatter
Check message frequency:
rostopic hz /chatter
It should report a rate around 10Hz.