Skip to main content

Nodes, Topics, Services

In this section, we'll explore the fundamental communication patterns in ROS 2: nodes, topics, and services. These concepts form the backbone of robotic applications and enable different components to work together seamlessly.

Nodes

A node is an executable process that works as part of a ROS 2 system. Nodes are the basic building blocks of a ROS 2 application and perform specific tasks. In a humanoid robot system, you might have nodes for:

  • Sensor processing
  • Motor control
  • Path planning
  • Perception
  • Behavior management

Creating a Node

Here's a basic example of a ROS 2 node in Python:

import rclpy
from rclpy.node import Node

class MinimalPublisher(Node):

def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0

def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1

def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
minimal_publisher.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Topics

Topics enable asynchronous communication between nodes through a publish/subscribe model. Nodes can publish messages to topics and subscribe to topics to receive messages. This pattern is ideal for continuous data streams like sensor readings or motor commands.

Topic Communication Example

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

class Talker(Node):

def __init__(self):
super().__init__('talker')
self.publisher = self.create_publisher(String, 'chatter', 10)
timer_period = 0.5
self.timer = self.create_timer(timer_period, self.timer_callback)

def timer_callback(self):
msg = String()
msg.data = 'Hello World'
self.publisher.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)

# Subscriber node
class Listener(Node):

def __init__(self):
super().__init__('listener')
self.subscription = self.create_subscription(
String,
'chatter',
self.listener_callback,
10)
self.subscription # prevent unused variable warning

def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)

Services

Services provide synchronous request/response communication between nodes. Unlike topics, services are used for specific requests that require a response, such as requesting a specific action or configuration change.

Service Example

# Service server
from example_interfaces.srv import AddTwoInts

class AddTwoIntsServer(Node):

def __init__(self):
super().__init__('add_two_ints_server')
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)

def add_two_ints_callback(self, request, response):
response.sum = request.a + request.b
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
return response

# Service client
class AddTwoIntsClient(Node):

def __init__(self):
super().__init__('add_two_ints_client')
self.cli = self.create_client(AddTwoInts, 'add_two_ints')
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info('service not available, waiting again...')
self.req = AddTwoInts.Request()

def send_request(self, a, b):
self.req.a = a
self.req.b = b
self.future = self.cli.call_async(self.req)
rclpy.spin_until_future_complete(self, self.future)
return self.future.result()

Actions

Actions are used for long-running tasks that may take time to complete and provide feedback during execution. They're particularly useful for tasks like navigation or manipulation that require ongoing communication about progress.

Best Practices

  • Use topics for continuous data streams (sensor data, motor commands)
  • Use services for specific requests that need immediate responses
  • Use actions for long-running tasks that require feedback
  • Keep message types consistent across your system
  • Use appropriate Quality of Service (QoS) settings for your use case

Exercise

Create a simple ROS 2 package with a publisher node that publishes joint positions for a humanoid robot and a subscriber node that logs these positions to the console.