Olá, ROS!
Agora que criamos um pacote, podemos começar a escrever programas ROS.
Sumário
Um programa simples
Lista 3.2 mostra uma versão ROS do programa canônico “Hello, world!”. Esse arquivo fonte, nomeado ‘hello.cpp’, pertence a sua pasta de pacotes, próximo ao ‘package.xml’ e ‘CMakeLists.txt’.
⚠️ Alguns tutoriais online sugerem a criação de um diretório scr dentro do seu diretório de pacote para conter arquivos fonte C++. Essa organização adicional pode ser útil, especialmente para pacotes maiores com vários tipos de arquivos, mas não é estritamente necessário.
Lista 3.1
O manifesto (isto é, package.xml) para esse pacote agitr do livro.
1 <?xml version ="1.0"?>
2 <package>
3 <name>agitr</name>
4 <version>0.0.1</version>
5 <description>
6 Examples from A Gen tle I n t r o d u c ti o n t o ROS
7 </description>
8 <maintainer email=" jokane@cse.sc.edu">
9 Jason O' Kane
10 </maintainer>
11 <license>TODO</license>
12 <buildtool_depend>catkin</buildtool_depend>
13 <build_depend>geometry_msgs</build_depend>
14 <run_depend>geometry_msgs</run_depend>
15 <build_depend>turtlesim</build_depend>
16 <run_depend>turtlesim</run_depend>
17 </package>
Nós veremos como compilar e executar esse programa momentaneamente, mas primeiro vamos examinar o próprio código.
-
O cabeçalho de arquivo
ros/ros.h
inclui declarações das classes padrão ROS. Você vai desejar inclui-lo em todo programa ROS que você escrever. -
A função
ros::init
inicializa a biblioteca cliente ROS. Chame essa uma vez no começo do seu programa. * O ultimo parâmetro é uma string contendo o nome default do seu nó.
⏩ Esse nome default pode ser anulado por um arquivo launch (ver página 87) ou por um parâmetro de linha de comando rosrun (ver página 23).
- O objeto
ros::NodeHandle
é o principal mecanismo que seu programa vai usar para interagir com o sistema ROS. Criar esse objeto registra o seu programa como um nó com o ROS máster. A técnica mais simples é criar um único objetoNodeHandle
para usar durante o seu programa.
Lista 3.2
Um programa trivial ROS chamado hello.cpp
.
1 // Essa é uma versão ROS do programa padrão
2 // "hello, world"
3
4 // Esse cabeçalho define as classes padrão ROS.
5 #include<ros/ros.h>
6
7 int main (int argc ,char∗∗ argv ) {
8 // Inicializa o sistema ROS.
9 ros::init (argc , argv ,"hello_ ros") ;
10
11 // Estabelece esse programa como o nó ROS.
12 ros :: NodeHandle nh ;
13
14 // Envia a saída como mensagem log.
15 ROS_INFO_STREAM( " Hell o , ␣ROS! " ) ;
16 }
⏩ Internamente, a classe
NodeHandle
mantém uma contagem de referência e só registra um novo nó com o master quando o primeiro objetoNodeHandle
é criado. Da mesma forma, o nó só é desregistrado quando todos objetos doNodeHandle
forem destruídos. Esse detalhe tem dois impactos: Primeiro, você pode, se preferir, criar múltiplos objetosNodeHandle
, todos os quais se referem ao mesmo nó. Ocasionalmente, haverão situações onde isso fará sentido. Um exemplo dessa tal situação aparece na página 129. Segundo, isso significa que não é possível, usando a interface padrãoroscpp
, executar múltiplos nós distintos dentro de um único programa.
- A linha
ROS_INFO_STREAM
gera uma mensagem informativa. Essa mensagem é enviada a diversos locais diferentes, incluindo a tela do console. Nós veremos mais detalhes sobre esse tipo de mensagem log no capítulo 4.
Compilando o programa Hello
Como você pode compilar e executar esse programa? Isso é tratado pelo sistema de construção do ROS, chamado de catkin
. Existem quatro passos.
Declarando dependências
Primeiro, nós precisamos declarar os outros pacotes dos quais o nosso depende. Para os programas em C++, esse passo é necessário primordialmente para assegurar que catkin
forneça o compilador C++ com as bandeiras apropriadas para localizar os arquivos e bibliotecas de cabeçalho que ele precisa.
Para listar dependências, edite o CMakeLists.txt
no seu diretório de pacotes. A versão default desse arquivo tem essa linha:
find_package(catkin REQUIRED)
Dependências em outros pacotes catkin
podem ser adicionadas em uma seção de componentes nessa linha:
find_package(catkin REQUIRED COMPONENTS package-names)
Para o exemplo hello, nós precisamos de uma dependência em um pacote chamado de roscpp
, o qual fornece a biblioteca de cliente do ROS em C++. A linha obrigatória find_package
, portanto é:
find_package(catkin REQUIRED COMPONENTS roscpp)
Nós devemos também listar dependências no pacote manifesto package.xml
, usando os elementos build_depend
e run_depend
:
package-name
Em nosso exemplo, o programa hello precisa do roscpp
tanto na construção quanto na execução, então o manifesto deve conter:
roscpp
Contudo, dependências declaradas no manifesto não são usadas no processo de produção; se você os omite aqui, você provavelmente não verá nehuma mensagem de erro até que você distribua seu pacote a outros que tentam construi-lo sem possuirem os pacotes obrigratórios instalados.
Declarando um executável
Em seguida, nós precisamos adicionar duas linhas ao CMakeLists.txt
declarando o executável que gostaríamos de criar. A forma geral é:
add_executable(executable-name source-files)
target_link_libraries(executable-name ${catkin_LIBRARIES})
A primeira linha declara o nome do executável que queremos e uma lista de aquivos fonte que devem ser combinados para formar aquele executável. Se você tem mais de um arquivo fonte, liste-os todos aqui, separados por espaços. A segunda linha fala ao CMake
para usar as bandeiras apropriadas de biblioteca ( definidas pelo find_package
linha acima) ao conectar esse executável. Se o seu pacote contém mais de um executável, copie e modifique essas duas linhas para cada executável que houver.
Em nosso exemplo, queremos um executável chamado hello, compilado de um único arquivo fonte chamado hello.cpp, então nós adicionaremos essas linhas ao CMakeLists.txt
:
add_executable(hello hello.cpp)
target_link_libraries(hello ${catkin_LIBRARIES})
Para referência, Lista 3.3 mostra um pequeno CMakeLists.txt
que é suficiente para o nosso exemplo. A versão default do CMakeLists.txt
criada pelo catkin_create_pkg
contém um pouco de orientação extra para outros poucos propósitos; para muitos programas simples, algo similar a versão simples mostrada aqui é o bastante.
Lista 3.3
The CMakeLists.txt
to build hello.cpp
.
# Qual versão do CMake é necessária?
cmake_minimum_required(VERSION 2.8.3)
# Nome desse pacote.
project(agitr)
# Encontre o sistema de construção catkin e qualquer outro pacote o
# qual nós dependemos.
find_package(catkin REQUIRED COMPONENTS roscpp)
# Declare nosso pacote catkin.
catkin_package()
# Especifique localização dos arquivos de cabeçalho.
include_directories(include ${catkin_INCLUDE_DIRS})
# Declare o executável junto com seus arquivos fonte. Se
# existem vários executáveis, use várias cópias
# dessa linha.
add_executable (hellohello.cpp)
# Especifique bibliotecas para qual se contra-liga. Novamente, essa
# linha deve ser copiado para cada executável distinto
# no pacote.
target_link_libraries(hello${catkin_LIBRARIES})
Construindo área de trabalho
Uma vez que o seu CMakeLists.txt
está pronto, você pode construir sua area de trabalho — incluindo compilar todos os executáveis em todos esses pacotes — usando este comando:
catkin_make
Por ser projetado para construir todos os pacotes na sua área de trabalho, esse comando deve ser executado pelo diretório da área de trabalho. Ele irá realizar vários passos de configuração (especialmente na primeira execução) e criar subdiretórios chamados devel and build dentro da sua área de trabalho. Esses dois novos diretórios contêm arquivos relacionados à construção como arquivos criadores automaticamente gerados, código objeto e os próprios executáveis. Se preferir, os subdiretórios devel and build podem ser deletados com segurança quando você terminar de trabalhar no seu pacote.
Se houverem erros de compilação, você os verá aqui. Depois de corrigi-los você pode usar catkin_make
novamente para completer o processo de construção.
⚠️ Se você vir erros do
catkin_make
que o cabeçalhoros/ros.h
não pode ser encontrado, ou erros “ referência indefinida” noros::init
ou outras funções ROS, a razão mais provável é que o seuCMakeLists.txt
não declara corretamente uma dependência noroscpp
.
Abastecendo setup.bash
A etapa final é executar um roteiro chamado setup.bash
, o qual é criado pelo catkin_make
dentro o subdiretório devel da sua area de trabalho.
source devel/setup.bash
Esse roteiro de geração automatica define várias variáveis ambientais que permitem que o ROS encontre o seu pacote e é um executável recentemente gerado. Isso é análago ao setup.bash
global da seção 2.2, mas designado especificamente para a sua área de trabalho. A menos que a estrutura do diretório mude, você só vai precisar fazer isso uma só vez em cada terminal, mesmo que você modifique o código e compile novamente com catkin_make
.
Executando o programa hello
Quando todas as etapas de construção estão completas, o seu novo programa ROS está pronto para execução usando rosrun
(Seção 2.6), assim como qualquer outro programa ROS. No nosso exemplo, o comando é:
rosrun agitr hello
O programa deve produzir uma saída que se pareça mais ou menos assim:
[ INFO ] [1416432122.659693753]: Hello, ROS!
Não esqueça de iniciar o roscore
primeiro: Esse programa é um nó e nós precisam de um máster para rodar corretamente. Por sinal, os números nessa linha de saída representam o tempo — medido em segundos desde 1 de janeiro de 1970 — quando a nossa linha ROS_INFO_STREAM
foi executada.
⚠️ Esse
rosrun
paralelo a alguns outros commandos ROS, pode gerar um erro que se parece com isto:[rospack] Error: stack/package package-name not found
Duas causas comuns para esse erro são (a) erro de ortografia no nome do pacote e (b) falha em executar o
setup.bash
para sua área de trabalho.