Pular para o conteúdo principal

🕹️ Interfaces de Controle para Humanoides

Objetivo do Módulo

Dominar as principais formas de controlar um robô humanoide: desde joysticks tradicionais até realidade virtual e comandos de voz.


🎮 Tipos de Interface de Controle

Comparação Geral

InterfacePrecisãoLatênciaCurva de AprendizadoCustoMelhor Para
TecladoBaixaBaixa (10ms)Fácil$0Testes iniciais
Joystick GamepadMédiaBaixa (15ms)Fácil$30-60Operação geral
Joystick ProfissionalAltaBaixa (5ms)Moderada$200-500Tarefas de precisão
SpaceMouseMuito AltaBaixa (5ms)Difícil$150-400Manipulação 6-DOF
Tablet TouchscreenMédiaMédia (50ms)Fácil$300-1000Supervisão mobile
VR (Realidade Virtual)Muito AltaMédia (30ms)Difícil$300-1500Teleoperação imersiva
Comandos de VozBaixaAlta (200ms)Fácil$0Comandos de alto nível
Motion CaptureAltíssimaBaixa (10ms)Difícil$5k+Imitação de movimentos

⌨️ Controle por Teclado

Quando Usar

  • ✅ Testes rápidos em simulação
  • ✅ Aprender comandos básicos
  • ✅ Desenvolvimento de software (debug)
  • NUNCA em hardware real (muito impreciso)

Mapeamento Básico ROS2

Pacote: teleop_twist_keyboard

# Instalar
sudo apt install ros-humble-teleop-twist-keyboard

# Executar
ros2 run teleop_twist_keyboard teleop_twist_keyboard

Teclas Padrão:

        i      (frente)
j k l (esquerda, parar, direita)
, (trás)

u o (girar enquanto anda)
m . (girar enquanto anda para trás)

q/z : Aumentar/diminuir velocidade linear (10%)
w/x : Aumentar/diminuir velocidade angular (10%)

CTRL-C para sair

🎮 Joystick Gamepad (Xbox/PlayStation)

Hardware Recomendado

Xbox One Controller (com fio)

  • Preço: $40 (Amazon)
  • Conexão: USB
  • Latência: ~15ms
  • Compatibilidade: Linux nativo (driver xpad)

Configuração:

# Verificar se foi detectado
sudo apt install joystick
jstest /dev/input/js0

# Instalar pacote ROS2
sudo apt install ros-humble-joy
sudo apt install ros-humble-teleop-twist-joy

Configuração ROS2 Joy

Arquivo de configuração: config/joy_teleop.yaml

teleop_twist_joy_node:
ros__parameters:
# Eixos do joystick (valores de 0 a N, conforme seu controle)
axis_linear: 1 # Stick esquerdo vertical (frente/trás)
axis_angular: 2 # Stick direito horizontal (girar)

# Escala de velocidade
scale_linear: 1.0 # m/s máximo
scale_angular: 2.0 # rad/s máximo

# Botão "turbo" (segurar para velocidade máxima)
enable_button: 5 # Botão RB (bumper direito)

# Botão "slow mode" (precisão)
enable_turbo_button: 4 # Botão LB (bumper esquerdo)

Lançar nó:

ros2 launch teleop_twist_joy teleop-launch.py joy_config:='xbox'

Mapeamento Avançado para Humanoides

# Exemplo: Controlar Unitree H1
humanoid_teleop:
ros__parameters:
# Movimento da base
axis_walk_forward: 1 # Stick esquerdo Y
axis_walk_strafe: 0 # Stick esquerdo X
axis_turn: 2 # Stick direito X

# Controle de altura (agachar)
axis_height: 5 # Gatilhos L2/R2 (analogicos)

# Braços
button_arm_mode: 3 # Botão Y (alternar modo braço)
axis_left_arm_x: 0 # Stick esquerdo X (quando em modo braço)
axis_left_arm_y: 1 # Stick esquerdo Y

# Comandos discretos
button_stand: 0 # A (posição neutra)
button_sit: 1 # B (sentar)
button_wave: 2 # X (acenar)
button_emergency_stop: 6 # Botão central esquerdo (E-STOP)

