Service communication

This chapter discusses service communication, which was briefly introduced in the preceding section. In contrast to topic communication which is conceptually data streaming to many subscribers, Service communication is fulfilled only when a client (caller of a service) receives the response from the server.

Service Interface

Before proceeding, run turtlesim_node executable. 🐢

ros2 run turtlesim turtlesim_node

Examine Registered Services

We can list the names of services by:

Names of registered service communications
rosmarry@rosmarry:~$ ros2 service list # get names of service communications
/clear
/kill
/reset
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically

Note that the list consists of registrations from both servers and clients. For example, if a node has a client who wants to call a service named /some_service, the command ros2 service list includes /some_service.

Communication registrations of /turtlesim
rosmarry@rosmarry:~$ ros2 node info /turtlesim
/turtlesim
  Subscribers:
    ...
  Publishers:
    ...
  Service Servers: # registrations of service servers
    /clear: std_srvs/srv/Empty
    /kill: turtlesim/srv/Kill
    /reset: std_srvs/srv/Empty
    /spawn: turtlesim/srv/Spawn
    /turtle1/set_pen: turtlesim/srv/SetPen
    /turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
    /turtle1/teleport_relative: turtlesim/srv/TeleportRelative
    /turtlesim/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /turtlesim/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /turtlesim/get_parameters: rcl_interfaces/srv/GetParameters
    /turtlesim/list_parameters: rcl_interfaces/srv/ListParameters
    /turtlesim/set_parameters: rcl_interfaces/srv/SetParameters
    /turtlesim/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
  Service Clients: # registrations of service clients (currently none)

In contrast to topic names, service communications seem to be giving a command as their names indicate (e.g., /clear, /spawn or /turtle1/set_pen).

Service Types

As we learned here, topic communication can be described by fields of message contents. For example,

Getting type of /spawn service
rosmarry@rosmarry:~$ ros2 service type /spawn # ros2 service type <service_name>
turtlesim/srv/Spawn # <package_name>/srv/<service_type_name>

/spawn is described by turtlesim/srv/Spawn, which equals to:

Getting service type
rosmarry@rosmarry:~$ ros2 interface show turtlesim/srv/Spawn # ros2 interface show <service_type_name>
float32 x
float32 y
float32 theta
string name # Optional.  A unique name will be created and returned if this is empty
---
string name

In contrast to the topic interface, the service description is divided into two sections: request and response.

Calling a Service

As the above description shows, the request of /spawn was described by x,y,theta and name. Before proceeding, confirm the below:

Topic list when only single turtle
rosmarry@rosmarry:~$ ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

Now, we call the /spawn service by:

ros2 service call /spawn turtlesim/srv/Spawn "{x: 3, y: 3, theta: 0, name: "turtle2"}"

This will output the below communication result:

Output of calling spawn service
rosmarry@rosmarry:~$ ros2 service call /spawn turtlesim/srv/Spawn "{x: 3, y: 3, theta: 0, name: "turtle2"}"
requester: making request: turtlesim.srv.Spawn_Request(x=3.0, y=3.0, theta=0.0, name='turtle2')
 
response:
turtlesim.srv.Spawn_Response(name='turtle2')

As the description, response outputs name. Now our turtle turtle1 has a friend turtle2 as the figure shows:

A few more topics were added also:

Topic list after turtle2 spawned
rosmarry@rosmarry:~$ ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
/turtle2/cmd_vel
/turtle2/color_sensor
/turtle2/pose
ℹ️

A homework. In this section, we published topic /turtle1/cmd_vel to make the turtle circle around. Try on your own to move the second turtle we've spawned.

Using GUI Tool (rqt_gui)

In a similar way to topic publishing in rqt_gui, we can call a service easily as the video demonstrates:

Service Request from Node

As a service caller (client) is a kind of communication object, a node can request a service. To observe this, make sure you have two turtles. Run our new executable draw_square by:

Run draw_square executable
 
rosmarry@rosmarry:~$ ros2 run turtlesim draw_square
[INFO] [1692020201.521227190] [draw_square]: New goal [7.544445 5.544445, 0.000000]
[INFO] [1692020203.473165793] [draw_square]: Reached goal
[INFO] [1692020203.473228893] [draw_square]: New goal [7.448444 5.544445, 1.570796]

Up on the start of the associated node, the turtle2 is removed and the turtle tries to follow a square. Why the turtle2 was removed?

List of communications of /draw_square
rosmarry@rosmarry:~$ ros2 node info /draw_square
/draw_square
  Subscribers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /turtle1/pose: turtlesim/msg/Pose
  Publishers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log
    /turtle1/cmd_vel: geometry_msgs/msg/Twist
  Service Servers:
    /draw_square/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /draw_square/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /draw_square/get_parameters: rcl_interfaces/srv/GetParameters
    /draw_square/list_parameters: rcl_interfaces/srv/ListParameters
    /draw_square/set_parameters: rcl_interfaces/srv/SetParameters
    /draw_square/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
  Service Clients:
    /reset: std_srvs/srv/Empty
  Action Servers:
 
  Action Clients:

As shown in the above output, the node /draw_square had a service caller for /reset which resets /turtlesim to the initial scene (having a single turtle turtle1). In fact this service is called inside /draw_square when the node starts (opens in a new tab). Note that you do not need to understand the code.