Encontrando e chamando serviços a partir da linha comando

Sumário

  1. Listando todos os serviços
  2. Listando serviços por nó
  3. Encontrando o nó que oferece um serviço
  4. Encontrando o tipo de dado de um serviço
  5. Inspecionando os tipos de dados de serviço
  6. Chamando serviços a partir da linha de comando

Muito embora serviços sejam mais comumente utilizados em códigos dentro de nós, existem algumas ferramentas de linha de comando para interagir com eles. Experimentar essas ferramentas pode tornar mais fácil entender o funcionamento das chamadas de serviço.

Listando todos os serviços

Você pode obter a lista de serviços atualmente ativos utilizando este comando:

rosservice list

No computador do autor, somente com um nó turtlesim em execução, a lista de serviços é a seguinte:

/clear
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level

Cada linha mostra o nome de um serviço que está atualmente disponível para ser chamado. Nomes de serviço são nomes de recursos gráficos, e como outros nomes de recursos gráficos podem ser especificados como nomes globais, relativos, ou privados. A saída da lista rosservice mostra o nome global completo de cada serviço.

Os serviçoes nesse exemplo, e muitos outros serviços ROS no geral, podem ser divididos em dois tipos básicos.

  • Alguns serviços, tais como o get_loggers e o set_logger_level na lista acima, são usados para obter informações a partir de nós específicos ou para passar informações para eles. Esses tipos de serviços normalmente usam os seus nomes de nó como um namespace para evitar conflito de nomes, e para permitir que seus nós ofereçam eles por meio de nomes privados como ∼get_loggers ou ∼set_logger_level. (Veja a Seção 4.5 para mais detalhes sobre log e níveis de log.)
  • Outros serviços representam capacidades mais gerais que não são conceitualmente ligadas a qualquer nó em particular. Por exemplo, o serviço chamado /spawn, que cria uma tartaruga, é oferecida pelo nó turtlesim. No entanto, em um sistema diferente, esse serviço poderia concebivelmente ser oferecido por um nó diferente; quando chamamos o /spawn, nós somente nos importamos que uma nova tartaruga é criada, e não com os detalhes de qual nó faz tal trabalho. Todos os serviços na lista acima, exceto o get_loggers e o set- _logger_level, encaixam-se nessa descrição. Esses tipos de serviços tipicamente têm nomes que descrevem sua função, mas isso não menciona nenhum nó em específico.

Listando serviços por nó

Para visualizar os serviços oferecidos por um nó específico, use o comando de informações rosnode info:

rosnode info node-name

Por exemplo, aqui está a porção relevante da saída deste comando para um nó turtlesim:

Services:
* /turtle1/teleport_absolute
* /turtlesim/get_loggers
* /turtlesim/set_logger_level
* /reset
* /spawn
* /clear
* /turtle1/set_pen
* /turtle1/teleport_relative
* /kill

Isso mostra, esperançosamente sem surpresa, que a maioria dos serviços que estão disponíveis são oferecidos pelo nó turtlesim. (As únicas exceções são os dois serviços de logging oferecidos pelo /rosout.)

Encontrando o nó que oferece um serviço

Para realizar a consulta reversa — isto é, ver qual nó oferece um dado serviço — use esse comando:

rosservice node service-name

Como esperado, esse comando exibe como saída o /turtlesim quando perguntado sobre quaisquer serviços listados pelo rosnode info /turtlesim, e /rosout quando perguntado sobre os outros dois serviços.

Encontrando o tipo de dado de um serviço

Você pode determinar o tipo de dado de um serviço utilizando um comando como esse:

rosservice info service-name

Por exemplo, a partir do comando

rosservice info /spawn

a saída é:

Node: /turtlesim
URI: rosrpc://donatello:47441
Type: turtlesim/Spawn
Args: x y theta name

Podemos ver que o tipo de dado do serviço /spawn é turtlesim/Spawn. Assim como tipos de mensagem, o tipo de dado de um serviço tem duas partes, uma nomeando o pacote que detém o tipo, e um nomeando o próprio tipo:


