Criando um "Hello World" no Robot Operating System (ROS)

Hello World no Robot Operating System
Este post faz parte da série ROS (Robot Operating System). Leia também os outros posts da série:

Último artigo da série introdutória sobre o Robot Operating System. Vamos finalmente colocar as mãos na massa e construir nosso primeiro pacote em C++ contendo um "Hello World" no ROS.

 

 

Criando um workspace para seus pacotes

 

Antes de criarmos nosso primeiro pacote no ROS, precisaremos criar um local aonde iremos armazenar todos os nossos pacotes personalizados (pacotes criados por nós). Em nosso caso, chamamos esse local de um catkin workspace.

 

Vamos criar nosso catkin workspace em nosso diretório de usuário com os seguintes comandos:

 

 

Em outras palavras, nosso catkin workspace foi criado na pasta catkin_ws dentro do seu diretório de usuário (/home/SEU_USERNAME). Além disso, todos os nossos pacotes ficarão armazenados na pasta src dentro do seu catkin workspace.

 

Mesmo que não tenhamos criado nenhum pacote, já podemos compilar nosso catkin workspace com o comando catkin_make:

 

 

O comando catkin_make deve ser sempre executado na pasta raiz do seu catkin workspace, caso contrário você receberá várias mensagens de erro. 

 

Para que todos os seus pacotes sejam visíveis em qualquer terminal de sua máquina, precisamos executar os seguintes comandos:

 

 

Nota: substitua SEU_USERNAME pelo seu nome de usuário.

 

 

Criando seu primeiro pacote

 

Agora que configuramos nosso catkin workspace, podemos finalmente criar nosso primeiro pacote. Navegue para a pasta catkin/src  e execute o seguinte comando:

 

 

Pronto! Acabamos de criar um pacote chamado ros_embarcados_tutorial que depende dos pacotes std_msgs, rospy e roscpp. Entretanto, o pacotes que acabamos de criar está vazio e precisamos adicionar nosso código para termos nosso "Hello World" no ROS. Mas, antes disso, vamos entender um pouco mais como é a estrutura de um pacote no ROS.

 

O pacote std_msgs possui wrappers para os tipos primitivos de mensagens existentes no ROS, tais como Bool, Byte, Float32, Float64, etc. Em outras palavras, é o pacote básico para qualquer pacote que você esteja criando.

 

O pacote rospy é o responsável por criar uma interface para a criação de nós usando Python. É um pacote básico se você estiver criando pacotes que utilizem scripts escritos em Python. No nosso caso, como vamos criar nosso pacote usando C++, não é necessário a sua utilização.

 

O pacote roscpp é semelhante ao pacote rospy, mas é utilizado quando estamos criando pacotes com nós escritos em C++.

 

 

Entendendo a estrutura do seu primeiro pacote

 

Abra seu gerenciador de arquivos e navegue até a pasta que contém o seu pacote. Você verá duas pastas (include e src) e dois arquivos (CMakeLists.txt e package.xml), conforme mostrado na Figura 1.

 

Hello World no Robot Operating System: Estrutura de arquivos de um pacote no ROS.
Figura 1 - Estrutura de arquivos de um pacote no ROS.

 

Como você deve ter percebido, catkin é um sistema baseado em cmake. Se você possui familiaridade com cmake não terá problemas em criar pacotes mais avançado. Para os que não sabem, eu incluso, temos que sofrer um pouco para entender as sutilezas do cmake. Entretanto, mostrarei como modificar o arquivo CMakeLists.txt para nosso "Hello World".

 

Enquanto o arquivo CMakeLists.txt é utilizado para compilar seu pacote, o arquivo package.xml é utilizado como um manifesto para seu pacote. Ele contém os dados básicos do seu pacote. Por exemplo, é nele que você deve definir o tipo de licença utilizada em seu pacote (GPL, BSD, etc), o nome do mantenedor e endereço de email, etc. Esse arquivo também contém a lista de dependências que seu pacote precisa para funcionar corretamente.

 

A pasta src é utilizada para armazenar os códigos fontes C++ do seu pacote e a pasta include é utilizada para armazenar os arquivos de cabeçalho do seu pacote (arquivos .h).

 

