PTENES
MÓDULO 4.1 · FUNDAMENTO

🧩 ROS 2 sem medo

O ROS 2 parece enorme porque tem muita coisa pronta. Para começar você só precisa de cinco ideias: nó, tópico, mensagem, serviço e ação. Neste módulo você escolhe a distro, instala (ou roda em Docker), lê o grafo pelo terminal e escreve o seu primeiro nó em Python.

6
Tópicos
Intermediário
Nível
Fundamento
Tipo
Só o PC
Hardware exigido
0%
0 de 0 tópicos lidos · Seção 1 de 6

Conteúdo detalhado

1

🧠 O que é o ROS 2 e por que usar

Até a Trilha 3, o robô era um ou dois programas que você escrevia inteiros. Quando entram LiDAR, mapa, câmera e navegação, um programa só vira um nó impossível de manter. O ROS 2 (Robot Operating System 2) resolve isso: cada tarefa vira um programa pequeno, e todos trocam dados por nome, sem saber quem está do outro lado nem em qual computador. Apesar do nome, ele não é um sistema operacional: roda em cima do Linux, como um conjunto de bibliotecas e ferramentas.

🌱 Novo aqui?

Middleware é o software "do meio": fica entre os seus programas e a rede e cuida de entregar as mensagens. No ROS 2 esse papel é do DDS (Data Distribution Service), um padrão industrial que descobre sozinho quem publica e quem assina cada dado. Um pacote é a unidade de código que você instala ou escreve: um driver de LiDAR, o Nav2, o seu robô.

DDS: entrega as mensagens por nome driver LiDARpublica /scan câmerapublica /image navegaçãoassina /scan base (ESP32)assina /cmd_vel RViz no PCoutro computador

Como ler: cada caixa âmbar é um programa independente (um nó). Nenhum fala direto com o outro: todos se ligam à faixa ciano. A navegação pede "/scan" e recebe do driver do LiDAR sem saber quem ele é. A caixa tracejada está em outro computador da rede e participa do mesmo jeito.

✓ Use ROS 2 quando

  • ✓O robô tem LiDAR, mapa ou navegação.
  • ✓Há mais de um computador (Pi, PC, ESP32) trabalhando junto.
  • ✓Você quer simular antes de montar.

✗ Não precisa de ROS 2 para

  • ✗Seguidor de linha ou rover que desvia (Trilhas 1 e 2).
  • ✗Um ESP32 sozinho, sem computador por perto.
  • ✗Um protótipo de fim de semana com um sensor só.

Por que aprender

O ROS 2 é o idioma comum da robótica de pesquisa e de boa parte da indústria. Aprendendo o básico, você passa a usar de graça drivers de sensores, o slam_toolbox para mapas e o Nav2 para navegação, em vez de escrever tudo do zero.

Conceitos-chave

Middleware
entrega as mensagens
DDS
descobre quem fala
Grafo ROS
nós + ligações
Pacote
unidade de código
2

📅 Qual distro: Lyrical ou Jazzy

O ROS 2 sai em distribuições (distros) com nome de tartaruga, uma por ano. As de número par, lançadas em maio, são LTS (suporte longo, cinco anos) e casam com uma versão LTS do Ubuntu. Em outubro de 2026 há duas boas escolhas: Lyrical Luth, lançada em 22/05/2026 para o Ubuntu 26.04 e suportada até maio de 2031, e Jazzy Jalisco, a LTS anterior, para o Ubuntu 24.04, suportada até 2029 e com mais tutoriais e pacotes prontos.

202220242026202820302032 hoje (out/2026) Humble · fim mai/2027 Jazzy · Ubuntu 24.04 · Harmonic Lyrical · Ubuntu 26.04 · Jetty

Como ler: cada barra é o período em que a distro recebe correções. A linha ciano é hoje. A Humble (cinza tracejada) acaba em menos de um ano: não comece por ela. Jazzy e Lyrical cobrem você por anos; cada uma traz o Ubuntu e o Gazebo do mesmo par.