Tipos de dados de serviços são sempre referenciados por esses tipos de nome completos.

Inspecionando os tipos de dados de serviço

Podemos obter alguns detalhes sobre os tipos de dados de serviço usando o comando `rossrv:

rossrv show service-data-type-name

Por exemplo,

rossrv show turtlesim/Spawn

produz essa saída:

float32 x
float32 y
float32 theta
string name
---
string name

Neste caso, os dados antes dos traços (—) são os elementos da requisição. Essa é a informação que o nó cliente envia ao nó servidor. Tudo depois dos traços é a resposta, ou informações que o servidor envia de volta a partir do cliente quando o servidor terminou de agir na requisição.

⚠️ Tenha cuidado com a diferença entre rosservice e rossrv. O primeiro é para interagir com serviços são atualmente oferecidos por algum outro nó. O último — cujo nome vem da extensão .srv usada para arquivos que declaram os tipos de dados de serviço — é para solicitar sobre os tipos de dados de serviço, se há algum serviço disponível oferecido por algum nó que tem aquele tipo. A diferença é similar à diferença entre os comandos rostopic and rosmsg:

  Topics Services
coisas ativas rostopic rosservice
tipos de dados rosmsg rossrv

Note que a requisição, a resposta, ou ambas podem ser vazias. Por exemplo, no serviço /reset oferecido pelo turtlesim_node, o qual tem tipo std_srvs/Empty, tanto a parte de requisição como a parte de resposta são vazias. Isso é aproximadamente equivalente a uma função de C++ que não aceita argumentos e retorna vazio. Nenhuma informação entra ou sai, mas coisas úteis (isto é, efeitos colaterais) ainda podem acontecer.

Chamando serviços a partir da linha de comando

Para ter uma ideia de como os serviços funcionam, você pode chamá-los a partir da linha de comando utilizando esse comando:

rosservice call service-name request-content

A parte do conteúdo da requição deve listar valores para cada campo da requisição, como mostrado pelo rossrv show. Aqui vai um exemplo:

rosservice call /spawn 3 3 0 Mikey

O efeito dessa chamada de serviço é criar uma nova tartaruga chamada “Mikey”, na posição (x, y) = (3, 3) , com ângulo de face θ = 0 , dentro do simulador existente.

⚠️ Essa nova tartaruga vem com o seu próprio conjunto de recursos, incluindo serviços cmd_vel, pose, tópicos color_sensor e set_pen,teleport_absolute, teleport_relative. Estes novos recursos vivem em um namespace chamado — nesse exemplo — Mikey. Esses são adicionais aos recursos usuais do namespace turtle1, e são necessários para permitir a outros nós o controle individual das tartarugas separadamente. Isso ilustra bem a forma com a qual os namespaces podem previnir conflitos de nomes.

A saída da chamada do rosservice mostra os dados de resposta do servidor. Para o exemplo acima, a resposta deveria ser:

name: Mikey

Nesse caso, o servidos envia o novo nome da tartaruga de volta como parte da resposta.

Além de enviar os dados de resposta, o servidor também diz ao cliente se a chamada falhou ou teve sucesso. Por exemplo, no turtlesim, cada tartaruga deve ter um nome único. Se rodarmos a chamada exemplo rosservice duas vezes, a primeira chamada deveria ter sucesso, mas a segunda geraria um erro parecido com esse:

ERROR: service [/spawn] responded with an error:

O erro ocorre porque tentamos criar duas tartarugas com o mesmo nome.

⏩ Essa mensagem de erro termina com dois pontos porque o turtlesim respondeu com uma mensagem de erro vazia. A infraestrutura básica é capaz de retornar curtas strings de mensagem de erro quando o serviço falha, mas a biblioteca cliente C++, a qual o turtlesim está usando, não provê uma maneira fácil de retornar uma mensagem de erro não vazia.