Skip to main content

ROS 2 Services

Introduction

ROS 2 Services provide a request-response communication pattern where a client sends a request and receives a response from a server. Unlike topics which provide asynchronous communication, services offer synchronous communication that's ideal for operations that need a direct response. This lesson will explore the concepts of services, clients, and servers in ROS 2.

Service Communication Overview

Services in ROS 2 implement a request-response pattern where:

  • Service Server provides a specific functionality and waits for requests
  • Service Client requests a specific functionality and waits for the response
  • Request/Response Messages define the data structure for communication

This synchronous pattern is appropriate for operations that need a definitive response before proceeding.

Service Flow

Client Node A → Request → Service Server → Response → Client Node A
Client Node B → Request → Service Server → Response → Client Node B

Creating Services and Clients

Here's an example of how to create a service server and client in Python:

Service Definition

First, you need a service definition file (typically in an srv package). For example, AddTwoInts.srv:

int64 a
int64 b
---
int64 sum

Service Server Example

import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class MinimalService(Node):
def __init__(self):
super().__init__('minimal_service')
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(
f'Incoming request\na: {request.a}, b: {request.b}\n'
f'Returning: {response.sum}'
)
return response

def main(args=None):
rclpy.init(args=args)
minimal_service = MinimalService()
rclpy.spin(minimal_service)
rclpy.shutdown()

if __name__ == '__main__':
main()

Service Client Example

import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class MinimalClient(Node):
def __init__(self):
super().__init__('minimal_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()

def main():
rclpy.init()
minimal_client = MinimalClient()
response = minimal_client.send_request(1, 2)
minimal_client.get_logger().info(
f'Result of add_two_ints: {response.sum}'
)
minimal_client.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Service Commands

Useful ROS 2 command-line tools for working with services:

ros2 service list                    # List all active services
ros2 service info <service_name> # Get information about a service
ros2 service call <service_name> <type> <args> # Call a service
ros2 service type <service_name> # Get the type of a service

When to Use Services vs Topics

Use services when you need:

  • Synchronous communication with guaranteed response
  • Action confirmation (e.g., "turn on/off device")
  • Data queries (e.g., "get current sensor values")
  • Operations with a clear success/failure result

Use topics when you need:

  • Asynchronous communication
  • Continuous data streams
  • Broadcast to multiple receivers
  • Decoupled communication patterns

Service-Quality of Service

Similar to topics, services also support QoS settings:

from rclpy.qos import qos_profile_services_default

# Use default service QoS profile
self.srv = self.create_service(
AddTwoInts,
'add_two_ints',
self.add_two_ints_callback,
qos_profile=qos_profile_services_default
)

Best Practices

  • Use services for operations that require a response
  • Handle service call timeouts appropriately
  • Design service interfaces to be idempotent when possible
  • Consider the performance implications of synchronous calls
  • Use appropriate service types from standard interfaces when available

Summary

ROS 2 Services provide a reliable request-response communication mechanism for robotic applications. Understanding when to use services versus topics is crucial for designing effective ROS 2 systems. In the next chapter, we'll explore how Python agents can interact with ROS controllers using rclpy.