Skip to main content

ROS 2 Services - Synchronous Communication in the Robotic Nervous System

What are ROS 2 Services?

A Service is a named interaction where a client node sends a request message and waits for a server node to respond synchronously with a single response message. Services provide synchronous, request-response communication and represent the "direct neural pathways" of the robotic nervous system, enabling specific queries and coordinated actions.

Key Characteristics of Services

Synchronous Communication

  • Client sends a request and waits for a response
  • Server processes the request and sends a response
  • Blocking communication until response is received

One-to-One Pattern

  • One service server responds to requests from client nodes
  • Each request gets a dedicated response
  • Direct connection between client and server during the call

Request/Response Types

  • Each service has a specific request message type
  • Each service has a specific response message type
  • Types are defined using .srv files

Creating Service Servers and Clients

Service Definition

First, define the service in a .srv file:

# AddTwoInts.srv
int64 a
int64 b
---
int64 sum

This defines:

  • Request: two integers a and b
  • Response: one integer sum

Service Server Example

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

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'Returning {response.sum}')
return response

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

try:
rclpy.spin(minimal_service)
except KeyboardInterrupt:
pass
finally:
minimal_service.destroy_node()
rclpy.shutdown()

Service Client Example

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

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(args=None):
rclpy.init(args=args)
minimal_client = MinimalClient()
response = minimal_client.send_request(2, 3)
minimal_client.get_logger().info(f'Result of add_two_ints: {response.sum}')
minimal_client.destroy_node()
rclpy.shutdown()

Service Commands

Listing Services

ros2 service list

Getting Service Information

ros2 service info /add_two_ints

Calling a Service (Command Line)

ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1, b: 2}"

Service Types

Common Built-in Service Types

  • std_srvs: Basic services (Empty, Trigger, SetBool, etc.)
  • example_interfaces: Example services (AddTwoInts, etc.)
  • Custom services defined in your packages

Creating Custom Service Types

Custom service types are defined in .srv files in the srv/ directory of a package:

# Custom service example: ComputePath.srv
geometry_msgs/Point start
geometry_msgs/Point goal
---
nav_msgs/Path path
bool success
string error_message

The request and response parts are separated by ---.

Advanced Service Features

Service Callback Groups

Control execution of service callbacks:

from rclpy.callback_groups import MutuallyExclusiveCallbackGroup

# Create a callback group
cb_group = MutuallyExclusiveCallbackGroup()

# Use the callback group when creating the service
self.srv = self.create_service(
AddTwoInts,
'add_two_ints',
self.add_two_ints_callback,
callback_group=cb_group
)

Service Quality of Service

Services have their own QoS settings:

from rclpy.qos import QoSProfile

# Services use specific QoS for service communication
self.srv = self.create_service(
AddTwoInts,
'add_two_ints',
self.add_two_ints_callback
)

Service Error Handling

Handle service call failures:

def send_request(self, a, b):
self.req.a = a
self.req.b = b
self.future = self.cli.call_async(self.req)

try:
rclpy.spin_until_future_complete(self, self.future, timeout_sec=5.0)
if self.future.done():
return self.future.result()
else:
self.get_logger().error('Service call timed out')
return None
except Exception as e:
self.get_logger().error(f'Service call failed: {e}')
return None

Service vs. Topic Comparison

FeatureTopicsServices
CommunicationAsynchronousSynchronous
PatternMany-to-manyOne-to-one
LatencyLow (fire and forget)Higher (wait for response)
ReliabilityBest effort or reliableReliable
Use CaseStreaming dataSpecific queries/commands

Service Performance Considerations

Latency

  • Services block until response is received
  • Consider using topics for high-frequency data
  • Design services to respond quickly

Concurrency

  • Multiple clients can call the same service
  • Service server processes requests sequentially by default
  • Consider using multiple callback groups for concurrency

Error Handling

  • Always handle service call failures
  • Implement timeouts to prevent indefinite blocking
  • Design services to handle errors gracefully

The Role of Services in the Robotic Nervous System

Services function as the synchronous communication mechanism in the robotic nervous system:

  • Configuration: Request specific configuration changes
  • Activation: Turn on/off specific behaviors or components
  • Queries: Request specific information that requires processing
  • Coordination: Synchronize actions between nodes

This synchronous communication pattern allows for reliable, coordinated robot behaviors where nodes need to wait for confirmation before proceeding.

Common Service Patterns

Parameter Configuration

Change parameters of a node or system component.

Activation/Deactivation

Turn on/off specific robot behaviors or subsystems.

Data Queries

Request specific processed data that requires computation.

Action Coordination

Coordinate multi-step processes that require acknowledgment.

Service Best Practices

Response Time

  • Keep service responses fast
  • For long computations, consider using Actions instead
  • Provide feedback if processing will take time

Error Handling

  • Handle all possible error conditions
  • Provide meaningful error messages
  • Use appropriate return codes

Robustness

  • Handle multiple simultaneous requests
  • Validate input parameters
  • Clean up resources properly

Next Steps

Now that you understand ROS 2 Services, continue to learn about:

  • URDF: How to describe robot structure and components
  • Architecture: How nodes, topics, and services work together in the ROS 2 graph
  • Hello World Tutorial: Practical implementation of publisher/subscriber patterns