Um Service diferente de Topics é uma comunicação bilateral. Nele temos um Client que envia uma solicitação e um Server que envia de volta a resposta. Essa comunicação é feita de forma síncrona, ou seja, quando um Client envia uma solicitação ele espera até que haja uma resposta do Server.
Um bom exemplo de ROS Service é dado através da interface turtlesim, para instalá-la use o comando adequado para sua versão ROS, nesse caso noetic.
$ sudo apt-get install ros-noetic-turtlesim
$ sudo rosdep init
$ rosdep update
Para iniciá-lo comece pela inicialização do ROS e em um novo terminal abra a interface
$ roscore
$ rosrun turtlesim turtlesim_node
Uma interface como essa deve aparecer
Em um terminal, é possível ver todos os services atualmente ativos com
$ rosservice list
Será visto nessa lista um service de nome /spawn cujo detalhes pode ser expandido com $ rosservice info /spawn
O seu tipo de mensagem é turtlesim/Spawn e seus argumentos x, y, theta e name são a localização e direção para o aparecimento de uma nova tartaruga na tela e o nome dado a ela.
Com $ rossrv info turtlesim/spawn é possível ver informações detalhadas sobre o tipo de mensagem do serviço
Podemos chamar esse serviço com o comando
$ rosservice call /spawn 7 7 0 t2
Nesse caso uma nova tartaruga deve aparecer na posição (x,y) = (7,7) rotacionada de 0 graus com nome t2 cuja informação é retornada no terminal como resposta.
Também é possível criar seu próprio serviço, aqui criaremos uma aplicação Client/Server onde o cliente envia 2 inteiros ao servidor que retorna a soma.
Em seu workspace, no diretório do pacote onde realiza suas aplicações, no nosso caso ros_essentials_cpp, deverá ser criado uma pasta de nome srv, nessa pasta criaremos um arquivo de nome AddTwoInts.srv que deverá ser preenchido com as seguintes linhas:
_____________________
int64
int b
—
int64 sum
_____________________
Os passos seguintes são reproduzidos igualmente em ROS messages e podem ser pulados com exceção do add_service_files caso já os tenha realizado.
Para que o serviço possa ser usado através de mensagens é necessário atualizar as dependências em CMakeLists.txt adicionando a linha message_generation no campo seguinte:
########################################
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
#######################################
Ainda em CMakeLists.txt adicionar o nome do arquivo criado no campo seguinte:
####################
add_service_files(
FILES
AddTwoInts.srv
)
####################
Agora em package.xml adicionar nos locais adequados (de acordo com a sintaxe) as linhas :
<build_depend>message_generation</build_depend>
e
<exec_depend>message_runtime</exec_depend>
Para finalizar é necessário no diretório do workspace realizar um catkin_make. E agora novos arquivos podem ser observados no diretório /catkin_ws/devel/include/ros_essentials_cpp
Agora, o código seguinte refere-se ao Server add_server.py criado em python que retorna a resposta
#################################################################
1 #!/usr/bin/env python
2
3 from ros_essentials_cpp.srv import AddTwoInts
4 from ros_essentials_cpp.srv import AddTwoIntsRequest
5 from ros_essentials_cpp.srv import AddTwoIntsResponse
6
7 import rospy
8
9 def handle_add_two_ints(req):
10 print “Returning [%s + %s = %s]”%(req.a, req.b, (req.a + req.b))
11 return AddTwoIntsResponse(req.a + req.b)
12
13 def add_two_ints_server():
14 rospy.init_node(‘add_two_ints_server’)
15 s = rospy.Service(‘add_two_ints’, AddTwoInts, handle_add_two_ints)
16 print (“Ready to add two ints.”)
17 rospy.spin()
18
19 if __name__ == “__main__”:
20 add_two_ints_server()
###########################################################
O primeiro passo é importar os arquivos de service, request e response criados. O serviço é criado na linha 15 e tem como parâmetros o nome do serviço criado, o tipo de serviço e a função que será executada sempre que houver uma nova solicitação. Essa função (linha 9) é a responsável por retornar a soma dos inteiros passados.
A seguir o código do Client add_client.py que faz a solicitação
########################################################
1 #!/usr/bin/env python
2
3 import sys
4 import rospy
5 from ros_essentials_cpp.srv import AddTwoInts
6 from ros_essentials_cpp.srv import AddTwoIntsRequest
7 from ros_essentials_cpp.srv import AddTwoIntsResponse
8
9 def add_two_ints_client(x, y):
10 rospy.wait_for_service(‘add_two_ints’)
11 try:
12 add_two_ints = rospy.ServiceProxy(‘add_two_ints’, AddTwoInts)
13 resp1 = add_two_ints(x, y)
14 return resp1.sum
15 except rospy.ServiceException, e:
16 print “Service call failed: %s”%e
17
18 def usage():
19 return “%s [x y]”%sys.argv[0]
20
21 if __name__ == “__main__”:
22 if len(sys.argv) == 3:
23 x = int(sys.argv[1])
24 y = int(sys.argv[2])
25 else:
26 print usage()
27 sys.exit(1)
28 print “Requesting %s+%s”%(x, y)
29 s = add_two_ints_client(x, y)
30 print “%s + %s = %s”%(x, y, s)
#########################################################
Para iniciar é necessário esperar o serviço para começar (linha 10) caso contrário não será possível rodar a aplicação. Na linha 12 é criado o service proxy que é responsável por enviar informação ao server e tem como parâmetros o nome do serviço definido anteriormente e o tipo.
Agora em 2 novos terminais é possível conferir a aplicação, no primeiro fazer
$ rosrun ros_essentials_cpp add_server.py
e no segundo
$ rosrun ros_essentials_cpp add_client.py 1 2
Nota-se que os inteiros que serão somados foram passados no comando do cliente e a resposta retornada deverá ser 1 + 2 = 3
Dessa forma está feito um novo ROS Service.