A estrutura de arquivos e pasta acima é o básico para todo e qualquer pacote, mas isso não quer dizer que todos os pacotes terão essa estrutura. Por exemplo, você pode criar nós utilizando Python. Nesse caso, você precisa colocar todos os seus códigos fontes na pasta scripts que deve ser criada manualmente.

 

 

Escrevendo o código para publicar seu "Hello World"

 

Para termos um pacote completo no ROS, precisamos de um nó para publicar mensagens e um nó para receber mensagens. Em outras palavras, um nó que publica mensagens em um tópico e um nó que subscrever em um tópico.

 

Agora vamos criar um nó para publicar a mensagem "hello world" no tópico /chatter. Abra seu editor de textos, como o GEdit ou o Sublime Text e escreva o seguinte código:

 

 

Salve o arquivo com o nome talker.cpp na pasta src do nosso pacote ros_embarcados_tutorial:

/home/SEU_USERNAME/catkin_ws/src/ros_embarcados_tutorial/src/talker.cpp

 

Vamos explicar o código linha por linha:

 

 

Nessa linha estamos adicionando os arquivos de cabeçalhos referentes ao ROS e todas as suas funções e métodos.

 

 

Arquivo de cabeçalho referente ao pacote std_msgs. Em nosso  caso, vamos utilizar mensagens do tipo String. Note que o tipo String do ROS faz parte do pacote std_msgs e não é relacionado com o tipo padrão de strings utilizado no C++.

 

 

String stream padrão do C++ não possui relação com o ROS.

 

 

Inicializar o ROS e cria um nó com o nome talker.

 

 

Cria um objeto do tipo NodeHandle. Esse objeto é essencialmente o nosso nó. Toda publicação ou leitura de um tópico pelo nó talker será feito utilizando o NodeHandle n que acabamos de criar.

 

 

Cria o objeto chatter_pub responsável por publicar mensagens do tipo std::msgs::String no tópico /chatter.

 

 

Especifica a frequência do loop principal do seu nó. Nesse caso, 10 Hz.

 

 

Cria a variável count para que possamos saber quantas mensagens foram publicadas até o momento.

 

 

Esse é o loop principal do seu nó. Significa que seu nó irá rodar indefinidamente até que alguém use Ctrl+C para parar a execução. ros::ok() irá retornar false, uma vez que o usuário use Ctrl+C, e o programa sairá do loop, encerrando-o.

 

 

Cria a variável msg do tipo std_msgs::String. Essa variável irá armazenar a mensagem que queremos publicar.

 

 

Criamos a string "hello world" e adicionamos o nosso contador de mensagens. Note que qualquer mensagem do tipo std_msgs::String possui um membro chamado data que é aonde nossa string ficará armazenada.

 

 

ROS_INFO é o equivalente ao printf/cout em ROS. Usamos ROS_INFO para mostrar informações ao usuário. Nesse caso, vamos mostrar a string que está dentro da nossa mensagem, msg.

 

 

Essa linha fará com que o ROS efetivamente publique nossa mensagem no tópico /chatter.

 

 

Faz com que o ROS atualize nosso nó, publicando e subscrevendo mensagens.

 

 

Faz com que nosso nó durma a quantidade de tempo necessário para que tenhamos uma frequência de 10 Hz no nosso loop principal.

 

 

Escrevendo o código para receber seu "Hello World"

 

 

Agora que escrevemos nosso nó para publicarmos nosso "Hello World", precisamos criar um nó para se subscrever no tópico /chatter e receber nosso "Hello World". Chamaremos esse nó de listener. Use seu editor preferido para criar o arquivo listener.cpp dentro da pasta src do nosso pacote ros_embarcados_tutorials (/home/SEU_USERNAME/catkin_ws/src/ros_embarcados_tutorials/src/listener.cpp) com o seguinte código:

 

 

Vamos explicar as partes do código que diferem do nó criado anteriormente.

 

 