# Sensibilidade
deadzone: 0.1 # Zona morta (evitar drift)
max_linear_vel: 1.5 # m/s
max_angular_vel: 1.0 # rad/s

🖱️ SpaceMouse (Controle 6-DOF)

O Que é 6-DOF?

6 Degrees of Freedom (6 Graus de Liberdade):

  • Translação: X, Y, Z (mover nos 3 eixos)
  • Rotação: Roll, Pitch, Yaw (girar nos 3 eixos)

Exemplo de Uso:

  • Controlar mão do robô no espaço 3D
  • Posicionar câmera da cabeça do robô
  • Teleoperar braço com precisão milimétrica

Hardware

3Dconnexion SpaceMouse Wireless

  • Preço: $150
  • Conexão: USB wireless receiver
  • Precisão: 0.01mm de resolução
  • Uso Profissional: CAD, robótica, simulação

Integração ROS2

Driver: spacenav_node (ROS2)

# Instalar driver do kernel
sudo apt install spacenavd libspnav-dev

# Clonar pacote ROS2
cd ~/ros2_ws/src
git clone https://github.com/ros-drivers/joystick_drivers.git -b ros2
cd ~/ros2_ws
colcon build --packages-select spacenav

# Iniciar daemon
sudo systemctl start spacenavd

# Lançar nó ROS2
ros2 run spacenav spacenav_node

Tópico publicado:

/spacenav/twist  (geometry_msgs/Twist)
- linear.x/y/z: translação
- angular.x/y/z: rotação

Exemplo de Uso: Controlar Efetor Final (Mão)

import rclpy
from geometry_msgs.msg import Twist, Pose
from moveit_msgs.srv import GetPositionIK

class SpaceMouseTeleop(Node):
def __init__(self):
super().__init__('spacemouse_teleop')

# Subscribe to SpaceMouse
self.sub = self.create_subscription(
Twist, '/spacenav/twist', self.spacemouse_callback, 10
)

# Publicar pose do efetor final
self.ee_pose_pub = self.create_publisher(
Pose, '/target_end_effector_pose', 10
)

# Pose atual (inicializar em posição neutra)
self.current_pose = Pose()
self.current_pose.position.x = 0.5 # 50cm à frente
self.current_pose.position.z = 1.0 # 1m de altura

def spacemouse_callback(self, msg):
# Fator de escala (ajustar conforme necessário)
scale_translation = 0.001 # 1mm por unidade
scale_rotation = 0.01 # 0.01 rad por unidade

# Atualizar posição
self.current_pose.position.x += msg.linear.x * scale_translation
self.current_pose.position.y += msg.linear.y * scale_translation
self.current_pose.position.z += msg.linear.z * scale_translation

# Atualizar orientação (usando quaternion - simplificado)
# (Em produção, usar biblioteca de transformação como tf2)

# Publicar nova pose
self.ee_pose_pub.publish(self.current_pose)
self.get_logger().info(f'EE Position: x={self.current_pose.position.x:.3f}')

📱 Tablet Touchscreen

Vantagens da Interface Mobile

  • Mobilidade (acompanhar robô andando)
  • Interface visual rica (botões grandes, gráficos)
  • Multitouch (zoom, pan em mapas)
  • Câmeras integradas (AR - Realidade Aumentada)

Opções de Software

Descrição: Interface web para ROS2 (similar ao rviz, mas no navegador)

Vantagens:

  • ✅ Funciona em qualquer tablet (iPad, Android, Surface)
  • ✅ Sem instalação (apenas acessar URL)
  • ✅ Customizável (HTML/CSS/JS)

Setup:

# Instalar Foxglove Studio (substituto do Webviz)
# Acesse: https://foxglove.dev/download
# Ou use versão web: https://studio.foxglove.dev/

# Lançar ponte ROS2 → WebSocket
sudo apt install ros-humble-rosbridge-suite
ros2 launch rosbridge_server rosbridge_websocket_launch.xml

No tablet:

  1. Abrir navegador
  2. Ir para https://studio.foxglove.dev/
  3. Conectar em ws://IP_DO_ROBOT:9090
  4. Adicionar painéis: Câmera, Telemetria, Mapa, Joystick Virtual

