Sistema de Comunicação por WebSockets
Sistema responsável pela comunicação em tempo real entre robô, backend e frontend do projeto Tour Inteli, incluindo chat com visitantes e controle de checkpoints.
1. Introdução
Este documento descreve a arquitetura, os componentes e os fluxos do sistema de comunicação em tempo real do robô do Inteli. O sistema de WebSockets possui dois módulos principais:
1.1 Módulo de Chat e Conversação
- Recebe perguntas dos visitantes (texto ou áudio)
- Envia respostas em texto e áudio
- Sincroniza múltiplos dispositivos (painel do operador, robô, turista)
- Realiza transcrição de fala (STT) e síntese de voz (TTS)
1.2 Módulo de Controle de Checkpoints
- Comunica eventos de navegação do robô (início/fim de checkpoints)
- Sincroniza status do robô em tempo real com o backend e frontend
- Atualiza automaticamente o banco de dados com timestamps reais
- Gerencia comandos de controle (play, stop, status)
A comunicação ocorre em tempo real via WebSockets, centralizada pelo backend implementado em Rust com Actix-Web.
2. Visão Geral da Arquitetura
O sistema utiliza três canais de WebSockets:
- Text WebSocket → para mensagens em texto (chat)
- Audio WebSocket → para mensagens de áudio (entrada e saída do chat)
- Robot WebSocket → para controle de checkpoints e sincronização de navegação
Diagrama da Arquitetura Completa
┌──────────────────────────────────────────────────────────────────────┐
│ FRONTEND (React/JS) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │
│ │ Text WebSocket │ │ Audio WebSocket │ │ Robot WebSocket │ │
│ │ (Chat) │ │ (Chat) │ │ (Checkpoints) │ │
│ └────────┬─────────┘ └────────┬─────────┘ └────────┬────────┘ │
└───────────┼──────────────────────┼──────────────────────┼───────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ BACKEND (Actix-Web + Rust) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Broadcast Server (Central Hub - Chat) │ │
│ │ - Conexões de texto e áudio │ │
│ │ - Broadcast de mensagens │ │
│ │ - Conversão Texto→Áudio (TTS) │ │
│ │ - Exclusão de eco por cliente │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Robot Client + Frontend Server (Checkpoints) │ │
│ │ - Cliente WebSocket → Conecta ao servidor Python do robô │ │
│ │ - Servidor WebSocket → Aceita conexões do frontend │ │
│ │ - Relay inteligente de eventos e comandos │ │
│ │ - Atualização automática do banco de dados (PostgreSQL) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ ▲ │ │
│ │ WebSocket Client │ Broadcast │
│ │ (tokio-tungstenite) │ (actix-ws) │
└────────┼─────────────────────────────────────────────┼────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ ROBOT (Python + aiohttp) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ WebSocket Server (move_path.py) │ │
│ │ - Recebe comandos do backend (play, stop, get_status) │ │
│ │ - Envia eventos de checkpoint em tempo real │ │
│ │ - Controla movimento físico do robô via WebRTC │ │
│ └────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
▲
│ WebRTC (movimento físico)
▼
🤖 Robô Físico3. Componentes Principais
MÓDULO 1: CHAT E CONVERSAÇÃO
3.1 Broadcast Server (broadcast.rs)
O que é?
O Broadcast Server é o "cérebro" do sistema de comunicação de chat. Ele funciona como um ponto central que recebe mensagens e distribui para todos os clientes conectados.
O que ele faz?
-
Gerencia clientes conectados
- Clientes de texto
- Clientes de áudio
-
Distribui mensagens
- Texto → todos clientes de texto
- Áudio → todos clientes de áudio
-
Converte texto em áudio
- Usando o serviço ML de TTS, quando necessário
-
Evita eco
- O cliente que enviou a mensagem não recebe sua própria mensagem (evitando duplicação).
Estrutura interna (simplificada)
pub struct BroadcastServer {
text_clients: HashMap<String, Recipient<BroadcastMessage>>,
audio_clients: HashMap<String, Recipient<BroadcastAudio>>,
ml_endpoint: String,
}Mensagens que ele entende
| Mensagem | Significado |
|---|---|
Connect | Cliente de texto entrou |
ConnectAudio | Cliente de áudio entrou |
Disconnect | Cliente saiu |
Broadcast | Enviar texto para todos |
BroadcastAudioMessage | Enviar áudio para todos |
RequestTTS | Transformar texto em áudio e enviar |
3.2 Text WebSocket Handler (text_ws.rs)
O que é?
É o componente responsável por lidar com mensagens de texto enviadas pelos clientes.
O que ele faz?
- TextWebSocket recebe uma mensagem de texto do cliente.
- Envia essa mensagem para o endpoint
/v1/modelo. - Recebe a resposta do modelo.
- Retorna a resposta ao cliente.
- Envia essa mesma resposta para conversão TTS (para que os clientes de áudio também a recebam).
- Usa o Broadcast Server para sincronizar a resposta com todos os dispositivos.
Exemplo de mensagem enviada pelo cliente
{
"type": "text",
"texto": "Qual é a história deste lugar?",
"checkpoint_id": 123,
"estado": "active",
"question_topic": "história",
"tour_id": 456
}Exemplo de resposta
{
"texto": "Este lugar tem uma história fascinante...",
"message_type": "resposta"
}3.3 Audio WebSocket Handler (audio_ws.rs)
O que é?
Esse componente recebe áudios dos usuários, realiza transcrição (STT), envia texto para o modelo e depois converte a resposta em áudio (TTS).
Fluxo 1: Usuário fala (STT)
Cliente envia áudio (base64)
→ AudioWebSocket decodifica áudio
→ STT transcreve para texto
→ Modelo recebe texto
→ Modelo retorna resposta
→ TTS converte resposta em áudio
→ Texto e áudio retornam ao cliente
→ Broadcast para outros clientesFluxo 2: Usuário envia texto pelo Audio WS
Cliente envia texto
→ Modelo retorna resposta
→ TTS converte resposta em áudio
→ Sistema envia texto e áudio ao cliente
→ Broadcast para todos os clientes3.4 Modelo Endpoint (modelo.rs)
O que é?
Um endpoint HTTP usado para enviar perguntas ao modelo de IA responsável por gerar respostas.
O que ele faz?
- Recebe uma pergunta via POST
- Salva a pergunta no banco.
- Envia para o modelo externo.
- Salva a resposta no banco.
- Atualiza o estado da pergunta.
- Retorna a resposta ao WebSocket.
Endpoint
POST /v1/modeloMÓDULO 2: CONTROLE DE CHECKPOINTS
3.5 Robot Client (robot_client.rs)
O que é?
Cliente WebSocket que conecta ao servidor Python do robô para receber eventos de navegação e enviar comandos de controle.
O que ele faz?
- Conecta ao robô via WebSocket (tokio-tungstenite)
- Recebe eventos do robô (checkpoint_started, checkpoint_completed, emergency_stop)
- Envia comandos (play, stop, get_status)
- Atualiza o banco de dados automaticamente com timestamps reais
- Retenta conexão a cada 5 segundos se o robô estiver offline
- Broadcast para frontend via canal broadcast
Estrutura interna
pub struct RobotClient {
robot_ip: String,
writer: Arc<Mutex<Option<WsWriter>>>,
frontend_tx: broadcast::Sender<FrontendEvent>,
db_pool: PgPool,
}Eventos recebidos do robô
| Evento | Quando ocorre | Ação no Backend |
|---|---|---|
connected | Conexão inicial estabelecida | Envia status inicial para frontend |
checkpoint_started | Robô inicia movimento para checkpoint | UPDATE banco: status='running', inicio_real=NOW() |
checkpoint_completed | Robô chega no checkpoint | UPDATE banco: status='finished', fim_real=NOW() |
emergency_stop | Parada de emergência acionada | UPDATE banco: status='skipped' (checkpoint atual) |
robot_connected | Robô físico conecta via WebRTC | Notifica frontend que robô está online |
Comandos enviados ao robô
RobotCommand::play() // Executar próximo checkpoint
RobotCommand::stop() // Parada de emergência
RobotCommand::get_status() // Consultar status atualExemplo de atualização no banco
// Quando checkpoint inicia
sqlx::query(
"UPDATE checkpoints
SET status = $1, inicio_real = $2
WHERE tipo = $3 AND ordem = $4"
)
.bind("running")
.bind(inicio_dt)
.bind(&tipo)
.bind(ordem)
.execute(db_pool)
.await?;
// Quando checkpoint completa
sqlx::query(
"UPDATE checkpoints
SET status = $1, fim_real = $2
WHERE tipo = $3 AND ordem = $4"
)
.bind("finished")
.bind(fim_dt)
.bind(&tipo)
.bind(ordem)
.execute(db_pool)
.await?;3.6 Frontend Server (frontend_server.rs)
O que é?
Servidor WebSocket que aceita conexões do frontend para enviar eventos de checkpoint em tempo real e receber comandos de controle.
O que ele faz?
- Aceita conexões WebSocket do frontend (actix-ws)
- Relata eventos do robô para o frontend em tempo real
- Recebe comandos do frontend (play, stop, status)
- Encaminha comandos para o RobotClient
- Usa tokio::select! para gerenciar fluxo bidirecional
Handler principal
pub async fn ws_frontend_handler(
req: HttpRequest,
stream: web::Payload,
app_state: web::Data<AppState>,
) -> Result<HttpResponse, Error>Fluxo bidirecional
tokio::select! {
// Recebe eventos do robô → Envia para frontend
Ok(event) = frontend_rx.recv() => {
session.text(json).await?;
}
// Recebe comandos do frontend → Envia para robô
Some(Ok(msg)) = msg_stream.next() => {
let cmd = serde_json::from_str::<FrontendCommand>(&text)?;
robot_client.send_command(cmd).await?;
}
}3.7 WebSocket Models (websocket.rs)
Estruturas de dados
RobotEvent (Robô → Backend)
pub enum RobotEvent {
Connected { status: RobotStatus },
CheckpointStarted { tipo: String, ordem: i32, status: String, inicio_real: String },
CheckpointCompleted { tipo: String, ordem: i32, status: String, inicio_real: String, fim_real: String },
EmergencyStop { tipo: Option<String>, ordem: Option<i32> },
RobotConnected { status: String },
}FrontendEvent (Backend → Frontend)
pub enum FrontendEvent {
RobotStatus { robot_connected: bool, is_running: bool, current_checkpoint: Option<String> },
CheckpointStarted { tipo: String, ordem: i32, status: String, inicio_real: DateTime<Utc> },
CheckpointCompleted { tipo: String, ordem: i32, status: String, inicio_real: DateTime<Utc>, fim_real: DateTime<Utc> },
EmergencyStop { tipo: Option<String>, ordem: Option<i32> },
Error { message: String },
}FrontendCommand (Frontend → Backend)
pub enum FrontendCommand {
Play,
Stop,
GetStatus,
}4. Fluxos de Comunicação
4.1 Fluxo de Checkpoint Completo
1. Frontend envia comando
Frontend → Backend: { "command": "play" }
2. Backend encaminha para robô
Backend (RobotClient) → Robot Server: { "action": "play" }
3. Robô inicia movimento
Robot Server → Backend: { "event": "checkpoint_started", "tipo": "recepcao", "ordem": 1, ... }
4. Backend atualiza banco de dados
UPDATE checkpoints SET status='running', inicio_real='2025-12-15T14:02:35Z' WHERE tipo='recepcao'
5. Backend relata para frontend
Backend → Frontend: { "event": "checkpoint_started", "tipo": "recepcao", ... }
6. Frontend atualiza UI
UI mostra: "🚀 Indo para Recepção..."
Perguntas bloqueadas até chegada
7. Robô chega no destino
Robot Server → Backend: { "event": "checkpoint_completed", "tipo": "recepcao", "fim_real": "..." }
8. Backend atualiza banco
UPDATE checkpoints SET status='finished', fim_real='2025-12-15T14:08:12Z' WHERE tipo='recepcao'
9. Backend relata para frontend
Backend → Frontend: { "event": "checkpoint_completed", "tipo": "recepcao", ... }
10. Frontend libera perguntas
UI mostra: "✅ Chegou na Recepção! Faça suas perguntas"
Perguntas do checkpoint 'recepcao' liberadas4.2 Fluxo de Parada de Emergência
1. Frontend envia stop
Frontend → Backend: { "command": "stop" }
2. Backend encaminha
Backend → Robot: { "action": "stop" }
3. Robô para imediatamente
Robot Server → Backend: { "event": "emergency_stop", "tipo": "auditorio", "ordem": 2 }
4. Backend atualiza banco
UPDATE checkpoints SET status='skipped' WHERE tipo='auditorio' AND status='running'
5. Backend notifica frontend
Backend → Frontend: { "event": "emergency_stop", "tipo": "auditorio" }
6. Frontend mostra alerta
UI: "🛑 Tour interrompido! Checkpoint 'Auditório' foi pulado"4.3 Sincronização Entre Clientes (Chat)
O sistema implementa um padrão publish-subscribe através do BroadcastServer:
-
Clientes de Texto recebem:
- Perguntas de outros usuários
- Respostas do modelo (tanto de clientes de texto quanto de áudio)
-
Clientes de Áudio recebem:
- Áudio das respostas (convertidas via TTS)
-
Exclusão de Eco:
- Cada mensagem broadcast pode especificar um
exclude_client - O cliente que originou a mensagem não recebe seu próprio broadcast
- Evita feedback loops e duplicação de mensagens
- Cada mensagem broadcast pode especificar um
5. Integração com Banco de Dados
Tabela: checkpoints
| Coluna | Tipo | Preenchimento |
|---|---|---|
id | SERIAL (PK) | Auto-gerado |
tour_id | INT (FK) | Criação do tour |
tipo | TEXT | Criação do tour (recepcao, auditorio, atelie, etc.) |
ordem | INT | Criação do tour (1, 2, 3, 4, 5) |
status | TEXT | Inicial: pending → running → finished/skipped |
inicio_previsto | TIMESTAMPTZ | Criação do tour (horário estimado) |
inicio_real | TIMESTAMPTZ | Evento checkpoint_started (timestamp real) |
fim_real | TIMESTAMPTZ | Evento checkpoint_completed (timestamp real) |
Estados do checkpoint
| Status | Quando ocorre |
|---|---|
pending | Checkpoint criado, aguardando execução |
running | Robô em movimento para o checkpoint |
finished | Robô chegou e completou o checkpoint |
skipped | Emergency stop durante execução |
6. Formatos de Mensagens
6.1 Chat - Broadcast de texto
{
"message_type": "broadcast_text",
"texto": "Resposta do modelo..."
}6.2 Chat - Broadcast de áudio
{
"message_type": "broadcast_audio",
"audio_base64": "AAAAFJDSAIWEA..."
}6.3 Checkpoints - Evento de início
{
"event": "checkpoint_started",
"tipo": "recepcao",
"ordem": 1,
"status": "running",
"inicio_real": "2025-12-15T14:02:35.123Z"
}6.4 Checkpoints - Evento de conclusão
{
"event": "checkpoint_completed",
"tipo": "recepcao",
"ordem": 1,
"status": "finished",
"inicio_real": "2025-12-15T14:02:35.123Z",
"fim_real": "2025-12-15T14:08:12.456Z"
}6.5 Checkpoints - Status do robô
{
"event": "robot_status",
"robot_connected": true,
"is_running": false,
"current_checkpoint": "recepcao"
}7. Configuração
7.1 Arquivo config.toml
[settings.server]
host = "0.0.0.0"
port = 8081 # Backend Rust
[settings.database]
host = "aws-1-us-east-2.pooler.supabase.com"
username = "postgres.xxxxx"
password = "xxxxx"
database = "postgres"
port = 5432
max_connections = 5
[settings.robot]
ip = "127.0.0.1" # IP do servidor Python do robô (localhost para testes)7.2 Portas utilizadas
| Serviço | Porta | Protocolo |
|---|---|---|
| Backend Rust | 8081 | HTTP/WS |
| Robot Python Server | 8080 | HTTP/WS |
| PostgreSQL (Supabase) | 5432 | TCP |
8. Testando o Sistema
8.1 Teste de Checkpoints
# Terminal 1: Servidor Python do robô
cd 2025-2B-T12-EC08-ROBO
python move_path.py
# Terminal 2: Backend Rust
cd 2025-2B-T12-EC08-BACK
cargo run -- --config config.toml
# Terminal 3: Cliente de teste
cd 2025-2B-T12-EC08-BACK
python test_websocket.py interactive --url ws://localhost:8081/wsComandos disponíveis:
status- Consultar status do robôplay- Executar próximo checkpointstop- Parada de emergênciaquit- Sair
8.2 Observando logs
Backend logs esperados:
✅ Conectado ao robô!
📡 Iniciando listener de eventos do robô
🤖 Status inicial do robô: robot_connected=false
▶️ Checkpoint INICIADO: recepcao (ordem: 1)
💾 Checkpoint atualizado no banco: recepcao -> running
✅ Checkpoint CONCLUÍDO: recepcao (status: finished)
💾 Checkpoint finalizado no banco: recepcao -> finished9. Tratamento de Erros
9.1 Robô offline
- Comportamento: Backend retenta conexão a cada 5 segundos
- Frontend: Recebe
robot_connected: falseno status - Comandos: São enfileirados mas não executados até robô conectar
9.2 Perda de conexão durante execução
- WebSocket desconecta: Backend retenta automaticamente
- Checkpoint em andamento: Status
runningpermanece no banco até reconexão - Frontend: Mostra indicador de "Conexão perdida"
9.3 Emergency stop
- Checkpoint atual: Marcado como
skipped - Checkpoints futuros: Permanecem
pending - Robô: Para movimento físico imediatamente
10. Conclusão
O sistema de WebSockets deste projeto é o que permite:
Módulo de Chat:
- Conversação natural com visitantes via texto e áudio
- Sincronização em tempo real entre múltiplos dispositivos
- Integração inteligente com STT, TTS e modelo de IA
Módulo de Checkpoints:
- Controle preciso da navegação do robô
- Atualização automática do banco com timestamps reais
- Sincronização perfeita entre robô físico, backend e frontend
- Gerenciamento de estados e paradas de emergência
A arquitetura foi construída para ser:
- Simples de entender - Componentes bem separados e documentados
- Escalável - Usa broadcast channels e WebSockets eficientes
- Resiliente - Retry automático e tratamento de erros
- Extensível - Fácil adicionar novos eventos e comandos
- Testável - Cliente de teste incluso para validação
O sistema está pronto para uso em produção, com o robô físico ou em modo de simulação para testes.
Sistema de Comunicação por WebSockets
É um protocolo de comunicação moderno que estabelece uma conexão persistente e bidirecional entre um cliente e um servidor através de uma única conexão TCP
Kill Switch - Sistema de Parada de Emergência
Documentação técnica completa do Kill Switch (botão de emergência) para o robô Unitree