← Voltar à Trilha 2 MÓDULO 2.4

🔗 ROS2: Middleware para Robótica Real

ROS2 é a cola entre percepção, planejamento e controle no robô físico. Aqui você modela um VLA como nó de inferência, sincroniza câmera+estado com QoS, transforma poses com tf2, planeja com MoveIt2 e fecha o loop em tempo real.

6
Tópicos
40
Minutos
Inter.
Nível
Prática
Tipo

Conteúdo detalhado

Grafo de nós: do frame ao torque /cameraImage+depth /vla_nodeinferência /tf2frames /controllertrajetória 🦾 /armtorque tópicos (pub/sub) · serviços · ações · QoS
1

🔹 ROS2 vs ROS1: DDS, tempo real, segurança

ROS2 reescreveu o middleware sobre DDS (Data Distribution Service): comunicação descentralizada (sem roscore único), QoS configurável, suporte a tempo real e segurança (SROS2). Os blocos são nós que conversam por tópicos (pub/sub), serviços (req/resp) e ações (objetivos longos com feedback).

📊 Primitivas de comunicação

  • Tópico — fluxo contínuo, muitos-para-muitos (ex: imagens, juntas).
  • Serviço — chamada síncrona única (ex: "ligar gripper").
  • Ação — objetivo de longa duração com feedback/cancelamento (ex: "mover para pose").
  • Parâmetro — config em runtime por nó.

⚡ Dica prática

Use tópico para fluxo contínuo (imagens, juntas), serviço para chamadas pontuais e ação para "mover para a pose X" — onde você precisa de feedback de progresso e poder cancelar. Escolher a primitiva errada (ex: tópico para um goal único) gera código frágil.

DDS

Transporte descentralizado.

Unidade de processo.

Ação

Goal longo + feedback.

SROS2

Segurança e auth.

2

🔹 Anatomia de um sistema: percepção, planejamento, controle

Um sistema ROS2 decompõe o robô em nós com responsabilidade única: drivers de câmera/RGB-D, nó de percepção, planejador, controlador de junta. Essa modularidade permite trocar a "policy" sem mexer no driver do braço — exatamente onde o VLA entra.

📊 Nós típicos de uma célula VLA

  • /camera — driver RealSense publica RGB + depth.
  • /vla_node — inferência da policy, publica ações.
  • /robot_state_publisher + /tf2 — árvore de frames.
  • /controller_manager — ros2_control executa trajetória.
# inspecionar o sistema vivo
ros2 node list
ros2 topic list
ros2 topic hz /camera/color/image_raw     # checar frequência
ros2 topic echo /joint_states --once
ros2 run rqt_graph rqt_graph              # visualizar o grafo

⚡ Dica prática

Antes de escrever código, mapeie o grafo com rqt_graph e confira a hz de cada tópico. Câmera a 60 Hz mas /joint_states a 10 Hz vira gargalo silencioso na sincronização.

Percepção

Nó de visão/RGB-D.

Planejamento

VLA ou MoveIt2.

Controle

ros2_control / driver.

Modularidade

Trocar policy isolada.

3

🔹 Integrar um VLA: nó de inferência, sincronização, QoS

O VLA vira um nó rclpy que assina câmera + estado, roda o forward e publica o comando. Imagem e estado precisam vir do mesmo instante: use message_filters (ApproximateTimeSynchronizer) e escolha a QoS certa — BEST_EFFORT para imagem (descarta atrasados), RELIABLE para comandos.

import rclpy
from rclpy.node import Node
from message_filters import Subscriber, ApproximateTimeSynchronizer
from sensor_msgs.msg import Image, JointState
from rclpy.qos import QoSProfile, ReliabilityPolicy

class VLANode(Node):
    def __init__(self):
        super().__init__("vla_node")
        qos = QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT)
        img = Subscriber(self, Image, "/camera/color/image_raw", qos_profile=qos)
        st  = Subscriber(self, JointState, "/joint_states")
        sync = ApproximateTimeSynchronizer([img, st], queue_size=2, slop=0.02)
        sync.registerCallback(self.on_obs)

    def on_obs(self, img, state):
        action = self.policy(preprocess(img), state.position)  # forward VLA
        self.pub.publish(to_cmd(action))                       # ação chunked

rclpy.init(); rclpy.spin(VLANode())

