How to create a simple Publisher Node with Python – ROS

In this guide, we’ll build a simple publisher node using Python in ROS.
The node will periodically publish a string message on a topic.

We’ll explain every step clearly and line-by-line, so even if you’re new to ROS you can follow along.

🔍  What is a ROS Node and a Topic?

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.

🚀 What We’ll Build

We’ll:

  • Create a new Python package inside an existing ROS workspace

  • Write a publisher node in Python

  • 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

📦 Prerequisite: A ROS Workspace

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.

📦 Create a New Package

Inside your workspace’s src folder:

				
					cd ~/catkin_ws/src
catkin_create_pkg tutorial_publisher std_msgs rospy

				
			

This creates a new package with dependencies on:

  • std_msgs for message types like String

  • rospy the Python client library for ROS

📄 Write the Publisher Node

Create a scripts/ directory and the Python script inside:

				
					cd tutorial_publisher
mkdir scripts
touch scripts/simple_publisher.py
chmod +x scripts/simple_publisher.py

				
			

Now open simple_publisher.py and write:

				
					#!/usr/bin/env python

import rospy
from std_msgs.msg import String

def publisher():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('simple_publisher_py', anonymous=True)
    rate = rospy.Rate(10)  # 10Hz

    counter = 0
    while not rospy.is_shutdown():
        msg_str = "Hello world %d" % counter
        rospy.loginfo(msg_str)
        pub.publish(msg_str)
        rate.sleep()
        counter += 1

if __name__ == '__main__':
    try:
        publisher()
    except rospy.ROSInterruptException:
        pass

				
			

🔍 Code Explained Step by Step

Let’s carefully go through this code line by line.

Shebang

				
					#!/usr/bin/env python

				
			

Tells Linux to execute the file using the Python interpreter.

Imports

				
					import rospy
from std_msgs.msg import String

				
			
  • rospy is the ROS 1 Python client library.

  • String is a message type from std_msgs.

Publisher Function

				
					def publisher():

				
			

Defines the main function for the publisher node.

Create Publisher

				
					pub = rospy.Publisher('chatter', String, queue_size=10)

				
			
  • Creates a publisher that sends messages of type String to the topic 'chatter'.

  • queue_size buffers up to 10 messages if subscribers can’t keep up.

Initialize Node

				
					rospy.init_node('simple_publisher_py', anonymous=True)

				
			

Initializes a new ROS node called simple_publisher_py.

  • anonymous=True ensures unique node names in case multiple instances run.

Set Publish Rate

				
					rate = rospy.Rate(10)  # 10 Hz

				
			

Defines a Rate object to control the loop frequency (10 times per second).

Message Counter

				
					counter = 0

				
			

Simple counter to number messages.

Main Loop

				
					while not rospy.is_shutdown():

				
			

Loops until ROS is shut down (via Ctrl+C or shutdown signals).

Publish a Message

				
					msg_str = "Hello world %d" % counter
rospy.loginfo(msg_str)
pub.publish(msg_str)

				
			
  • Formats a message string with the current counter.

  • Logs it to the terminal.

  • Publishes it to the topic.

Sleep

				
					rate.sleep()

				
			

Sleeps just enough to maintain the desired publish rate (10 Hz).

Increment Counter

				
					counter += 1

				
			

Increases message number for next iteration.

Exception Handling

				
					if __name__ == '__main__':
    try:
        publisher()
    except rospy.ROSInterruptException:
        pass

				
			
  • Runs the publisher() function.

  • Cleanly handles ROS shutdown events.

🛠️ Build the Package

From your workspace root:

				
					cd ~/ros_cpp_ws
catkin_make
source devel/setup.bash

				
			

🚀 Run the Publisher

First, start the ROS master:

				
					roscore

				
			

Then, in a new terminal:

				
					source ~/catkin_ws/devel/setup.bash
rosrun tutorial_publisher simple_publisher.py

				
			

📡 Monitor the Topic

In another terminal:

 
				
					rostopic list

				
			

Then, in a new terminal:

				
					/chatter
/rosout
/rosout_agg
				
			

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.

Want to learn more?

You can find a detailed explaination of the workspace in the "Robotics and ROS 2 - Learn by Doing! Manipulators" course
DISCOUNT
en_US