Tópicos e mensagens
Sumário
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
ez
.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
eangular.z
- são os únicos campos dentro degeometry_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” dopub 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 deeco rostópico
.
⚠️ Talvez você tenha começado a imaginar possibilidades de usar uma combinação de script de
rostopic echo
erostopic pub
como uma forma de “gravar” e “reproduzir” mensagens, para automatizar o teste de seus programas. Nesse caso, você se interessará pelaferramenta 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
eturtlesim/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 completogazebo/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!