Documentação

Software, Firmware e Operação

Código-fonte, serviço Rust, ROS 2 e fluxo operacional do Kill Switch

Kill Switch - Software, Firmware e Operação

1. Firmware Serial (ESP32C3)

Código-Fonte: robot-button.cpp

robot-button.cpp
void setup() {
  pinMode(0, INPUT_PULLUP);  // Botão no GPIO 0
  Serial.begin(115200);       // Inicializa serial a 115200 baud
}

void loop() {
  int state = digitalRead(0);
  // Lógica invertida: LOW = pressionado (1), HIGH = solto (0)
  Serial.println(state == LOW ? "1" : "0");
  delay(50);  // Polling a cada 50ms
}

Explicação da Lógica

LinhaExplicação
pinMode(0, INPUT_PULLUP)Configura GPIO 0 como entrada com pull-up interno
Serial.begin(115200)Inicializa comunicação serial a 115200 baud
digitalRead(0)Lê o estado atual do GPIO 0
state == LOW ? "1" : "0"Se LOW (pressionado), envia "1"; senão envia "0"
delay(50)Aguarda 50ms antes de próxima leitura (~20 Hz)

Comportamento

  • Lê o estado do GPIO 0 a cada 50ms
  • Envia "1" quando o botão está pressionado (LOW)
  • Envia "0" quando o botão está solto (HIGH)
  • Taxa de transmissão: ~20 mensagens por segundo

A taxa de 50ms é um bom compromisso entre responsividade e economia de energia. Pode ser ajustada conforme necessário.

2. Serviço Rust no Robô

O serviço Rust roda no sistema do robô e é responsável por monitorar a porta serial e traduzir sinais para comandos ROS.

Responsabilidades Principais

  1. Monitoramento Serial: Escuta continuamente a porta tty AM0
  2. Lógica de Flip-Flop: Detecta transições de estado
  3. Publicação ROS: Envia comando para tópico /cmd/dump
  4. Logging Estruturado: Registra eventos com trace_id

Pseudocódigo

rust-serial-emergency-button
use serialport;
use ros2_client;

fn main() {
    let mut serial_port = serialport::open("/dev/ttyAM0")
        .expect("Failed to open serial port");

    serial_port.set_baud_rate(115200)
        .expect("Failed to set baud rate");

    let mut ros_publisher = ros2_client::create_publisher("/cmd/dump");
    let mut previous_state = '0';

    loop {
        let mut buffer = [0; 1];
        match serial_port.read_exact(&mut buffer) {
            Ok(_) => {
                let current_byte = buffer[0] as char;

                if current_byte == '1' && previous_state == '0' {
                    // Transição 0→1: Botão pressionado
                    log_event("KILL_SWITCH_ACTIVATED", "CRITICAL");

                    ros_publisher.publish(EmergencyStopCommand {
                        action: "DUMP".to_string(),
                        timestamp: get_current_time_utc(),
                        trace_id: generate_trace_id(),
                    });
                } else if current_byte == '0' && previous_state == '1' {
                    // Transição 1→0: Botão liberado
                    log_event("KILL_SWITCH_RELEASED", "HIGH");

                    ros_publisher.publish(RecoverCommand {
                        action: "RECOVER_FROM_FALL".to_string(),
                        timestamp: get_current_time_utc(),
                    });
                }

                previous_state = current_byte;
            }
            Err(e) => {
                log_event("SERIAL_READ_ERROR", "ERROR");
                eprintln!("Error reading from serial: {}", e);
            }
        }
    }
}

Estrutura de Eventos Publicados

Evento: KILL_SWITCH_ACTIVATED
{
  "timestamp": "2025-12-10T16:30:45.123Z",
  "trace_id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "KILL_SWITCH_ACTIVATED",
  "severity": "CRITICAL",
  "source": "SERIAL",
  "action": "DUMP",
  "ack_time_ms": 245
}
Evento: KILL_SWITCH_RELEASED
{
  "timestamp": "2025-12-10T16:30:50.456Z",
  "trace_id": "550e8400-e29b-41d4-a716-446655440001",
  "event": "KILL_SWITCH_RELEASED",
  "severity": "HIGH",
  "source": "SERIAL",
  "action": "RECOVER_FROM_FALL"
}

3. Integração com ROS 2

O serviço Rust publica em dois tópicos ROS 2:

TópicoMensagemFrequênciaDescrição
/cmd/dumpEmergencyStopCommandSob demandaAtiva Dump Mode
/cmd/recoverRecoverCommandSob demandaAtiva Recover from Fall

Subscribers ROS 2

O robot controller (outro nó ROS 2) se inscreve nesses tópicos e executa as ações correspondentes:

robot-controller.cpp (exemplo)
void estop_callback(const EmergencyStopCommand& msg) {
    // Desliga todos os motores
    for (auto& motor : motors) {
        motor.set_torque(0);
    }
    robot_state = DUMP_MODE;
    log_event("DUMP_MODE_ACTIVATED");
}

void recover_callback(const RecoverCommand& msg) {
    // Inicia sequência de recuperação
    robot_state = RECOVERING;
    execute_recovery_sequence();
}

4. Fluxo Operacional

Sequência de Acionamento

A sequência de acionamento segue 8 etapas principais:

EtapaAçãoTempoResponsávelStatus
1Operador pressiona botãoT+0msOperadorCrítica
2ESP32C3 detecta transição GPIOT+0-50msMicrocontroladorCrítica
3Transmissão Serial iniciadaT+50-100msESP32C3Crítica
4Serviço Rust recebe sinal serialT+100-150msRust ServiceCrítica
5ROS Topic /cmd/dump publicadoT+150-200msROS 2Crítica
6Motor controllers recebem comandoT+200-300msRobot HardwareCrítica
7Torque cortado (Dump Mode ativado)T+300-500msRobot MotorsCrítica
8Dump Mode confirmadoT+500-1000msRobotCrítica

SLA: ACK ≤ 1 segundo (RF-KS-006)

Diagrama de Sequência

Playbooks de Resposta

Playbook KS-001: Acionamento Normal

Procedimento Operacional Completo

Gatilho: Operador detecta situação de risco iminente

Passos:

  1. Operador pressiona o botão de emergência (cogumelo amarelo)
  2. Sistema detecta pressão e envia sinal via Serial
  3. Robô entra em Dump Mode (motores desligados)
  4. Operador aguarda confirmação visual (robô imóvel)
  5. Operador libera o botão após situação controlada
  6. Robô entra em modo Recover from Fall (sequência automática)
  7. Operador aguarda recuperação completa
  8. Revisar logs de telemetria
  9. Verificar se houve danos ao robô
  10. Atualizar relatório de incidentes

Playbook KS-002: Falha de Comunicação Serial

Recuperação de Falha Serial

Gatilho: Serviço Rust não recebe sinal serial por > 5 segundos

Passos:

  1. Sistema detecta perda de comunicação serial
  2. Ativar failsafe mecânico (se disponível)
  3. Registrar evento importante no SIEM com trace_id
  4. Notificar Analista 4 via ChatOps em < 60 segundos
  5. Investigar causa raiz (cabo solto, driver serial, etc.)
  6. Restaurar conexão e validar funcionamento
  7. Executar teste de carga Kill Switch para confirmar

SLA de Resposta: 5 minutos para mitigação

Responsável: Analista 4 (SIEM-ROB)

Investigação:

  • Verificar logs de erro do ESP32C3
  • Testar conexão USB-C
  • Validar baud rate e configuração serial

Playbook KS-003: Acionamento Indevido

Falso Positivo

Gatilho: Botão acionado sem situação de emergência

Passos:

  1. Registrar timestamp e contexto do acionamento
  2. Verificar logs de telemetria do robô (bateria, sensores, etc.)
  3. Investigar se houve contato acidental ou falha de hardware
  4. Se falso positivo confirmado, documentar em post-mortem
  5. Avaliar necessidade de proteção física adicional (capa, etc.)
  6. Atualizar guidelines operacionais se necessário
  7. Comunicar ao operador sobre o incidente

SLA de Resposta: 2 minutos para contenção

Responsável: Operador + Analista 4

Análise:

  • Taxa de falsos positivos por hora
  • Padrão de acionamentos (acidental vs. intencional)
  • Necessidade de ajuste de sensibilidade

Resumo

O software do Kill Switch é composto por firmware simples no ESP32C3, um serviço Rust robusto que monitora a porta serial, e integração com ROS 2 para acionamento de Dump Mode. O fluxo operacional garante resposta em menos de 1 segundo com procedimentos bem documentados para diferentes cenários.