Se você...Escolha
vai começar do zero hoje, em um PC novoLyrical (Ubuntu 26.04, Gazebo Jetty)
segue um tutorial, livro ou robô que pede JazzyJazzy (Ubuntu 24.04, Gazebo Harmonic)
precisa de um pacote que ainda não saiu para LyricalJazzy, ou Lyrical em Docker para testar
tem um projeto antigo em HumblePlaneje migrar para Jazzy antes de maio/2027

🌱 Novo aqui?

Neste curso os comandos usam <distro> como parte variável: troque por lyrical ou jazzy, sempre em minúsculas. Exemplo: source /opt/ros/jazzy/setup.bash. O resto do comando é igual nas duas.

Por que aprender

A maioria dos "não funciona" em ROS vem de mistura: tutorial de uma distro, pacote de outra, Gazebo de uma terceira. Decidir a distro no começo e manter o par Ubuntu ↔ ROS ↔ Gazebo evita esse tipo de defeito.

Conceitos-chave

Distro
versão nomeada do ROS
LTS
cinco anos de suporte
Par oficial
Ubuntu ↔ ROS ↔ Gazebo
<distro>
lyrical ou jazzy
3

📦 Instalar (Ubuntu, Docker ou Pi)

Há três caminhos. No Ubuntu (no PC ou numa máquina virtual), você instala pacotes prontos e tem o melhor desempenho no Gazebo. Com Docker, você roda um contêiner que já vem com o ROS, em qualquer Linux (e no Windows ou macOS, com mais ajuste para janelas gráficas). No Raspberry Pi 5, a forma direta é instalar o Ubuntu da mesma versão da distro; no Raspberry Pi OS, use Docker.

Passo a passo no Ubuntu

1

Confira o Ubuntu

Lyrical pede Ubuntu 26.04; Jazzy pede 24.04. Veja com lsb_release -a.

2

Adicione o repositório do ROS

Siga a seção "Setup Sources" da página oficial de instalação da sua distro em docs.ros.org. Esse passo muda de tempos em tempos; copie de lá, não de tutoriais antigos.

3

Instale e ative

Rode o bloco abaixo. O pacote desktop traz RViz2, exemplos e ferramentas; ros-dev-tools traz o colcon e o rosdep.

Objetivo: instalar o ROS 2 e deixar cada terminal novo já com ele ativado.

terminal (Ubuntu)
# depois de configurar o repositório pela página oficial
sudo apt update && sudo apt upgrade -y
sudo apt install -y ros-<distro>-desktop ros-dev-tools
# ativa o ROS em todo terminal novo
echo "source /opt/ros/<distro>/setup.bash" >> ~/.bashrc
source ~/.bashrc
# teste: dois nós de exemplo, um em cada terminal
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_py listener

Como verificar

  • ✓O talker imprime "Publishing: 'Hello World: 1'", "...: 2"; o listener imprime "I heard: [Hello World: 1]".
  • ✓printenv ROS_DISTRO mostra lyrical ou jazzy.
  • ✗"ros2: command not found"? Faltou o source neste terminal.

Caminho rápido com Docker: a imagem oficial osrf/ros:<distro>-desktop já vem com tudo. As opções de DISPLAY deixam o contêiner abrir janelas (RViz, turtlesim) no seu Linux. Confira as tags disponíveis no Docker Hub antes de baixar.

terminal (Docker no Linux)
# permite que o contêiner use a tela (rode uma vez por sessão)
xhost +local:docker
docker run -it --rm --net=host \
  -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
  -v ~/ros2_ws:/root/ros2_ws \
  osrf/ros:<distro>-desktop
# dentro do contêiner o ROS já está ativado:
ros2 run turtlesim turtlesim_node

Como verificar: abre uma janela azul com uma tartaruga no meio. A pasta ~/ros2_ws do seu PC aparece dentro do contêiner em /root/ros2_ws, então o código que você escrever não some quando o contêiner fechar.

💡 E no Raspberry Pi 5?