A primeira diferença é que precisamos de uma função para lidar com as novas informações que estão chegando no nosso tópico /chatter. Sempre que uma nova mensagem é publicada em /chatter, nosso subscriber irá chamar a função chatterCallback. Essa função irá receber a nova mensagem publicada (msg) e irá realizar alguma ação. No nosso caso, vamos simplesmente converter nossa mensagem para string e mostrar em nossa janela de terminal usando ROS_INFO (note que ROS_INFO possui a mesma sintaxe do tradicional printf em C).

 

 

Note que nosso subscriber será um nó totalmente independente do nosso publisher criado anteriormente e será registrado com o nome de listener.

 

 

Cria o objeto sub que irá subscrever no tópico /chatter e chamará a função chatterCallback sempre que o tópico for atualizado com uma nova mensagem.

 

 

Faz com que o nosso nó entre em um loop chamando a função chatterCallback o mais rápido possível assim que o tópico /chatter seja atualizado. Nesse caso, a frequência do loop será totalmente relacionado com a frequência de publicação do tópico /chatter. Além disso, ros::spin() irá finalizar a execução do nó uma vez que o usuário use a combinação de teclas Ctrl+C no terminal.

 

 

Pronto! Criamos nosso publisher e nosso subscriber usando C++ e ROS. Agora precisamos modificar nosso arquivo CMakeLists.txt do nosso pacote ros_embarcados_tutorials para que possamos compilar nossos nós.

 

 

Compilando nosso publisher e subscriber

 

Abra o arquivo CMakeLists.txt no seu editor favorito. Vá para a linha 131 e substitua a linha pela seguinte linha:

 

 

ROS Tutorial: Building a ROS PackageSubstitua a linha 135 por:

 

 

Substitua as linha 138 à 140 por:

 

 

Com essas modificações já podemos compilar o nó talker, mas ainda precisamos adicionar as informações referentes ao nó listener.

 

Abaixo da linha 138 adicione as seguintes linhas:

 

 

Aqui está um exemplo do arquivo CMakeLists.txt funcional e sem todos os comentários:

 

 

Agora podemos compilar nossos nós:

 

 

 

Testando nosso publisher e subscriber

 

Agora que compilamos nossos nós, podemos finalmente testá-los. Abra uma nova janela de terminal e inicialize o ROS:

 

 

Em outra janela de terminal, inicialize o nó talker:

 

 

Por fim, em outra janela de terminal, inicialize o nó listener:

 

 

Se tudo ocorrer bem, você verá os seguintes resultados:

 

ros_helloworld_testing

 

E assim terminamos nossa séria introdutória ao ROS. Agora você possui conhecimentos básicos para começar a criar seus próprios nós no ROS.

 

 

Referências

 

ROS Tutorial: Writing a Simple Publisher and Subscriber (C++)

ROS Tutorial: Creating a ROS Package

ROS Tutorial: Building a ROS Package

Outros artigos da série

<< Entendendo as mensagens e tópicos do ROS
Este post faz da série ROS (Robot Operating System). Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

13
Deixe um comentário

avatar
 
4 Comment threads
9 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
6 Comment authors
JeffersonUm_CuriosoJéssica MottaFrancisco Erivaldo Fernandes JuniorGustavo Jose Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Jefferson
Visitante
Jefferson

Olá, recebo as seguintes mensagens : The dependency target "ros_embarcados_tutorials_generate_messages_cpp" of
target "talker" does not exist.
e
The dependency target "ros_embarcados_tutorials_generate_messages_cpp" of
target "listener" does not exist.

Como resolver isso ?

Um_Curioso
Visitante
Um_Curioso

Muito obrigado. Com seu tutorial consegui fazer o listener em c++ e o talker em python, e o melhor é que deu certo a comunicação entre eles. Show, agradeço muito mesmo, continue com mais tutoriais!

Jéssica Motta
Visitante
Jéssica Motta

Olá, eu estava executando o código disponibilizado no artigo do CMakeLists e tava dando erro, percebi que tem erro nas seguintes linhas: 2, 15 e 19, onde invés de estar escrito ros_embarcados_tutorial está como ros_embarcados_tutorials, com o 'S' no final. 😀
Excelente tutorial, continue compartilhando seu conhecimento de ROS conosco!

Pryce
Visitante
Pryce

