Tópicos e mensagens

Sumário

  1. Visualizando o gráfico
  2. Mensagens e tipos de mensagem
    1. Listagem de tópicos
    2. Ecoando mensagens
    3. Medindo taxas de publicação
    4. Inspecionando um tópico
    5. Inspecionando um tipo de mensagem
    6. Publicação de mensagens na linha de comando
    7. Nomes dos tipos de mensagens entendimento

Em nosso exemplo turtlesim, está claro que o nó de teleoperação e o nó do simulador devem estar se comunicando de alguma forma. Caso contrário, como a tartaruga, que vive no último nó, saberia quando se mover em resposta aos seus pressionamentos de tecla, que são coletados pelo primeiro nó?

O principal mecanismo que os nós ROS usam para se comunicar é enviar mensagens. As mensagens no ROS são organizadas em tópicos nomeados. A ideia é que um nó que deseja compartilhar informações publique mensagens sobre o(s) tópico(s) apropriado(s); um nó que deseja receber informações se inscreve no tópico ou nos tópicos de seu interesse. O mestre ROS se encarrega de garantir que editores e assinantes possam se encontrar; as próprias mensagens são enviadas diretamente do editor para o assinante.

Visualizando o gráfico

Essa ideia é provavelmente mais fácil de ver graficamente e a maneira mais fácil de visualizar as relações de publicação-assinatura entre nós ROS é usar este comando:

rqt_graph

Neste nome, o r é para ROS, e qt se refere ao kit de ferramentas Qt GUI usado para implementar o programa. Você deve ver uma GUI, a maioria da qual é dedicada a mostrar os nós no sistema atual. Neste caso, você verá algo como a Figura 2.2. Neste gráfico, as formas ovais representam os nós e as bordas direcionadas representam os relacionamentos editor-assinante. O gráfico nos diz que o nó chamado /teleop_turtle publica mensagens sobre um tópico chamado /turtle1/cmd_vel, e que o nó chamado /turtlesim assina essas mensagens. (Neste contexto, o nome “cmd_vel” é uma abreviação de “velocidade de comando”.)


Figura 2.2: A interface rqt_graph, mostrando o gráfico para o exemplo turtlesim. Nós de depuração, incluindo rosout, são omitidos por padrão.

Você pode notar que o nó /rosout que vimos na Seção 2.6 está faltando nesta visualização. Por padrão, rqt_graph oculta nós que ele pensa que existem apenas para depuração. Você pode desativar esse recurso desmarcando a caixa “Ocultar depuração”. Figura 2.3 mostra o gráfico resultante.


Figura 2.3: O gráfico turtlesim completo, incluindo nós que rqt_graph classifica como nós de depuração.

  • Observe que o próprio rqt_graph aparece como um nó.
  • Todos esses nós publicam mensagens em um tópico chamado /rosout, ao qual o nó chamado /rosout se inscreve. Este tópico é um mecanismo por meio do qual os nós podem gerar mensagens de log textuais. O capítulo 4 tem mais informações sobre como fazer login no ROS.

⚠️ O nome /rosout se refere tanto a um nó quanto a um tópico. ROS não se confunde com esses tipos de nomes duplicados porque é sempre claro a partir do contexto se queremos falar sobre o nó /rosout ou o tópico /rosout.

Essa visão dos nós de depuração é útil para ver uma imagem real do estado atual das coisas, mas também pode confundir o gráfico um pouco com informações que geralmente não são muito úteis. A ferramenta rqt_graph possui várias outras opções para ajustar a forma como o gráfico é mostrado. A preferência pessoal do autor é alterar a lista suspensa de “Somente nós” para “Nós/tópicos (todos)” e desabilitar todas as caixas de seleção, exceto “Ocultar depuração”. Esta configuração, cujos resultados são mostrados na Figura 2.4, tem a vantagem de todos os tópicos serem mostrados em retângulos, separados dos nós. Pode-se ver, por exemplo, que o nó /turtlesim, além de assinar os comandos de velocidade, também publica sua pose atual e os dados de um sensor de cor simulado. Quando você está explorando um novo sistema ROS, rqt_graph, especialmente com essas opções, pode ser uma maneira útil de descobrir quais tópicos estão disponíveis para seus programas usarem para se comunicar com os nós existentes.