Grave o Ubuntu Server da versão do par (26.04 para Lyrical, 24.04 para Jazzy) com o Raspberry Pi Imager e instale ros-<distro>-ros-base (sem as ferramentas gráficas). Visualize no PC: RViz e Gazebo pesam demais para o Pi. Se quiser manter o Raspberry Pi OS da Trilha 3, use a imagem ros:<distro>-ros-base no Docker.

Por que aprender

Instalar certo uma vez poupa horas depois. O Docker também é a saída para sala de aula: todos os alunos rodam exatamente a mesma imagem, sem diferenças entre máquinas.

Conceitos-chave

desktop
ROS + ferramentas gráficas
ros-base
enxuto, para o robô
source
ativa o ROS no terminal
Contêiner
ambiente igual em todo PC
4

🔗 Nós, tópicos, mensagens

Um nó é um processo que faz uma coisa: ler o LiDAR, girar os motores, planejar a rota. Nós conversam por tópicos, canais com nome como /cmd_vel ou /scan. Quem envia é o publisher; quem recebe é o subscriber. Um tópico pode ter vários de cada lado. O conteúdo tem formato fixo, a mensagem: /cmd_vel usa geometry_msgs/msg/Twist, com velocidade linear e angular.

🌱 Novo aqui?

Twist é a mensagem de "quero andar assim": linear.x em metros por segundo (para a frente) e angular.z em radianos por segundo (girar; positivo é anti-horário visto de cima). Um robô diferencial ignora os outros quatro campos. QoS (qualidade de serviço) é o combinado de entrega de cada tópico, como "guardar as últimas 10 mensagens".

teleop /cmd_vel base lidar /scan slam rviz2 publicaassina Twist: linear.x, angular.z

Como ler: caixas retas são nós (programas); cápsulas ciano são tópicos (canais). A seta sai de quem publica e entra em quem assina. Repare que /scan tem dois assinantes: o mesmo dado do laser alimenta o mapa e a tela sem nenhum código extra.

Objetivo: inspecionar um grafo de verdade com o turtlesim. Abra três terminais (todos com o ROS ativado).

terminal
# terminal 1: o simulador da tartaruga
ros2 run turtlesim turtlesim_node
# terminal 2: dirija com as setas do teclado
ros2 run turtlesim turtle_teleop_key
# terminal 3: olhe o grafo
ros2 node list
ros2 topic list -t
ros2 topic info /turtle1/cmd_vel
ros2 interface show geometry_msgs/msg/Twist
ros2 topic echo /turtle1/pose
# publique você mesmo: a tartaruga anda em círculo
ros2 topic pub --rate 2 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 1.0}, angular: {z: 0.8}}"

Como verificar

  • ✓ros2 node list mostra /turtlesim e /teleop_turtle.
  • ✓topic info diz "Publisher count: 1, Subscription count: 1" (2 publishers quando o topic pub estiver rodando).
  • ✓O echo imprime x, y e theta mudando enquanto a tartaruga anda. Para ver o grafo desenhado, rode rqt_graph.

Por que aprender

Quando o robô não anda, o primeiro passo é sempre o mesmo: ros2 topic echo /cmd_vel. Se o comando chega, o defeito está no motor; se não chega, está em quem publica. Ler o grafo pelo terminal é a ferramenta de diagnóstico mais usada de toda a trilha.

Conceitos-chave

Nó
um processo, uma tarefa
Tópico
canal com nome
Mensagem
formato do dado
topic echo
ver o que passa
5

🔁 Serviços, ações e parâmetros

Tópico é fluxo contínuo, sem resposta. Para os outros casos o ROS 2 tem mais três peças. Um serviço é pergunta e resposta rápida: "crie uma tartaruga aqui", "salve o mapa". Uma ação é uma tarefa demorada com progresso e possibilidade de cancelar: "vá até a cozinha" (o Nav2 inteiro funciona assim). Um parâmetro é um ajuste do nó que você muda sem recompilar: velocidade máxima, nome da porta serial, cor do fundo.

tópico serviço ação ABclienteservidorclienteservidor sem resposta pedidorespostarápido, uma vez objetivoprogressoresultadolongo, cancelável

