Custom Server/Client Example¶
This page contains examples on how to create custom ROS server/client classes using the parent
the ROSServiceServer
and ROSServiceClient
classes described previously. In general, a server/client model is
preferred over a publisher/subscriber one when a task requires execution at certain times specified by the user.
In this example, we’ll create a custom ROS service server and client classes. The client will request the age of a person.
Defining Name Message Class¶
In the root folder of your package, create a new directory called srv
and a file that will contain the
definition of the Age service class.
$ mkdir srv
$ touch Age.srv
Next we’ll define the service message. Open the Age.srv
file and write the following
string name
---
int8 age
This is our simple service class we’ll be publishing. The ---
separates the request made by the client (top) and
the response given by the server (bottom). As with the publisher/subscriber example, name
and age
are attributes
of this service class.
ROSServiceServer¶
First we’ll make the server. We’ll do this in a new file within the package ‘src’ folder called age_server.py.
from Age.srv import AgeResponse
class AgeServer(ROSServiceServer):
def __init__(self, _service_name, _service_type):
# only need to redefine __init__ if extending functionality
super(AgeServer, self).__init__(_service_name, _service_type)
self.ages = {} # dictionary
rospy.loginfo("Created a new Age service server")
def add_person(person, age):
self.ages[person] = age
def callback(self, request):
rospy.loginfo("Received request to get age of %s", request.name)
try:
age = self.ages[request.name]
return AgeResponse(age)
except KeyError as e:
rospy.logerr(e)
return AgeResponse(-1)
ROSServiceClient¶
Next we’ll create the client, also in the ‘src’ folder. We’ll call the file age_client.py.
class AgeClient(ROSServiceClient):
def __init__(self, _service_name, _service_type):
# only need to redefine __init__ if extending functionality
super(AgeClient, self).__init__(_service_name, _service_type)
self.name_list = []
rospy.loginfo("Created a new Age service client")
def make_request(self, request):
server_response = self._call_service(request) # ROSServiceClient method to handle service call
if server_response is None:
rospy.loginfo("%s server response was none", self.service_name)
return None
elif server_response == -1:
rospy.loginfo("That person does not exist in the server records")
return server_response
else:
rospy.loginfo("%s is %s years old", request, str(server_response.age))
return server_response.age
Using the custom classes¶
To use these, classes we will create two ROS nodes, one for the server and one for the client.
First the server
#!/usr/bin/env python
import rospy
from my_package.srv import Age
from age_server import AgeServer
rospy.init_node("age_server")
server = AgeServer('age_service_server', Age)
server.add_person("Jono Falco", 52)
rospy.spin()
Next the client node.
#!/usr/bin/env python
import rospy
from my_package.srv import Age, AgeResponse
from age_client import AgeClient
rospy.init_node("age_client")
client = AgeClient('age_service_server', Age) # has to have the same service_name as server
age = client.make_request("Jono Falco")
if age != -1 and age is not None:
rospy.loginfo("Jono Falco is %s years old", str(age))
Now execute both, first the server and then the client.
Attention
Make sure that both files are executable. You can make a file executable with the following linux command chmod u+x <file_name>
.
$ rosrun my_package server_node.py
and in a new terminal window
$ rosrun my_package client_node.py
You should see the message Jono Falco is 52 years old
.