Figura 2.4: O gráfico turtlesim, mostrando todos os tópicos, incluindo aqueles sem editores ou assinantes, como objetos distintos.

⚠️ O fenômeno de ter tópicos sem inscritos pode parecer um bug, mas na verdade é muito comum. A intuição é que os nós ROS geralmente são projetados para publicar as informações úteis que possuem, sem se preocupar se alguém está assinando essas mensagens. Isso ajuda a reduzir o nível de acoplamento entre nós individuais.

Agora podemos entender pelo menos parte de como funciona o sistema de teleoperação turtlesim. Quando você pressiona uma tecla, o nó /teleop_turtle publica mensagens com aqueles comandos de movimento em um tópico chamado /turtle1/cmd_vel. Por se inscrever nesse tópico, o turtlesim_node recebe essas mensagens e simula a tartaruga se movendo com a velocidade solicitada. Os pontos importantes aqui são:

  • O simulador não se importa (ou mesmo sabe) qual programa publica essas mensagens cmd_vel. Qualquer programa que publique sobre esse assunto pode controlar a tartaruga.
  • O programa de teleoperação não se importa (ou mesmo sabe) qual programa assina as mensagens cmd_vel que publica. Qualquer programa que assine esse tópico está livre para responder a esses comandos.

A propósito, esses nomes de tópicos começam com /turtle1 porque estão relacionados à tartaruga padrão, cujo nome é “turtle1”. Veremos, no capítulo 8, como adicionar tartarugas adicionais a uma janela turtlesim.

Mensagens e tipos de mensagem

Até agora, falamos sobre a ideia de que os nós podem enviar mensagens uns aos outros, mas temos sido muito vagos sobre quais informações estão realmente contidas nessas mensagens. Vamos examinar mais de perto os próprios tópicos e mensagens.

Listagem de tópicos

Para obter uma lista de tópicos ativos, use este comando:

rostopic list

Em nosso exemplo, isso mostra uma lista de cinco tópicos:

/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

A lista de tópicos deve, é claro, ser igual ao conjunto de tópicos visíveis em rqt_graph, mas pode ser mais conveniente ver em forma de texto.

Ecoando mensagens

Você pode ver as mensagens reais que estão sendo publicadas em um único tópico usando o comando rostopic:

rostopic echo topic-name

Este comando irá despejar todas as mensagens publicadas no tópico fornecido para o terminal. O código abaixo mostra alguns exemplos de saída obtidos

$ rostopic echo /turtle1/cmd_vel
linear:
x:2.0
y:0.0
z:0.0
angular:
x:0.0
y:0.0
z:0.0
−−−
linear:
x:0.0
y:0.0
z:0.0
angular:
x:0.0
y:0.0
z:−2.0
−−−
linear:
x:2.0
y:0.0
z:0.0
angular:
x:0.0
y:0.0
z:0.0
−−−

no momento em que /teleop_turtle estava recebendo pressionamentos de teclas. Cada — linha na saída mostra o final de uma mensagem e o início de outra. Nesse caso, houve três mensagens.

Medindo taxas de publicação

Existem também dois comandos para medir a velocidade com que as mensagens são publicadas e a largura de banda consumida por essas mensagens:

rostopic hz topic-name
rostopic bw topic-name

Esses comandos assinam o tópico fornecido e as estatísticas de saída em unidades de mensagens por segundo e bytes por segundo, respectivamente.

⚠️ Mesmo que você não se importe muito com as taxas específicas, esses comandos podem ser úteis para depuração, porque fornecem uma maneira fácil de verificar se as mensagens estão realmente sendo publicadas regularmente em tópicos específicos.

Inspecionando um tópico

Você pode aprender mais sobre um tópico usando o comando info rostopic:

rostopic info topic-name

Por exemplo, a partir deste comando:

rostopic info /turtle1/color_sensor

você deve ver uma saída semelhante a esta:

