Saltar a contenido
← Volver a OPRobots.org

Arquitectura Software

IRTimer tiene dos firmwares independientes que se cargan en la misma PCB según el modo de funcionamiento deseado. Ambos usan el framework Arduino sobre ESP32-C3 con PlatformIO.

Aspecto Modo Main Modo Aux
Directorio source_code/main_module/ source_code/aux_module/
Disciplina LineFollower Micromouse
Rol Host central + cronómetro Sensor de pared
Display ST7789, 6 pantallas con navegación No
WiFi STA+AP, servidor web + SSE STA, solo escaneo de canal
ESP-NOW Recibe comandos (27/42) Envía comandos (27/42)
RC5 IR Decodifica (control remoto) No
Botones 2 (navegación + reset) No
Cronómetro Local: su propio sensor IR Remoto: notifica al Main
LED NeoPixel Power + Connection Power + Identificación

Modo Main — Host y Cronómetro de LineFollower

Firmware más complejo de los dos. Actúa como centro del sistema: cronometra, muestra resultados, sirve el overlay web, recibe ESP-NOW y comandos RC5.

Bucle Principal

flowchart TD
    Setup[setup] --> Config[config_setup]
    Setup --> CtrlInit[control_init]
    Config --> Serial[Serial 115200]
    Config --> Pins[GPIO + IR ISR]
    Config --> TFT[Pantalla ST7789]
    CtrlInit --> Splash[Pantalla SPLASH]

    Loop[loop] --> ManageScreen[control_manage_screen]
    Loop --> ManageBatt[control_manage_battery]
    Loop --> ManageEvent[control_manage_pending_event]

    ManageScreen --> Screen{current_screen}
    Screen -->|SPLASH| SplashWait[Esperar 2s → MENU]
    Screen -->|MENU| MenuNav[Navegar opciones]
    Screen -->|WIFI_INIT| WifiSetup[web_setup → WIFI_INFO/FAIL]
    Screen -->|WIFI_INFO| WifiShow[Mostrar IP/MAC]
    Screen -->|WIFI_FAIL| WifiErr[Mostrar error]
    Screen -->|TIMER| TimerRun[Cronómetro activo]

setup() inicializa el hardware y loop() itera sobre tres funciones principales:

Función Responsabilidad
control_manage_screen() Navegación entre pantallas, lectura de botones
control_manage_battery() Monitorización del LED de batería (parpadeo si baja)
control_manage_pending_event() Procesar eventos RC5 pendientes (RESET/STOP)

La detección del sensor IR (stopwatch_check()) se llama solo dentro de control_manage_screen() bajo el estado SCREEN_TIMER. En cualquier otra pantalla el cronómetro no avanza.

Máquina de Estados de Pantallas

stateDiagram-v2
    [*] --> SPLASH
    SPLASH --> MENU: 2s timeout
    MENU --> WIFI_INIT: Botón sup. (opción 0)
    MENU --> TIMER: Botón inf. (opción 1)
    WIFI_INIT --> WIFI_INFO: web_setup() OK
    WIFI_INIT --> WIFI_FAIL: web_setup() falla
    WIFI_INFO --> MENU: Botón inf.
    WIFI_FAIL --> MENU: Botón inf.
    TIMER --> MENU: Botón inf.
    TIMER --> TIMER: Botón sup. (reset)
Estado Pantalla Acción
SCREEN_SPLASH Logo OPRobots Muestra 2s, transición automática
SCREEN_MENU Menú principal 2 opciones: Iniciar WiFi / Cronómetro
SCREEN_WIFI_INIT Conectando... web_setup(), bloquea hasta connect/timeout
SCREEN_WIFI_INFO Info WiFi Muestra IP, MAC, canal
SCREEN_WIFI_FAIL Error WiFi Muestra mensaje de error
SCREEN_TIMER Cronómetro Tiempo actual, última vuelta, mejor vuelta, historial (5)

ISR del Receptor RC5

flowchart TD
    Edge[Flanco en pin 7] --> ISR[rc5_isr]
    ISR --> Register[rc5_register]
    Register --> Decode[rc5_decode_pulse]
    Decode --> State{Estado RC5}
    State -->|START1/MID1/MID0/START0| Transition[Transición de estado]
    Transition -->|14 bits completos| Command[rc5_manage_command]
    Command -->|RESET| Pending[control_set_pending_event EVENT_RESET]
    Command -->|STOP| Pending2[control_set_pending_event EVENT_STOP]

La ISR se dispara en cada flanco (CHANGE) del receptor TSSP77038TR. El decodificador RC5 implementa la máquina de estados del algoritmo Clearwater:

  • 4 estados: STATE_START1, STATE_MID1, STATE_MID0, STATE_START0
  • 14 bits por trama: 2 start + 1 toggle + 5 address + 6 command
  • Ventanas de timing: short 444–1333 µs, long 1334–2222 µs
  • Comandos: dirección 0x0B (Program) → RESET, dirección 0x07 (Computer) → STOP

⚠️ Advertencia: La ISR contiene delayMicroseconds(100) y escribe al pin 8 (TFT_MOSI). Ver HW-01 y HW-02.

Recepción ESP-NOW