🥽 Realidade Virtual (VR)

Por Que VR para Teleoperação?

Vantagens:

  • Imersão total (ver pelo "olhos" do robô)
  • Controle intuitivo (mover seus braços = mover braços do robô)
  • Percepção de profundidade (crucial para manipulação)
  • Treinamento seguro (simular cenários perigosos)

Desvantagens:

  • ❌ Latência (30-50ms causa enjoo)
  • ❌ Fadiga (uso contínuo > 1h é cansativo)
  • ❌ Custo (headset + workstation potente)

Hardware VR para Robótica

HeadsetPreçoTrackingLatênciaUso Recomendado
Meta Quest 3$500Inside-out (câmeras)~35msSimulação, demos
Valve Index$1000External (base stations)~25msTeleoperação precisa
HTC Vive Pro 2$1400External (SteamVR 2.0)~20msProfissional
Varjo XR-4$4000Mixed Reality (alta res)~15msIndustrial (NASA, BMW)

Stack de Software

Descrição: Renderizar câmeras do robô em VR usando Unity

Arquitetura:

Robot (ROS2) → ROS# Bridge → Unity (VR) → Meta Quest 3

Passos:

  1. Instalar Unity 2022 LTS

  2. Instalar ROS# Package

    # No computador do robô
    sudo apt install ros-humble-rosbridge-suite
    ros2 launch rosbridge_server rosbridge_websocket_launch.xml
  3. Configurar Unity:

    • Asset Store → ROS TCP Connector
    • Criar objeto ROS Connection com IP do robô
  4. Subscriber de Câmera:

    // Script C# no Unity
    using RosSharp.RosBridgeClient;
    using UnityEngine;

    public class RobotCameraVR : MonoBehaviour
    {
    RosSocket rosSocket;
    string topic = "/robot/camera/image_raw";

    void Start()
    {
    rosSocket = new RosSocket("ws://192.168.1.100:9090");
    rosSocket.Subscribe<sensor_msgs.Image>(topic, UpdateTexture);
    }

    void UpdateTexture(sensor_msgs.Image imageMsg)
    {
    // Converter ROS Image → Unity Texture2D
    // Aplicar em um Quad na frente da câmera VR
    }
    }

🎤 Comandos de Voz

Quando Usar

  • ✅ Comandos de alto nível ("vá para a cozinha")
  • ✅ Mãos ocupadas (operador carregando equipamento)
  • ✅ Acessibilidade (pessoas com mobilidade reduzida)
  • ❌ Ambientes ruidosos (fábrica com > 80 dB)
  • ❌ Comandos de precisão (difícil dizer "mova 5.3cm")

Stack de Reconhecimento de Voz

Prós: Alta precisão, multi-idioma Contras: Pago ($0.006 por 15s), precisa internet

import rclpy
from google.cloud import speech_v1
from std_msgs.msg import String

class VoiceCommands(Node):
def __init__(self):
super().__init__('voice_commands')
self.client = speech_v1.SpeechClient()
self.cmd_pub = self.create_publisher(String, '/voice_commands', 10)

def listen(self):
config = speech_v1.RecognitionConfig(
encoding=speech_v1.RecognitionConfig.AudioEncoding.LINEAR16,
sample_rate_hertz=16000,
language_code='pt-BR', # Português Brasil
)

# Streaming audio (microfone)
streaming_config = speech_v1.StreamingRecognitionConfig(config=config)

# Processar resposta
for response in responses:
for result in response.results:
transcript = result.alternatives[0].transcript
self.process_command(transcript)

def process_command(self, text):
text = text.lower()

if 'sentar' in text:
cmd = String()
cmd.data = 'sit'
self.cmd_pub.publish(cmd)
elif 'levantar' in text or 'ficar em pé' in text:
cmd = String()
cmd.data = 'stand'
self.cmd_pub.publish(cmd)
elif 'parar' in text or 'pare' in text:
cmd = String()
cmd.data = 'emergency_stop'
self.cmd_pub.publish(cmd)
# Adicionar mais comandos...

Lista de Comandos de Voz Recomendados