Type: turtlesim/Color
Publishers:
  * /turtlesim (http://donatello:46397/)
Subscribers: None

A parte mais importante desta saída é a primeira linha, que mostra o tipo de mensagem desse tópico. No caso de /turtle1/color_sensor, o tipo de mensagem é turtlesim/Color. A palavra “tipo” neste contexto se refere ao conceito de tipo de dados. É importante compreender os tipos de mensagem porque eles determinam o content das mensagens. Ou seja, o tipo de mensagem de um tópico informa quais informações estão incluídas em cada mensagem desse tópico e como essas informações são organizadas.

Inspecionando um tipo de mensagem

Para ver detalhes sobre um tipo de mensagem, use um comando como this:

rosmsg show message-type-name

Vamos tentar usá-lo no tipo de mensagem para /turtle1/color_sensor que encontramos acima:

rosmsg show turtlesim/Color

A saída é:

uint8 r
uint8 g
uint8 b

O formato é uma lista de campos, um por linha. Cada campo é definido por um tipo de dados embutido (como int8, bool ou string) e um nome de campo. A saída acima nos diz que um turtlesim/Color é , algo que contém três inteiros de 8 bits sem sinal chamados r, g e b. Cada mensagem em qualquer tópico com o tipo de mensagem turtlesim/Color é definida por valores para esses três campos. (Como você pode imaginar, esses números correspondem às intensidades de cor vermelho-verde-azul para o pixel sob o centro da tartaruga simulada.)

Outro exemplo, que revisitaremos várias vezes, é geometry_msgs/Twist. Este é o tipo de mensagem para o tópico /turtle1/cmd_vel, e é um pouco mais complicado:

geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z

Nesse caso, tanto lineares quanto angulares são campos compostos cujo tipo de dados é geometry-_msgs/Vector3. O recuo mostra que os campos chamados x, y e z são membros desses dois campos de nível superior. Ou seja, uma mensagem do tipo geometry_msgs/Twist contém exatamente seis números, organizados em dois vetores chamados linear e angular. Cada um desses números tem o tipo embutido float64, o que significa, naturalmente, que cada um é um número de ponto flutuante de 64 bits.

Em geral, um campo composto é simplesmente uma combinação de um ou mais subcampos, cada um dos quais pode ser outro campo composto ou um campo simples com um tipo de dados embutido. A mesma ideia aparece em C ++ e outras linguagens orientadas a objetos, nas quais um objeto pode ter outros objetos como membros de dados.

⏩ É importante notar que os tipos de dados dos campos compostos são tipos de mensagens em seu próprio direito. Por exemplo, seria perfeitamente legítimo ter um tópico com o tipo de mensagem geometry_msgs / Vector3. As mensagens com este tipo consistiriam em três campos de nível superior, a saber, x, y e z.

Esse tipo de aninhamento pode ser útil para evitar a duplicação de código para sistemas nos quais muitos tipos de mensagens compartilham elementos comuns. Um exemplo comum é o tipo de mensagem std_msgs/Header, que contém algumas informações básicas de sequência, carimbo de data/hora e quadro de coordenadas. Esse tipo é incluído como um campo composto denominado cabeçalho em centenas de outros tipos de mensagem.

Felizmente, rosmsg show expande automaticamente os campos compostos até os tipos embutidos subjacentes, usando indentação para mostrar a estrutura aninhada, portanto, geralmente não há necessidade de inspecionar os tipos de mensagem aninhados diretamente.

Os tipos de mensagem também podem conter matrizes com comprimento fixo ou variável (mostrado entre colchetes []) e constantes (geralmente para interpretar o conteúdo de outros campos não constantes). Esses recursos não são usados pelo turtlesim. Para obter um exemplo de tipo de mensagem que usa esses recursos, dê uma olhada em sensor_msgs/NavSatFix, que representa um único ponto de GPS.

Publicação de mensagens na linha de comando

Na maioria das vezes, o trabalho de publicação de mensagens é feito por programas1 especializados.
No entanto, às vezes você pode achar útil publicar mensagens manualmente. Para fazer isso, use rostopic:

rostopic pub -r rate-in-hz topic-name message-type message-content

Este comando publica repetidamente a mensagem fornecida no tópico fornecido na taxa fornecida.

O parâmetro final message content deve fornecer valores para todos os campos no tipo de mensagem, em ordem. Aqui está um exemplo:

rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist '[2, 0, 0]' '[0, 0, 0]'

Os valores são atribuídos aos campos de mensagem na mesma ordem em que são mostrados pelo rosmsg show. Nesse caso, os três primeiros números denotam a velocidade linear desejada e os três números finais denotam a velocidade angular desejada. Usamos aspas simples ('...') e colchetes ([...]) Para agrupar os subcampos individuais nos dois campos compostos de nível superior. Como você pode imaginar, as mensagens geradas por este exemplo comandam a tartaruga a dirigir em linha reta (ao longo de seu eixo x), sem rotação.

Da mesma forma, um comando como este fará com que o robô gire no lugar sobre seu eixo z (que é perpendicular à tela do seu computador):

rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist '[0, 0, 0]' '[0, 0, 1]'

⚠️ Na verdade, os dois campos diferentes de zero dos dois últimos exemplos - especificamente, linear.x e angular.z - são os únicos campos dentro de geometry_msgs/Twist aos quais o turtlesim presta atenção. Como os outros quatro campos representam movimentos que o simulador bidimensional não permite, turtlesim os ignora.

⏩ A sintaxe mostrada acima tem a desvantagem distinta de que você deve se lembrar de todos os campos do tipo de mensagem e da ordem em que aparecem. Uma alternativa é fornecer um único parâmetro especificando todos os campos como um único YAML (um acrônimo recursivo para “YAML Ain’t Markup Language”) dicionário. Este comando (que, na verdade, contém caracteres de nova linha) é equivalente ao anterior, mas mostra explicitamente o mapeamento de nomes de campo para valores:

rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
x: 2.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0"

Existem interações complicadas o suficiente entre bash e YAML que a documentação online tem uma página inteira dedicada apenas ao uso de YAML na linha de comando. A maneira mais simples de obter a sintaxe correta é usar o preenchimento com tabulação.

Pressionar Tab após inserir o tipo de mensagem irá inserir um dicionário YAML totalmente formado, com todos os campos no tipo de mensagem fornecido. A mensagem gerada pela guia usará valores padrão (zero, falso, string vazia, etc), mas você pode editá-la para conter o conteúdo real da mensagem que deseja.

Existem algumas opções adicionais para pub rostopic que podem ser úteis.

  • O formulário mostrado aqui usa -r para selecionar o “modo de taxa” do pub rostopic, que publica mensagens em intervalos regulares. Este comando também suporta um modo único (-1 “traço um”) e um modo especial “travado” ( -l “traço ell”) que publica apenas uma vez, mas garante que novos assinantes desse tópico receberão a mensagem. O modo travado é, na verdade, o padrão.
  • Também é possível ler mensagens de um arquivo (usando -f) ou da entrada padrão (omitindo -f e o conteúdo da mensagem do comando). Em ambos os casos, a entrada deve ser formatada como a saída de eco rostópico.

⚠️ Talvez você tenha começado a imaginar possibilidades de usar uma combinação de script de rostopic echo e rostopic pub como uma forma de “gravar” e “reproduzir” mensagens, para automatizar o teste de seus programas. Nesse caso, você se interessará pela ferramenta rosbag (capítulo 9), que é uma implementação mais completa desse tipo de ideia.

Nomes dos tipos de mensagens entendimento

Como tudo o mais no ROS, cada tipo de mensagem pertence a um pacote específico. Os nomes dos tipos de mensagens sempre contêm uma barra, e a parte antes da barra é o nome do pacote que o contém:

package-name/type-name

Por exemplo, o tipo de mensagem turtlesim/Color divide-se desta forma:

nome do pacote nome do tipo tipo de dados da mensagem
turtlesim Color turtlesim/Color

Essa divisão de nomes de tipo de mensagem tem alguns propósitos:

  • Mais diretamente, incluir pacotes nos nomes dos tipos de mensagens ajuda a prevenir colisões de nomes. Por exemplo, geometry_msgs/Pose e turtlesim/Pose são tipos de mensagens distintos que contêm dados diferentes (mas conceitualmente semelhantes).
  • Como veremos no capítulo 3, ao escrever programas ROS, precisaremos declarar dependências em outros pacotes que contêm tipos de mensagem que usamos. Incluir o nome do pacote como parte do nome do tipo de mensagem torna essas dependências mais fáceis de ver.
  • Finalmente, saber o pacote que contém um determinado tipo de mensagem pode ser útil para descobrir o propósito desse tipo. Por exemplo, o nome do tipo ModelState é bastante misterioso isoladamente, mas o nome completo gazebo/ModelState esclarece que este tipo de mensagem é parte do simulador Gazebo e provavelmente contém informações sobre um dos modelos dentro dessa simulação.

1 Na verdade, criar esses programas é o assunto principal deste livro!