Skip to main content

Topics

Topics are the most common communication mechanism in ROS 2, providing a publish-subscribe model for asynchronous data streaming. They are ideal for broadcasting continuous data streams, such as sensor readings, robot odometry, video feeds, or status updates.

Publish-Subscribe Model

  • Publisher: A node that sends messages to a specific topic. It doesn't know (or care) which nodes are receiving the data.
  • Subscriber: A node that receives messages from a specific topic. It doesn't know (or care) which nodes are sending the data.
  • Topic Name: A unique string identifier for the communication channel (e.g., /camera/image_raw, /odom, /robot_status).
  • Message Type: Every topic has a defined message type (e.g., sensor_msgs/msg/Image, nav_msgs/msg/Odometry, std_msgs/msg/String). This ensures that publishers and subscribers agree on the data structure.

Creating a Publisher and Subscriber (Python Example)

Let's expand on our my_python_pkg from the Nodes section to create a publisher and subscriber.

First, define a custom message type (e.g., Num.msg) in a new package if you don't want to use standard messages. For simplicity, we'll use std_msgs/msg/String.

Publisher Node (talker_publisher.py)

Create ~/ros2_ws/src/my_python_pkg/my_python_pkg/talker_publisher.py:

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

class TalkerPublisher(Node):
def __init__(self):
super().__init__('talker_publisher')
self.publisher_ = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(0.5, self.timer_callback)
self.i = 0
self.get_logger().info('Talker Publisher Node started.')

def timer_callback(self):
msg = String()
msg.data = f'Hello ROS 2: {self.i}'
self.publisher_.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.i += 1

def main(args=None):
rclpy.init(args=args)
talker_publisher = TalkerPublisher()
rclpy.spin(talker_publisher)
talker_publisher.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Subscriber Node (listener_subscriber.py)

Create ~/ros2_ws/src/my_python_pkg/my_python_pkg/listener_subscriber.py:

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

class ListenerSubscriber(Node):
def __init__(self):
super().__init__('listener_subscriber')
self.subscription = self.create_subscription(
String,
'chatter',
self.listener_callback,
10)
self.subscription # prevent unused variable warning
self.get_logger().info('Listener Subscriber Node started.')

def listener_callback(self, msg):
self.get_logger().info(f'I heard: "{msg.data}"')

def main(args=None):
rclpy.init(args=args)
listener_subscriber = ListenerSubscriber()
rclpy.spin(listener_subscriber)
listener_subscriber.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Update setup.py

Add the new executables to ~/ros2_ws/src/my_python_pkg/setup.py under console_scripts:

    entry_points={
'console_scripts': [
'talker = my_python_pkg.talker_node:main', # Existing
'talker_publisher = my_python_pkg.talker_publisher:main',
'listener_subscriber = my_python_pkg.listener_subscriber:main',
],
},

Building and Running

  1. Build the workspace:
    cd ~/ros2_ws
    colcon build --packages-select my_python_pkg
    source install/setup.bash
  2. Run the publisher in one terminal:
    ros2 run my_python_pkg talker_publisher
  3. Run the subscriber in another terminal:
    ros2 run my_python_pkg listener_subscriber
    You should see the subscriber node printing the messages published by the talker node.

ros2 topic Commands

  • ros2 topic list: Lists all active topics.
  • ros2 topic info <topic_name>: Displays the message type, publishers, and subscribers for a topic.
  • ros2 topic echo <topic_name>: Prints messages being published on a topic to the console.
  • ros2 topic pub <topic_name> <message_type> <args>: Publishes data to a topic from the command line.

Topics are fundamental for building distributed and dynamic robotic systems, allowing different components to share information efficiently.