# Comandos seguros para voz (inequívocos)
comandos:
movimentacao:
- "andar para frente"
- "andar para trás"
- "girar para esquerda"
- "girar para direita"
- "parar" # SEMPRE deve funcionar!

posturas:
- "sentar"
- "levantar"
- "agachar"
- "posição neutra"

emergencia:
- "parada de emergência"
- "desligar motores"

tarefas:
- "ir para cozinha" # Requer Nav2 com mapa
- "pegar caixa" # Requer detecção de objetos
- "seguir pessoa" # Requer tracking visual

# ❌ EVITAR comandos ambíguos:
- "mais rápido" (quanto mais? 10%? 50%?)
- "mover braço direito" (para onde? quanto?)
- "um pouco para esquerda" (impreciso)

🎯 Comparação Prática: Qual Interface Usar?

Cenário 1: Desenvolvimento de Software (Simulação)

Escolha: Teclado + Mouse

  • Rápido para testar comandos
  • Não precisa hardware extra
  • Fácil debug (logs no terminal)

Cenário 2: Operação em Fábrica (Produção)

Escolha: Tablet + Comandos de Voz

  • Operador pode andar pela linha de produção
  • Voz para comandos rápidos ("parar", "retomar")
  • Tablet para visualizar status

Cenário 3: Teleoperação Complexa (Resgate, Demolição)

Escolha: VR + Joystick Profissional (HOTAS)

  • VR para imersão e percepção espacial
  • Joystick para controle preciso de movimento
  • Feedback háptico (sentir resistência ao pegar objeto)

Cenário 4: Pesquisa Acadêmica (Motion Capture)

Escolha: Motion Capture (Vicon, OptiTrack)

  • Imitar movimentos humanos com alta precisão
  • Coletar dados para machine learning
  • Custo alto, mas necessário para certos estudos

🛠️ Projeto Prático: Implementar Multi-Interface

Objetivo: Criar sistema que aceita comandos de teclado, joystick E voz simultaneamente.

Arquitetura:

[Teclado] ─┐
├─→ [Arbitrator Node] ─→ [Robot Controller]
[Joystick]─┤ (prioridade)

[Voz] ─────┘

Lógica de Prioridade:

  1. E-Stop (voz ou botão): SEMPRE tem prioridade máxima
  2. Joystick: Prioridade alta (controle fino)
  3. Voz: Prioridade média (comandos de alto nível)
  4. Teclado: Prioridade baixa (backup)

Código Arbitrator:

class CommandArbitrator(Node):
def __init__(self):
super().__init__('command_arbitrator')

# Subscribers
self.sub_kbd = self.create_subscription(Twist, '/cmd_kbd', self.kbd_cb, 10)
self.sub_joy = self.create_subscription(Twist, '/cmd_joy', self.joy_cb, 10)
self.sub_voice = self.create_subscription(String, '/cmd_voice', self.voice_cb, 10)

# Publisher final
self.pub = self.create_publisher(Twist, '/cmd_vel', 10)

# Estado
self.last_command_source = None
self.last_command_time = self.get_clock().now()

def joy_cb(self, msg):
# Joystick sempre sobrescreve outros
self.publish_command(msg, 'joystick')

def voice_cb(self, msg):
# Voz só funciona se joystick não foi usado nos últimos 2s
elapsed = (self.get_clock().now() - self.last_command_time).nanoseconds / 1e9
if self.last_command_source != 'joystick' or elapsed > 2.0:
# Converter comando de voz em Twist
cmd = self.voice_to_twist(msg.data)
self.publish_command(cmd, 'voice')

def publish_command(self, msg, source):
self.pub.publish(msg)
self.last_command_source = source
self.last_command_time = self.get_clock().now()
self.get_logger().info(f'Command from {source}')

📚 Recursos e Ferramentas

Pacotes ROS2 Essenciais

sudo apt install ros-humble-joy
sudo apt install ros-humble-teleop-twist-joy
sudo apt install ros-humble-teleop-twist-keyboard
sudo apt install ros-humble-rosbridge-suite # Para web/mobile

Tutoriais Recomendados


🔗 Próximos Passos

Próximo Módulo

📊 Telemetria e Monitoramento →

Aprenda a monitorar o status do robô em tempo real: temperatura, bateria, erros e logs.