Olá Francisco
Estou começando a usar o ROS agora para fazer os teste para a minha tese, confesso que sou menos que iniciante. Comecei a usar o seu tutorial e apareceu o seguinte erro:

echo "source /home/SEU_USERNAME*/catkin_ws/devel/setup.bash" >> ~/.bashrc
bash: erro de sintaxe próximo do token' não esperado ;&'

*seu-username está o meu user

Desde já agradeço a atenção.

Gustavo Jose
Visitante
Gustavo Jose

Tbm tive o mesmo problema

Francisco Erivaldo Fernandes Junior
Visitante
Erivaldo Junior

Bom, eu expliquei os comandos no jeito "Linux". Se você tem o seguinte comando: ~/catkin_ws$ echo "source /home/SEU_USERNAME/catkin_ws/devel/setup.bash" >> ~/.bashrc A primeira parte (a parte com o $ não faz parte do comando). A parte ~/catkin_ws indica a pasta que você deve está no momento de usar o comando e o simbolo $ significa que você deve ser usuário normal (se você ver em outros tutoriais de linux, você verá o símbolo # que significa usuário root ou administrador). Portanto, o comando que você deve digitar no terminal é o seguinte: echo "source /home/SEU_USERNAME/catkin_ws/devel/setup.bash" >> ~/.bashrc Mas tenha certeza que… Leia mais »

Gustavo Jose
Visitante
Gustavo Jose

Consegui! Porém, mais a frente ainda aparece erros ao compilar o projeto, erro na sintaxe do código do talker e do listener, principalmente relativo aos includes...
Agradeço pela ajuda!

Francisco Erivaldo Fernandes Junior
Visitante
Erivaldo Junior

Posso tentar ajudar a resolver os problemas. Cola os erros nos comentários.

Se o ROS estiver instalado corretamente, você não deveria receber erros em relação aos includes.

Gustavo Jose
Visitante
Gustavo Jose

gustavoGustavo Guandalini:~/catkin_ws$ catkin_make Base path: /home/gustavo/catkin_ws Source space: /home/gustavo/catkin_ws/src Build space: /home/gustavo/catkin_ws/build Devel space: /home/gustavo/catkin_ws/devel Install space: /home/gustavo/catkin_ws/install #### #### Running command: "make cmake_check_build_system" in "/home/gustavo/catkin_ws/build" #### -- Using CATKIN_DEVEL_PREFIX: /home/gustavo/catkin_ws/devel -- Using CMAKE_PREFIX_PATH: /home/gustavo/catkin_ws/devel;/opt/ros/indigo -- This workspace overlays: /home/gustavo/catkin_ws/devel;/opt/ros/indigo -- Using PYTHON_EXECUTABLE: /usr/bin/python -- Using Debian Python package layout -- Using empy: /usr/bin/empy -- Using CATKIN_ENABLE_TESTING: ON -- Call enable_testing() -- Using CATKIN_TEST_RESULTS_DIR: /home/gustavo/catkin_ws/build/test_results -- Found gtest sources under '/usr/src/gtest': gtests will be built -- Using Python nosetests: /usr/bin/nosetests-2.7 -- catkin 0.6.18 -- BUILD_SHARED_LIBS is on -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~ traversing 1 packages in topological order: -- ~~ -… Leia mais »

Gustavo Jose
Visitante
Gustavo Jose

Descobri o problema! Na verdade eu não tinha percebido as entidades do HTML. Mas agora funcionou!(O nome do pacote também aparece diferente em dois momentos) Teria como eu entrar em contato com você via email, ou de alguma outra forma para tirar algumas dúvidas ?
Agradeço desde já!

Francisco Erivaldo Fernandes Junior
Visitante
Erivaldo Junior

Gustavo, obrigado pelo comentário. Agora que notei que os códigos foram "distorcidos" quando publiquei o artigo no site. Por isso que tinha tantos erros no código.

Atualizei o artigo e agora tudo parece está "corretamente" escrito.

Francisco Erivaldo Fernandes Junior
Visitante
Erivaldo Junior

Você pode me enviar email sim. Entra no meu site e envia por lá. Não quero escrever meu email nos comentários para não receber SPAM.