Tech Arcanist
Get in touch

06Chapter 6 of 51

ROS 2 Python Publisher

A ROS 2 publisher node sends messages to a topic at a defined frequency. In this example, the Python node publishes String messages to the chatter topic at 1 Hz, with each message containing an incrementing counter.

The section also covers the basic ROS 2 commands used to inspect the topic, view its messages, check publisher/subscriber information, and verify the message publishing frequency.

Open Visual Studio Code

What you do

  1. Open Visual Studio Code
  2. Click Open Folder

Now

  1. Select: bumperbot_ws
  2. Click Yes, I trust the authors

Inside VS Code, go step by step:

src
└── bumperbot_py_examples
└── bumperbot_py_examples

Why two folders with same name?

  • Outer folder → ROS 2 package
  • Inner folder → Python module (source code)

Create the Python Node File

What you do

  • Right-click on inner bumperbot_py_examples
  • Click New File
  • Name it:
simple_publisher.py

This file will contain our ROS 2 node code.

Code for simple_publisher.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class SimplePublisher(Node):
    def __init__(self):
        super().__init__("simple_publisher")

        self.pub_ = self.create_publisher(String, "chatter", 10)

        self.counter_ = 0
        self.frequency_ = 1.0

        self.get_logger().info("Publishing at %d Hz" % self.frequency_)
        self.timer_ = self.create_timer(self.frequency_, self.timerCallback)

    def timerCallback(self):
        msg = String()
        msg.data = "Hello ROS 2 - counter: %d" % self.counter_

        self.pub_.publish(msg)
        self.counter_ += 1

def main():
    rclpy.init()

    simple_publisher = SimplePublisher()
    rclpy.spin(simple_publisher)
    
    simple_publisher.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

simplepublisher.py code

Explanation for simple_publisher.py

Register Node in setup.py

Open: bumperbot_py_examples/setup.py

Add within the entry points

'simple_publisher = bumperbot_py_examples.simple_publisher:main'
  • simple_publisher → ROS 2 executable name
    • Used in terminal with:
      • ros2 run bumperbot_py_examples simple_publisher
    • Can be renamed to anything
  • bumperbot_py_examples → ROS 2 package name
  • simple_publisher → Python file name (simple_publisher.py)
  • main → function name inside that file
  • Format:
    • executable_name = package.python_file:function
  • When executed, ROS:
    • Finds the package
    • Loads the Python file
    • Calls the main() function

Declare Dependencies (package.xml)

Open: bumperbot_py_examples/package.xml

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  • Tells ROS 2 which libraries this node needs

Build the Workspace

cd bumperbot_ws/
colcon build

Converts Python script into ROS 2 executable

Source the Workspace

. install/setup.bash
  • Makes ROS 2 aware of your new node
  • Must be done per terminal

Run the Node

ros2 run bumperbot_py_examples simple_publisher
  • Node starts
  • Messages published at 1 Hz

Inspect Topics

List topics

ros2 topic list
  • Shows all active topics in the ROS 2 system
  • Topics appear only if some node is using them
  • /chatter → your publisher is running
  • If /chatter is NOT listed → publisher is not active

Use this when

  • You want to check which topics exist
  • You want to verify your node is publishing

View messages

ros2 topic echo /chatter
  • Prints live messages from a topic
  • Works like “listen to this topic”

What happens

  • Subscribes temporarily to /chatter
  • Displays messages as they arrive
  • ros2 → use ROS 2 CLI
  • topic → work with topics
  • echo → listen & print messages
  • /chatter → from this topic

Topic details

ros2 topic info /chatter --verbose
  • You use this command to:
    • Check who is publishing
    • Check who is subscribing
    • Check message type
    • Check QoS settings
    • Debug communication issues

Check frequency

ros2 topic hz /chatter

Measure how fast messages are coming on a topic.

What output looks like

average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00016s window: 3
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00018s window: 4
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00019s window: 6
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00017s window: 7
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00016s window: 8
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00022s window: 10
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00021s window: 11
average rate: 1.000