Como ler: as linhas verticais são os dois lados da conversa, e o tempo corre para baixo. No tópico, A só envia. No serviço, o cliente espera uma única resposta. Na ação, o servidor manda progresso (tracejado) enquanto trabalha e, no fim, o resultado.

terminal (com o turtlesim aberto)
# serviço: cria uma segunda tartaruga
ros2 service list
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2.0, y: 2.0, theta: 0.0, name: 'robo2'}"
# parâmetro: muda a cor do fundo sem reiniciar
ros2 param list /turtlesim
ros2 param set /turtlesim background_r 150
# ação: gira até 90 graus (1,57 rad) e mostra o progresso
ros2 action list
ros2 action send_goal --feedback /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"

Como verificar: aparece uma tartaruga nova em (2, 2); o fundo fica arroxeado; o terminal da ação imprime várias linhas "Feedback: remaining: ..." e termina com "Goal finished with status: SUCCEEDED".

✓ Padrão certo

  • ✓Leitura de sensor e velocidade: tópico.
  • ✓Ligar um relé, salvar o mapa: serviço.
  • ✓Ir até um ponto, girar o braço: ação.

✗ Gambiarra comum

  • ✗Serviço que demora 30 s (trava quem chamou).
  • ✗Tópico "/pronto" para simular uma resposta.
  • ✗Constante no código que deveria ser parâmetro.

Por que aprender

No módulo 4.5 você vai mandar o robô até um ponto por uma ação do Nav2 e, no 4.4, salvar o mapa por um serviço. Reconhecer o padrão faz a documentação desses pacotes ficar legível.

Conceitos-chave

Serviço
pedido → resposta
Ação
objetivo, progresso, resultado
Parâmetro
ajuste sem recompilar
.srv / .action
formatos de interface
6

🐍 Seu primeiro nó em Python (rclpy) publicando e ouvindo

Agora você escreve os seus nós. Em Python a biblioteca é a rclpy. Todo nó segue o mesmo molde: inicia o rclpy, cria um objeto Node, registra publishers, subscribers e timers, e entrega o controle ao spin, que fica esperando eventos e chamando as suas funções. Você vai criar um pacote meu_robo com dois nós: falante publica uma frase duas vezes por segundo; ouvinte recebe e imprime.

falantetimer 0,5 spublicar()create_publisher /conversastd_msgs/String ouvintecreate_subscriptionao_receber(msg)imprime no log spin() mantém os dois nós vivos esperando eventos

Como ler: o relógio (timer) do falante chama publicar(), que joga uma String no tópico. O ouvinte não pergunta nada: o ROS chama ao_receber() toda vez que chega mensagem. Esse "você não chama, você é chamado" é o callback.

Objetivo: criar o workspace e o pacote. O ros2 pkg create gera a estrutura; depois você só substitui os arquivos pelos blocos abaixo.

terminal
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python --license MIT meu_robo --dependencies rclpy std_msgs
# crie os dois nós dentro da pasta de código do pacote
touch meu_robo/meu_robo/falante.py meu_robo/meu_robo/ouvinte.py
meu_robo/meu_robo/falante.py
# Nó que publica uma frase no tópico /conversa duas vezes por segundo
import rclpy
from rclpy.node import Node
from rclpy.executors import ExternalShutdownException
from std_msgs.msg import String

class Falante(Node):
    def __init__(self):
        super().__init__('falante')
        self.pub = self.create_publisher(String, 'conversa', 10)  # fila de 10 mensagens
        self.contador = 0
        self.timer = self.create_timer(0.5, self.publicar)        # chama publicar() a cada 0,5 s

    def publicar(self):
        msg = String()
        msg.data = f'Ola do robo #{self.contador}'
        self.pub.publish(msg)
        self.get_logger().info(f'Publicado: {msg.data}')
        self.contador += 1

def main(args=None):
    rclpy.init(args=args)
    no = Falante()
    try:
        rclpy.spin(no)
    except (KeyboardInterrupt, ExternalShutdownException):
        pass
    finally:
        no.destroy_node()
        rclpy.try_shutdown()