flowchart TD
    ESP_NOW[ESP-NOW packet] --> Callback[data_receive callback]
    Callback --> Check{"data[0]?"}
    Check -->|27| CmdStart[START/lap]
    Check -->|42| CmdStop[STOP]
    CmdStart --> DisableSensor[stopwatch_disable_sensor_check]
    CmdStart --> Lap[stopwatch_lap + web_start/web_lap]
    CmdStop --> DisableSensor2[stopwatch_disable_sensor_check]
    CmdStop --> LapStop[stopwatch_lap + stopwatch_stop]
    CmdStop --> WebStop[web_stop]

Al recibir un comando ESP-NOW desde una pared Aux, el sensor IR del Main se deshabilita permanentemente (hasta reinicio). Esto evita dobles detecciones cuando la pared ya ha enviado la señal.

Cronómetro

El cronómetro (stopwatch.cpp) mantiene el siguiente estado:

Variable Tipo Descripción
is_running bool Cronómetro activo
start_ms long Timestamp de inicio (millis)
lap_number int Número de vuelta actual
last_lap_ms long Tiempo de la última vuelta
best_lap_ms long Mejor tiempo de vuelta
last_laps[5] long[] Historial circular de 5 vueltas
last_laps_delta[5] long[] Delta respecto a mejor vuelta

Debounce entre vueltas: 200 ms mínimo entre detecciones consecutivas.


Modo Aux — Paredes de Micromouse

Firmware minimalista. Su única función es detectar al robot con el sensor IR y notificar al Main por ESP-NOW.

Bucle Principal

flowchart TD
    Setup[setup] --> Config[config_setup]
    Config --> Identify{MAC address?}
    Identify -->|START_MAC| Start[LED verde — pared START]
    Identify -->|FINISH_MAC| Finish[LED roja — pared FINISH]

    Loop[loop] --> SensorCheck[stopwatch_check]
    Loop --> BattManage[manage_battery]

    SensorCheck --> Sensor{!digitalRead SENSOR_PIN?}
    Sensor -->|Sí| Debounce{debounce 500ms?}
    Debounce -->|OK| WallType{Tipo pared?}
    WallType -->|START| CheckInhibit{can_start?}
    CheckInhibit -->|Sí| SendStart[client_start → cmd 27]
    CheckInhibit -->|No| ReEnable[Esperar 1s → can_start=true]
    WallType -->|FINISH| SendStop[client_finish → cmd 42]

Identificación por MAC

Cada placa en modo Aux se identifica al arrancar por su dirección MAC (hardcodeada en config.cpp), lo que determina si actúa como pared de START o de FINISH:

MAC Rol LED Connection
64:E8:33:87:CB:AC Pared START (inicio del laberinto) Verde
34:B7:DA:F8:C9:9C Pared FINISH (meta del laberinto) Roja

⚠️ Advertencia: Las MAC están hardcodeadas. Ver HW-03.

Lógica de Inhibición (pared START)

Para evitar que el robot re-dispare el cronómetro al volver a la casilla de salida durante la fase de reconocimiento:

  1. La pared START envía el comando y pone can_start = false
  2. Mientras el sensor siga detectando (robot presente):
  3. Si pasan > 1s con detección continua → can_start = true (permite rearranque manual)
  4. Al liberarse el sensor, can_start se mantiene false hasta la próxima detección que supere el debounce de 500 ms

Envío ESP-NOW

El cliente (client.cpp) escanea el canal WiFi del Main y envía comandos:

Función Comando Comportamiento
client_start() 27 Reintenta si falla (bucle infinito)
client_finish() 42 Intento único, sin reintento

⚠️ Advertencia: client_start() tiene un bucle de reintento sin timeout. Ver CM-01.


Compilación Condicional

Macro Función
PIO_FRAMEWORK_ARDUINO_ENABLE_CDC Habilita CDC Serial sobre USB
IRTIMER_WIFI_SSID SSID WiFi (variable de entorno)
IRTIMER_WIFI_PASS Contraseña WiFi (variable de entorno)

Estructura de Archivos

source_code/
├── main_module/               # Firmware para Modo Main
│   ├── include/
│   │   ├── config.h           # Pines, constantes
│   │   ├── control.h          # Máquina de estados de pantalla
│   │   ├── icon_wifi.h        # Bitmap icono WiFi (PROGMEM)
│   │   ├── menu_screen.h      # Bitmap pantalla menú (PROGMEM)
│   │   ├── rc5.h              # Decodificador RC5
│   │   ├── screen.h           # Driver ST7789
│   │   ├── splash_screen.h    # Bitmap pantalla splash (PROGMEM)
│   │   ├── stopwatch.h        # Lógica de cronometraje
│   │   ├── utils.h            # LEDs, batería, formateo
│   │   └── web.h              # Servidor web + SSE
│   ├── platformio.ini
│   ├── src/                   # Implementaciones (.cpp)
│   └── web/
│       └── index.html         # Overlay web (empaquetado en PROGMEM)
└── aux_module/                # Firmware para Modo Aux
    ├── include/
    │   ├── client.h           # Cliente ESP-NOW
    │   ├── config.h           # Pines, identificación MAC
    │   ├── stopwatch.h        # Lógica del sensor
    │   └── utils.h            # LEDs, batería
    ├── platformio.ini
    └── src/                   # Implementaciones (.cpp)

Documento generado el 2026-06-29. Ver también Hardware, Comunicaciones, Menú.