✓ Fazer

  • Sincronizar imagem+estado por timestamp (slop pequeno).
  • QoS BEST_EFFORT/depth=1 para sensores de alta taxa.
  • Rodar inferência em thread/callback group separado.

✗ Evitar

  • Casar QoS incompatível (RELIABLE vs BEST_EFFORT) — não conecta.
  • Bloquear o executor com forward pesado no callback principal.
  • Usar imagem e estado de instantes diferentes.

rclpy

API Python do ROS2.

message_filters

Sync por timestamp.

QoS

Reliability/depth.

callback group

Concorrência segura.

4

🔹 tf2 e frames: pose do modelo → comando do braço

O VLA prevê uma pose num frame — geralmente da câmera. O braço espera comandos no frame da base. tf2 mantém a árvore de transformações temporizada (base_link → camera_link → tool0) e converte poses entre frames respeitando o timestamp.

from tf2_ros import Buffer, TransformListener
import tf2_geometry_msgs

buf = Buffer(); TransformListener(buf, node)
# transformar a pose prevista (frame da câmera) -> frame base do braço
pose_base = buf.transform(pose_cam, "base_link", timeout=Duration(seconds=0.1))
# agora a pose está no frame que o controlador entende

📊 Erros clássicos de frame

  • Calibração mão-olho ruim — câmera↔base errada desloca tudo.
  • Timestamp errado — transformar com TF antigo/futuro causa salto.
  • Convenção de eixos — REP-103: x para frente, z para cima.

tf2

Árvore de frames.

Mão-olho

Calibração câmera↔base.

REP-103

Convenção de eixos.

Timestamp

TF temporizado.

5

🔹 MoveIt2 e controladores: trajetória, limites, segurança

MoveIt2 faz planejamento de movimento com checagem de colisão, cinemática (IK/FK) e time parameterization respeitando limites de junta. Em VLA reativo de alta frequência, muitas vezes você ignora o planner e envia setpoints direto via ros2_control — mas MoveIt2 entra para approach seguro e detecção de colisão.

1

Planejar (MoveIt2)

OMPL/Pilz gera trajetória livre de colisão; útil para o movimento de aproximação.

2

Controlar (ros2_control)

JointTrajectoryController executa; VLA pode injetar setpoints reativos.

3

Proteger

Limites de velocidade/torque, e-stop por hardware, workspace bounds.

MoveIt2

Planejamento + colisão.

ros2_control

Camada de controlador.

IK/FK

Cinemática.

E-stop

Segurança física.

6

🔹 Latência e tempo real: do frame ao torque, jitter, watchdogs

A cadeia câmera → inferência → tf2 → controlador → torque tem um orçamento de latência. Pior que latência alta é o jitter (variância): um loop irregular desestabiliza o controle. Use kernel PREEMPT_RT, prioridade de tempo real e watchdogs que param o braço se o comando atrasar.

# watchdog: se não chegar comando em 100ms, freia
self.create_timer(0.1, self.watchdog)
def watchdog(self):
    if (self.now() - self.last_cmd) > 0.1:
        self.hold_position()   # fail-safe

# medir latência fim-a-fim do pipeline
ros2 topic delay /arm_command

⚡ Dica prática

Action chunking (do M2.1) é seu aliado: prever K passos amortiza a inferência e tolera o jitter da rede ROS, mantendo o loop de torque suave mesmo que o VLA re-infira só a cada N ciclos.

Latência

Frame → torque.

Jitter

Variância do loop.

PREEMPT_RT

Kernel tempo real.

Watchdog

Fail-safe por timeout.

✓ Fazer

  • Medir latência fim-a-fim e o jitter (p99), não só a média.
  • Watchdog que freia o braço se o comando atrasar.
  • Action chunking para tolerar jitter da rede ROS.

✗ Evitar

  • Loop de controle sem kernel RT em tarefa crítica.
  • Enviar torque sem timeout/limite de segurança.
  • Otimizar latência média ignorando picos de jitter.

✅ Resumo do módulo

ROS2 sobre DDS — nós, tópicos, serviços, ações e QoS.
VLA como nó — sincronize câmera+estado e escolha a QoS certa.
tf2 — converta pose do modelo para o frame do braço.
MoveIt2 + ros2_control — planejamento seguro e execução de trajetória.
Tempo real — controle jitter com RT, chunking e watchdogs.

Próximo módulo

2.5 — Hardware: braços, garras, sensores RGB-D e compute de borda Jetson, o corpo onde o ROS2 roda.