if __name__ == '__main__':
    main()
meu_robo/meu_robo/ouvinte.py
# Nó que assina /conversa e imprime cada mensagem recebida
import rclpy
from rclpy.node import Node
from rclpy.executors import ExternalShutdownException
from std_msgs.msg import String

class Ouvinte(Node):
    def __init__(self):
        super().__init__('ouvinte')
        self.sub = self.create_subscription(String, 'conversa', self.ao_receber, 10)

    def ao_receber(self, msg):
        self.get_logger().info(f'Ouvi: {msg.data}')

def main(args=None):
    rclpy.init(args=args)
    no = Ouvinte()
    try:
        rclpy.spin(no)
    except (KeyboardInterrupt, ExternalShutdownException):
        pass
    finally:
        no.destroy_node()
        rclpy.try_shutdown()

if __name__ == '__main__':
    main()

O setup.py diz ao ROS quais comandos o pacote oferece (os entry_points), e o package.xml lista as dependências. Substitua os dois gerados pelos mínimos abaixo.

meu_robo/setup.py
from setuptools import find_packages, setup

package_name = 'meu_robo'

setup(
    name=package_name,
    version='0.1.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages', ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='voce',
    maintainer_email='voce@exemplo.com',
    description='Primeiros nos do curso de robotica',
    license='MIT',
    entry_points={
        'console_scripts': [
            'falante = meu_robo.falante:main',
            'ouvinte = meu_robo.ouvinte:main',
        ],
    },
)
meu_robo/package.xml
<?xml version="1.0"?>
<package format="3">
  <name>meu_robo</name>
  <version>0.1.0</version>
  <description>Primeiros nos do curso de robotica</description>
  <maintainer email="voce@exemplo.com">voce</maintainer>
  <license>MIT</license>
  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <export>
    <build_type>ament_python</build_type>
  </export>
</package>
terminal
cd ~/ros2_ws
colcon build --symlink-install
source install/setup.bash
ros2 run meu_robo falante        # terminal 1
ros2 run meu_robo ouvinte        # terminal 2 (faça o source de novo nele)

Como verificar

  • ✓O colcon termina com "Summary: 1 package finished".
  • ✓Terminal 1: "[falante]: Publicado: Ola do robo #0", "#1"... Terminal 2: "[ouvinte]: Ouvi: Ola do robo #3".
  • ✓Num terceiro terminal, ros2 topic hz /conversa mostra cerca de 2 Hz.
  • ✗"Package 'meu_robo' not found"? Faltou source install/setup.bash naquele terminal.

💡 Desafio

Troque o falante para publicar geometry_msgs/msg/Twist em /turtle1/cmd_vel (adicione geometry_msgs ao package.xml) e faça a tartaruga desenhar um quadrado: anda 2 s, gira 90 graus, repete. É exatamente o que um nó de navegação faz com o seu robô.

Por que aprender

Este molde (classe Node, publisher, subscriber, timer, spin) é a base de todo nó da trilha: o que calcula a odometria no 4.3, o que manda o robô até um ponto no 4.5. Mudam os tipos de mensagem e a lógica do callback; a estrutura é a mesma.

Conceitos-chave

rclpy
ROS 2 em Python
Callback
o ROS chama você
entry_points
nome do ros2 run
colcon build
compila e instala

✅ Resumo do módulo

✓
ROS 2 é um grafo de programas pequenos que trocam dados por nome, via DDS, em um ou vários computadores.
✓
Lyrical para começar do zero, Jazzy se o seu material pede; Humble não, porque acaba em maio/2027.
✓
Instalação: repositório pela página oficial, ros-<distro>-desktop, ou Docker osrf/ros:<distro>-desktop.
✓
Tópico para fluxo, serviço para pergunta, ação para tarefa longa, parâmetro para ajuste.
✓
Nó em rclpy: Node + publisher/subscriber + timer + spin, empacotado com setup.py e compilado com colcon.

Para ir além

Próximo módulo

4.2 · Descrever e simular o robô: URDF, quadros TF, RViz2 e o robô andando no Gazebo.