Files
AR-Autopilot/docs/AR_Autopilot_brief.md
alro65 700756c16f sprint-0: foundations -- data model, seed library, tests, demo
Initial commit. Delivers what the brief calls 'Sprint 0 - Foundations'
(see docs/AR_Autopilot_brief.md section 12):

- Complete repository structure (arautopilot package + firmware, display,
  installer, tools placeholders + docs).
- Core data model (Pydantic v2): modes, alarms, actuator config, PID
  config + gain scheduling, vessel config, knob state machine, project
  config with YAML/JSON serialisation.
- Seed library: 2 actuator profiles (hydraulic & electric DC reversible)
  and 2 default tunings (yacht motor planeo 30 m and 40 m). Conservative
  literature values, NOT the integrator's production tuning IP.
- Firmware skeleton: only src/hal/pinout.h with the 21 I/O contract for
  the AR-NMEA-IO v1.0 board. No drivers, no main loop.
- Studio stubs (real PySide6 app starts in Sprint 4).
- pytest suite (80 tests, all green): modes, alarms, actuator, PID
  (incl. gain interpolation and the +/-50% adaptive bound from brief
  section 6), vessel, knob state, project config, library loader,
  end-to-end roundtrip.
- examples/sprint0_demo.py - the acceptance demo from the brief.

Acceptance criteria met:
- pytest green (80/80)
- demo creates, saves (YAML + JSON), reloads, and verifies a full
  ProjectConfig using the seed library
- repository ready for tag `sprint-0-approved`

See CHANGELOG.md for the detailed scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 23:57:18 -04:00

862 lines
41 KiB
Markdown

# AR-Autopilot · Brief para Claude Code
## Piloto automático marino — sistema de gobierno con PID adaptativo
> **Instrucciones para Álvaro (no para Code):** Este es el brief completo del proyecto. A diferencia de VMS-Sailor (6 partes), AR-Autopilot cabe en un solo documento porque es un sistema más acotado (gobierno). Las guías técnicas profundas (tuning PID en campo, derivación matemática del EKF, protocolo NMEA 2000 detallado, design system Flutter completo) se generarán como documentos adicionales cuando lleguemos a los sprints correspondientes.
>
> Abre Claude Code en `D:/Proyectos Software/` y deja que cree la subcarpeta `AR-Autopilot`. No abras Code dentro de `D:/Proyectos Software/AR-Autopilot/` antes de tiempo.
---
## 1. Qué es AR-Autopilot
Eres mi co-desarrollador senior en Python, Dart y firmware embebido. Vamos a construir **AR-Autopilot**, un piloto automático marino profesional para sistemas de gobierno, dirigido inicialmente a embarcaciones de 30 a 40 metros — yates motor, veleros a motor, pesqueros, ferries pequeños, patrulleros.
Es **producto independiente** dentro de mi suite (junto a AR-ECDIS, VMS-Sailor, AR-ShipDesign, AR-ElecArrangement, AR-StabCol). Se vende solo o como parte de una oferta integrada con AR-ECDIS.
**No es DP (Dynamic Positioning).** No es joystick docking. Es un piloto automático clásico de gobierno con compensación inteligente de deriva y seguimiento de ruta — controlando el timón del buque mediante actuadores hidráulicos o eléctricos.
**Compite con:** Raymarine Evolution, Garmin Reactor, Simrad AP-series, B&G H5000 Pilot, Furuno NavPilot. Apunta a ser **igual o mejor** porque tienes control total del firmware y puedes afinar cosas que productos cerrados no permiten.
---
## 2. Contexto en la suite AR
| Producto | Rol |
|---|---|
| **AR-ECDIS** | Sistema de navegación con cartografía, GPS, BNO085. Publica datos de navegación al backbone NMEA 2000 |
| **AR-Autopilot** | **Este proyecto.** Controla el sistema de gobierno del buque |
| VMS-Sailor | Monitoreo y control de máquinas. NO interfiere con gobierno |
| AR-ShipDesign, AR-ElecArrangement, AR-StabCol | Diseño naval, sin interacción con gobierno |
### Relación con AR-ECDIS
- AR-Autopilot **consume** del backbone NMEA 2000: rumbo del BNO085 (PGN 127250), rate of turn (PGN 127251), posición GPS (PGN 129025/129029), COG/SOG (PGN 129026), waypoints activos (PGN 129284)
- AR-Autopilot **publica** al backbone NMEA 2000: estado del piloto (PGN 127237), ángulo de timón comandado y actual (PGN 127245), heading deseado
- Si el ECDIS no está instalado, el piloto puede conectarse a otras fuentes NMEA 2000 estándar (Furuno, Garmin, Raymarine)
### Relación con VMS-Sailor
- No comparten control. Son independientes
- El VMS puede *leer* el estado del piloto desde el backbone NMEA 2000 (solo visualización, no control)
- El piloto puede *leer* alarmas críticas del VMS (blackout, sobrecarga eléctrica) y **desengancharse automáticamente** como medida de seguridad
---
## 3. Alcance por fases
### Fase 1 — Lanzamiento (este desarrollo)
**Embarcaciones objetivo:** 30-40 m yates motor, veleros a motor (con motor activo, sin vela), pesqueros, ferries pequeños, patrulleros costeros.
**Modos de operación:**
1. **Standby** — piloto desenganchado, timón manual
2. **Heading Hold** — mantiene rumbo magnético/true compass fijo. El operador ajusta el rumbo deseado con knob físico o controles en pantalla
3. **True Course Hold (TC)** — mantiene **COG** (course over ground) respecto al norte geográfico, compensando deriva por corriente o viento. Más profesional que Heading Hold para navegación real
4. **Track Keeping** — sigue una ruta de waypoints del ECDIS. Calcula y corrige XTE (cross-track error) usando TC internamente. Incluye **compensación suave automática de XTE** (S-curve approach)
5. **Dodge** — desvío temporal sin perder la ruta (esquivar otro barco, objeto en el agua). Vuelve a la ruta automáticamente cuando se libera
**Tipos de actuador soportados (configurables):**
- Bomba hidráulica reversible (Hynautic, Hypro, Octopus, Vetus, Lecomble & Schmitt) — más común en 30-40 m
- Motor eléctrico DC reversible con final de carrera (Lewmar, Simpson Lawrence)
- Servomotor con feedback de posición
- Sterndrive direccional analógico
- **NO incluidos en Fase 1**: Volvo IPS, Mercury Zeus, sistemas propietarios con CAN bus específico (requieren licencia y módulo de interfaz adicional)
**Lazo cerrado obligatorio:** sensor de posición de timón (rudder angle indicator) realimenta al PID interno. Sin feedback no se opera (modo "open loop" solo disponible si el integrador lo habilita explícitamente con override consciente).
### Fase 2 — Futuro (no en alcance inicial)
Para veleros propiamente dichos con vela activa:
- **Vane Mode (Apparent Wind Angle)** — mantiene ángulo aparente del viento constante
- **True Wind Mode** — mantiene ángulo real del viento (compensa COG y SOG)
- **Auto-tack** — vira automáticamente al alcanzar cierto ángulo
Estos modos aparecerán **grisados/deshabilitados** en la UI desde Fase 1 (con etiqueta "Fase 2") para que el cliente vea que están planeados sin rediseñar después.
### Fase 3 — Más futuro
- Integración con sterndrive electrónicos propietarios (Volvo IPS via EVC, Mercury Zeus via SmartCraft)
- Auto-tuning avanzado adaptativo
- Modo crucero con optimización de consumo
---
## 4. Componentes del producto
### 4.1 AR-Autopilot Controller (hardware en cabina técnica)
Usa tu tarjeta **AR-NMEA-IO-v1.0** (la misma que VMS-Sailor: ESP32-DOWD, 21 I/O, RS485 + NMEA 2000 + WiFi).
**Asignación típica de puertos para piloto motor 30-40m:**
| Puerto | Función |
|---|---|
| AI1 | Sensor posición timón (potenciómetro o Hall, 0-10V o 4-20mA) |
| AI2 | Voltaje batería del sistema |
| AI3 | Corriente bomba/motor timón (shunt o sensor Hall) — protección sobrecarga |
| AI4 | Reserva (futuro: presión hidráulica) |
| DI1 | Pulsador físico "Engage / Disengage" en consola |
| DI2 | Final de carrera babor (límite mecánico timón) |
| DI3 | Final de carrera estribor |
| DI4 | Alarma externa (blackout VMS, alarma genset crítica) |
| DI5 | Confirmación manual (override emergencia) |
| RPM1 | Reserva (futuro: sensor rotación si aplica) |
| DO1 | Comando bomba/motor a babor (sentido) |
| DO2 | Comando bomba/motor a estribor (sentido) |
| DO3 | Habilita potencia al actuador (relé maestro) |
| DO4 | Alarma sonora |
| DO5 | Indicador "piloto enganchado" (lámpara consola) |
| DO6-DO10 | Reserva |
**Comunicación:**
- **NMEA 2000 activo**: publica estado del piloto al backbone, consume heading/posición del backbone
- **RS485 Modbus activo**: comunica con el monitor dedicado del puente
- **WiFi**: solo para OTA del firmware, no para operación
### 4.2 AR-Autopilot Display (monitor dedicado en consola del puente)
Pantalla táctil dedicada exclusivamente al piloto — no comparte con ECDIS ni VMS.
**Hardware:**
- PC industrial pequeño tipo Mini-PC fanless o Raspberry Pi 5 con encapsulado marino
- Pantalla táctil 10-12" capacitiva, brillo alto para uso bajo sol (≥1000 nits)
- Resistente a salpicaduras (IP54 mínimo)
**Periféricos en consola:**
- **Trackball industrial USB** (puntero, navegar menús): NSI Cortron CTM, Logitech Trackman, o similar marítimo
- **Knob rotativo con push button** para ajustar rumbo y otros valores:
- Especificación funcional: encoder rotativo de **montaje en panel** con tuerca pasante, 24 detents, push button axial integrado, eje 6 mm, IP65 deseable
- Modelo concreto a definir al hacer compras (Grayhill, Bourns serie de panel, o encoder + knob aluminio aparte). NO encoder de PCB tipo PEC11R que es muy pequeño
- Conexión: 3 DI de la tarjeta AR-NMEA-IO (A, B, SW) o USB al PC del display
- Botón físico de **emergency disengage** (DI1 de la tarjeta) — siempre desconecta el piloto al instante
### 4.3 AR-Autopilot Studio (configurador del integrador)
Aplicación de escritorio en mi PC (similar al VMS-Sailor Studio) para:
- Configurar cada proyecto de piloto que instalo en un cliente
- Definir tipo de actuador, sensores, ganancias PID iniciales, alarmas
- Generar firmware personalizado para la tarjeta AR-NMEA-IO del proyecto
- Generar paquete distribuible `.appack` + instalador MSI
**Stack:** Python 3.11 + PySide6 (coherente con resto de mi suite).
Este Studio es **mío**, no se entrega al cliente.
### 4.4 Firmware AR-NMEA-IO (ESP32)
Donde corre el **PID en tiempo real**. Esto es lo crítico técnicamente.
---
## 5. UI/UX del Display dedicado
### Filosofía de diseño
**Premium cockpit feel.** No genérico. Debe sentirse como una consola profesional, no una app de teléfono ampliada.
**Stack:** **Flutter Desktop** (coherente con VMS-Sailor Mobile). Renderiza con motor Skia/Impeller propio — performance gráfico superior para indicadores animados en tiempo real.
### Estética
- **Tema oscuro premium**: fondo azul-negro profundo tipo cockpit, no negro plano
- **Material 3 + Cupertino** combinados según contexto
- **Glassmorphism**: paneles superpuestos con efecto cristal (blur de fondo + transparencia)
- **Sombras suaves con elevación** en cards y botones grandes
- **Acentos de color por estado:**
- Verde fosforescente: ENGAGED, OK
- Cyan: información, datos en vivo
- Ámbar: warnings, valores pendientes de confirmación
- Rojo: alarmas críticas, acciones peligrosas (disengage)
- **Indicadores circulares animados**: compass rose grande para rumbo, indicador semicircular para timón
- **Tipografía monoespaciada gruesa** para números críticos (rumbo, velocidad, ángulo)
- **Transiciones fluidas** entre cambios de modo y de estado (sin saltos bruscos)
- **Anti-glare mode**: alto contraste para uso bajo sol directo
### Layout principal
Tres zonas:
1. **Zona superior (estado global)**: marca + buque + estado de conexiones NMEA 2000 / GPS / VPN + hora UTC
2. **Zona central (lectura dominante)**:
- **Izquierda (60%)**: compass rose grande con rumbo actual, rumbo deseado (flecha punteada), ángulo de timón visible, métricas (error, ROT, SOG, COG)
- **Derecha (40%)**: selector de modos (5 botones grandes touch-friendly), información de XTE/waypoint/ETA, alarmas activas
3. **Zona inferior (controles inmediatos)**: ajuste fino ±1°/±10°, botón Dodge, botón DISENGAGE grande siempre visible
### Selección de modos (5 botones)
| Modo | Estado | Disponibilidad |
|---|---|---|
| Standby | Inicial / desenganchado | Siempre |
| Heading Hold | Mantiene rumbo compass | Fase 1 |
| **True Course** | Compensa deriva, mantiene COG | Fase 1 |
| Track Keeping | Sigue ruta con XTE | Fase 1 |
| Apparent Wind | Modo vela | **Fase 2 - grisado** |
### Operación del knob físico (filosofía de seguridad)
El knob **nunca controla nada por defecto**. Requiere armado explícito para prevenir cambios accidentales por bandazo, roce o golpe.
**Flujo "hundir → seleccionar → girar → hundir confirma":**
1. **Estado normal**: knob inactivo. Indicador en pantalla: 🔒 "KNOB: LIBRE" en gris
2. **Operador hunde el knob** (push del encoder):
- En pantalla aparece diálogo de selección grande: "¿Qué quieres ajustar?"
- Rumbo
- Ganancia P (solo nivel Técnico)
- Velocidad de giro deseada
- Brillo de pantalla
- Volumen de alarmas
- Operador selecciona con toque en pantalla, O gira el knob hasta la opción correcta y la hunde para confirmar selección
3. **Knob armado**: indicador cambia a 🔓 "KNOB ACTIVO · RUMBO · 28s" en amarillo
4. **Operador gira**: cada click = ±1° (o lo que aplique). Giro rápido se acelera a ±5° por click
5. **Pantalla muestra valor pendiente** en amarillo parpadeante junto al valor actual
6. **Operador hunde knob de nuevo** → confirma cambio pendiente. Knob queda armado 30s más por si quiere más ajustes
7. **Hundir prolongado (>2s)** → desarma completamente
**Auto-desarme:**
- 30 segundos sin actividad
- Cambio de modo del piloto
- Alarma crítica
- Cambio de autoridad
Esto se llama "armado por software" en aviónica/marina y es el patrón estándar para prevenir activaciones accidentales en consolas críticas.
---
## 6. El PID — corazón técnico del producto
### Arquitectura en cascada (lazos anidados)
Un PID único intentando controlar "rumbo deseado → comando a bomba" oscila o es lento. Solución estándar industrial: **cascada de dos PIDs**.
```
┌────────────────────────────────────────────────────────────┐
│ Lazo externo (slow) - 10 Hz │
│ Entrada: error de rumbo deseado vs actual │
│ Salida: setpoint de ángulo de timón │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Lazo interno (fast) - 50 Hz │ │
│ │ Entrada: error de posición de timón │ │
│ │ Salida: PWM/dirección a bomba/motor │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
```
### Frecuencias de los lazos
| Capa | Frecuencia | Justificación |
|---|---|---|
| Lectura sensor posición timón (AI1) | 100 Hz | Datos frescos para lazo interno |
| Lectura rumbo (BNO085 vía NMEA 2000) | 50-100 Hz | Limitado por el sensor |
| Lectura rate of turn (BNO085) | 50-100 Hz | Crítico para feed-forward |
| **Lazo PID interno** (timón a posición) | 50 Hz (20 ms) | Determinístico, sin jitter |
| **Lazo PID externo** (rumbo → setpoint timón) | 10 Hz (100 ms) | Suficiente para dinámica del buque |
| Reporte de estado al display (Modbus) | 5-10 Hz | UX fluida sin saturar bus |
| Publicación NMEA 2000 al backbone | 5 Hz | PGN 127245 Rudder |
### Por qué el PID corre en el firmware ESP32 y no en el display
- **Latencia determinística**: ESP32 corre el lazo a frecuencia fija sin jitter de sistema operativo
- **Seguridad**: si el display se cuelga o reinicia, el piloto sigue funcionando (modo degradado)
- **Eficiencia**: ESP32 a 240 MHz dual-core ejecuta un PID en microsegundos, sobra capacidad
### Técnicas obligatorias del PID
**1. Feed-forward de Rate of Turn (CRÍTICO)**
El BNO085 publica rate of turn nativo (velocidad angular del giro). Se mete directo al lazo externo como feed-forward — el PID anticipa cuándo dejar de aplicar timón para que el barco no sobrepase por inercia. Esto es lo que separa un piloto "decente" de uno "premium".
**2. Gain scheduling por velocidad**
Las ganancias K_p, K_i, K_d **varían con la velocidad** (SOG del GPS):
- A baja velocidad (<5 nudos): K_p mayor, K_d menor, más amortiguamiento
- A alta velocidad (>15 nudos): K_p menor, K_d mayor, anticipación más rápida
- Interpolación suave entre puntos de ajuste
Esto es 30 líneas de código. Hace diferencia enorme en sensación.
**3. Compensación de no-linealidades del actuador**
- **Deadband del actuador**: la bomba no responde al primer 5-10% de comando (fricción estática, resistencia hidráulica). Se compensa con offset configurable
- **Velocidad mínima útil**: debajo de cierto PWM consume corriente pero no mueve. Saltar al mínimo útil
- **Asimetría babor/estribor**: la bomba puede empujar más rápido para un lado que para el otro. Ganancias asimétricas
- **Histéresis del sensor de posición**: filtrar con mediana + deadband del setpoint
**4. Anti-windup, deadband del setpoint, saturación**
- **Anti-windup del integrador**: cuando el actuador satura, no acumular error indefinidamente
- **Deadband alrededor del setpoint**: ±0.5° por defecto, evita oscilaciones por ruido
- **Saturación de salida**: no exceder límites mecánicos del timón (típicamente ±35°)
- **Rate limit del setpoint**: cambios suaves de rumbo, no bruscos (típicamente 3-6°/s máximo)
### Filtros y fusión sensorial
**Sprint 2-3 (filtros clásicos):**
- **Mediana** (5 muestras) para sensor de posición de timón — elimina spikes
- **Low-pass** para rate of turn — suaviza ruido
- **Low-pass** para COG del GPS (constante de tiempo 3-5s) — el COG es ruidoso a baja velocidad
**Sprint 8+ (EKF de fusión sensorial):**
Implementación de **Extended Kalman Filter** para integración GNSS-INS. Combina:
- Heading del BNO085 (alta frecuencia, sin deriva)
- COG del GPS (baja frecuencia, con deriva real)
- Posición GPS (con corrección lever-arm por pitch/roll del BNO085)
- Velocidad angular del giroscopio
Produce:
- Heading filtrado robusto sin spikes
- Rate of turn estimado óptimo
- Set/leeway estimado (clave para modo True Course)
- Posición corregida por antena alta
**Importante**: el EKF llega cuando el piloto ya funciona bien con filtros clásicos. Implementarlo mal es PEOR que no implementarlo. Matrices de covarianza mal tuneadas hacen que el filtro "crea" más en datos malos que en buenos.
### True Course mode (compensación de deriva)
El modo más profesional del piloto. Diferencias clave:
| Concepto | Qué es | Fuente |
|---|---|---|
| Magnetic Heading | Hacia dónde apunta la proa (norte magnético) | BNO085 |
| True Heading | Hacia dónde apunta la proa (norte geográfico) | BNO085 + declinación |
| **COG** | Hacia dónde se mueve realmente el barco | GPS |
| **True Course** | Rumbo planeado en la carta | ECDIS / setpoint operador |
Con corriente o viento cruzado, el barco apunta hacia un lado (heading) pero se mueve hacia otro (COG). La diferencia se llama **set/leeway** (abatimiento).
**En modo True Course Hold:**
- El error que entra al PID externo es `(true_course_deseado - COG)`, no `(heading_deseado - heading)`
- El sistema observa el set/leeway calculado por el EKF (o filtros simples en Fase 1)
- Aplica offset al heading para compensar la deriva
- Resultado: el barco se mueve realmente hacia el rumbo deseado, no solo apunta
**Salvaguarda**: bajo 3 nudos el COG del GPS no tiene sentido. El modo se degrada automáticamente a Heading Hold con aviso al operador.
### Compensación suave automática de XTE (Track Keeping)
En modo Track Keeping, el piloto sigue una ruta de waypoints. Si el barco se desvía lateralmente (XTE distinto de cero), un piloto mal diseñado corrige bruscamente: timonazo grande, sobrepasa, oscila. Se ve y se siente horrible.
**Técnicas combinadas para corrección suave (S-curve approach):**
1. **Saturación del término XTE**: el aporte del XTE al comando de heading se satura (típicamente ±20°). Por mucho XTE, las correcciones nunca son extremas
2. **Approach angle scheduling**: el ángulo con el que se aproxima a la ruta depende de la distancia. Lejos: ángulo cerrado (30-45°). Cerca: ángulo abierto (5-10°). Trayectoria de reincorporación es curva suave
3. **Velocity-aware tuning**: a alta velocidad las correcciones son más pequeñas (encaja con gain scheduling general)
4. **Rate of approach limiter**: limita la velocidad lateral con la que el barco se acerca a la ruta. Detecta sobrepaso anticipadamente y "frena" el ángulo antes de tiempo
Esto es lo que la industria llama trayectoria de reincorporación tangencial. Lo que distingue Furuno NavPilot 700/711 de pilotos baratos que zigzaguean.
### Auto-tuning
**Sprint 7-8 (tuning offline):**
Auto-tuning Ziegler-Nichols modificado o relay test durante prueba de mar:
- Sistema aplica perturbaciones controladas en el timón
- Mide la respuesta (overshoot, settling time, oscilación)
- Calcula ganancias óptimas
- Guarda en capa de comisionado
**Sprint 9+ (adaptive tuning online):**
Adaptive control en operación normal:
- En cada maniobra (cambio de rumbo solicitado), observa respuesta real
- Compara con respuesta ideal esperada
- Ajusta K_p, K_i, K_d levemente en la dirección que mejora (1-2% por maniobra)
- Después de 20-50 maniobras converge a ganancias adaptadas al barco específico
**Salvaguardas críticas:**
- Ganancias adaptativas **nunca** salen de ±50% respecto a las base
- Adaptación lenta (1-2% por maniobra máximo)
- Si detecta divergencia (más oscilación, no menos), vuelve automáticamente a base
- Alarma al integrador si las ganancias se acercan a los límites
### Tres niveles de acceso al PID
| Nivel | Quién accede | Qué puede tocar |
|---|---|---|
| **Operador** | Capitán | Solo elegir perfil pre-configurado: Suave / Normal / Deportivo |
| **Técnico** | Jefe máquinas, instalador autorizado (PIN) | Ver ganancias activas, ajustar ±30% de base, activar/desactivar adaptación |
| **Integrador** | Yo (Álvaro) con PIN especial | Acceso completo: editar ganancias base, modificar límites de adaptación, calibración inicial |
**Las ganancias base son IP del integrador**. Las que vienen en biblioteca son resultado de mi experiencia, no se exponen al cliente final.
---
## 7. Seguridad funcional
Crítica en piloto automático — un fallo puede causar accidente grave. Filosofía: **cualquier duda, más conservador, no menos**. Un piloto que se desengancha por error es molesto pero seguro. Un piloto que no se desengancha en emergencia es peligroso.
### Watchdog hardware
El ESP32 reinicia automáticamente si el firmware se cuelga >2 segundos. Al reiniciar:
- Estado del piloto pasa a **STANDBY** (timón manual)
- Alarma sonora y visual
- Registro del evento en log
### Pulsadores de override
- **Disengage físico** (DI1) en consola del puente: un toque desengancha el piloto al instante. Independiente del display
- **Volante con sensor de torque** (opcional, configurable): si el operador toca el timón con fuerza, el piloto se desengancha automáticamente
- **Botón virtual DISENGAGE grande siempre visible** en pantalla (rojo, ocupa parte significativa de la zona inferior)
### Alarmas de seguridad
| Alarma | Condición | Acción |
|---|---|---|
| Off course | Rumbo se aparta >X° del deseado por >Ns | Warning sonoro + visual |
| Off course severo | Desviación >30° por >5s | Auto-desenganche + alarma máxima |
| Rudder no responde | Comando enviado pero posición no cambia >5s | Auto-desenganche + alarma máxima |
| Sensor rumbo perdido | NMEA 2000 deja de publicar PGN 127250 | Auto-desenganche tras 5s |
| Sobrecarga actuador | Corriente excede límite configurado | Cortar actuador + alarma |
| Voltaje bajo | <11V (12V) o <22V (24V) | Warning + auto-desenganche si crítico |
| Final de carrera | Timón al tope mecánico | Cortar comando en esa dirección |
| Watchdog dispara | Firmware colgado | Auto-reset + standby |
| Alarma crítica VMS | Blackout, sobrecarga eléctrica general | Auto-desenganche |
Cada alarma con prioridad (Emergency / High / Low / Info) y acción asociada.
### Auto-desenganche resumen
El piloto pasa a STANDBY automáticamente si:
- Watchdog dispara
- Pierde sensor de rumbo por >5 segundos
- Off course severo (>30° del deseado)
- Rudder no responde (comando vs feedback divergen)
- Alarma crítica del VMS
- Voltaje del sistema crítico
- Operador hunde botón DISENGAGE físico o virtual
---
## 8. Comunicaciones
### NMEA 2000 (vía backbone del buque)
**PGNs que CONSUME:**
| PGN | Datos |
|---|---|
| 127250 | Heading (BNO085 del ECDIS) |
| 127251 | Rate of Turn (BNO085) |
| 127257 | Attitude (pitch, roll, yaw) — para correcciones lever-arm |
| 129025 / 129029 | Position (GPS lat/lon) |
| 129026 | COG / SOG |
| 129284 | Navigation Data (waypoint activo, XTE) |
| 128259 | Speed Water (futuro, Fase 2) |
| 130306 | Wind Data (futuro, Fase 2) |
**PGNs que PUBLICA:**
| PGN | Datos |
|---|---|
| 127245 | Rudder (ángulo actual y comandado) |
| 127237 | Heading/Track Control (estado piloto, modo, heading deseado) |
### Modbus RTU (display ↔ tarjeta)
Comunicación local entre la tarjeta AR-NMEA-IO y el monitor de control del puente.
**Registros expuestos:**
- Estado del piloto (engaged/standby, modo activo)
- Rumbo deseado, rumbo actual, error
- Ángulo de timón actual, ángulo objetivo
- Ganancias PID activas
- Alarmas activas
- Estado del knob (libre / armado / función / tiempo restante)
- Comandos del usuario (engage, disengage, cambiar modo, cambiar setpoint, armar knob)
---
## 9. Arquitectura de configuración por capas
Reusa el concepto de capas de VMS-Sailor (ver documento VMS-Sailor):
- **Capa 1 — Paquete base** (`.appack` generado por mi Studio): tipo de actuador, sensores, ganancias por defecto del tipo de buque, configuración inicial
- **Capa 2 — Comisionado en campo**: rangos reales de timón (límites mecánicos detectados durante prueba de mar), ganancias afinadas, offsets de calibración
- **Capa 3 — Preferencias del operador**: rumbos favoritos, perfiles preferidos (Suave/Normal/Deportivo), sensibilidad de alarmas, brillo, volumen
Cada capa se aplica encima de la anterior. Actualizaciones futuras (firmware nuevo, ganancias mejoradas, modo viento de Fase 2) llegan como **deltas firmados** que Álvaro genera.
**Aprobación de actualizaciones**: igual que VMS-Sailor — orden de trabajo + verificación de disponibilidad operativa (buque en puerto, sin alarmas, sin maniobras críticas).
---
## 10. Modelo de negocio
- **Hardware**: tarjeta AR-NMEA-IO + display dedicado + trackball + knob + cableado. Actuadores los compra el cliente o se incluyen según proyecto
- **Software**: licenciado por buque, atado a HWID del display
- **Año 1 garantía**: soporte remoto VPN, ajustes de tuning incluidos
- **Año 2 en adelante**: contrato anual de mantenimiento (10-18% del valor inicial)
- **Expansiones cobradas**:
- Modo viento (Fase 2) — paquete adicional para veleros
- Integración Volvo IPS / Mercury Zeus (Fase 3)
- Auto-tuning adaptativo avanzado
- Tuning custom para condiciones especiales
---
## 11. Estructura del repositorio
```
D:/Proyectos Software/AR-Autopilot/
├── README.md
├── LICENSE.txt
├── CHANGELOG.md
├── pyproject.toml
├── requirements.txt
├── requirements-dev.txt
├── .gitignore
├── studio_main.py # Entry point del Studio
├── arautopilot/ # Código Python compartido
│ ├── __init__.py
│ ├── version.py
│ ├── core/ # Modelo de datos
│ │ ├── vessel_config.py
│ │ ├── actuator_config.py
│ │ ├── pid_config.py
│ │ ├── alarms.py
│ │ ├── modes.py
│ │ └── ids.py
│ ├── library/ # Biblioteca curada (solo Studio)
│ │ ├── actuators/ # Tipos de actuador soportados
│ │ │ ├── hydraulic_reversible.json
│ │ │ ├── electric_dc_reversible.json
│ │ │ └── servomotor_feedback.json
│ │ ├── default_tunings/ # Ganancias iniciales por tipo de buque
│ │ │ ├── yacht_motor_planeo_30m.yaml
│ │ │ ├── yacht_motor_planeo_40m.yaml
│ │ │ ├── pesquero_30m.yaml
│ │ │ ├── patrullero_costero_30m.yaml
│ │ │ └── ferry_pequeño_30m.yaml
│ │ ├── vessel_profiles/
│ │ └── _schemas/
│ ├── studio/ # App Studio (PySide6)
│ │ ├── app.py
│ │ ├── main_window.py
│ │ ├── wizards/
│ │ ├── editors/
│ │ ├── simulator/ # Test bench sin hardware real
│ │ └── compiler/ # Genera .appack + MSI
│ ├── shared/
│ └── tests/
├── firmware/ # Firmware ESP32
│ └── ar_autopilot_v1/
│ ├── platformio.ini
│ ├── src/
│ │ ├── main.cpp
│ │ ├── pid/
│ │ │ ├── pid_inner.cpp # PID control de timón (50 Hz)
│ │ │ ├── pid_outer.cpp # PID control de rumbo (10 Hz)
│ │ │ ├── feedforward_rot.cpp # Feed-forward rate of turn
│ │ │ ├── gain_scheduling.cpp # Por velocidad
│ │ │ ├── anti_windup.cpp
│ │ │ ├── actuator_compensation.cpp # Deadband, asimetría
│ │ │ └── auto_tuner.cpp # Sprint 7+
│ │ ├── modes/
│ │ │ ├── standby.cpp
│ │ │ ├── heading_hold.cpp
│ │ │ ├── true_course.cpp
│ │ │ ├── track_keeping.cpp
│ │ │ ├── xte_smooth_correction.cpp
│ │ │ └── dodge.cpp
│ │ ├── filters/
│ │ │ ├── median.cpp
│ │ │ ├── low_pass.cpp
│ │ │ └── ekf_fusion.cpp # Sprint 8+
│ │ ├── safety/
│ │ │ ├── watchdog.cpp
│ │ │ ├── auto_disengage.cpp
│ │ │ ├── alarms.cpp
│ │ │ ├── override_handler.cpp
│ │ │ └── limits_check.cpp
│ │ ├── protocols/
│ │ │ ├── modbus_slave.cpp # Con el display
│ │ │ ├── nmea2000_consumer.cpp
│ │ │ └── nmea2000_publisher.cpp
│ │ ├── hal/ # Hardware abstraction layer
│ │ │ ├── rudder_sensor.cpp
│ │ │ ├── rudder_actuator.cpp
│ │ │ ├── knob_encoder.cpp # Push button + cuadratura
│ │ │ └── pinout.h
│ │ └── system/
│ │ ├── ota_client.cpp
│ │ └── health_reporter.cpp
│ └── test/
├── display/ # App del display dedicado (Flutter)
│ ├── pubspec.yaml
│ ├── lib/
│ │ ├── main.dart
│ │ ├── app.dart
│ │ ├── core/
│ │ │ ├── models/
│ │ │ ├── modbus_client.dart # Cliente Modbus al ESP32
│ │ │ └── theme/
│ │ │ ├── cockpit_dark.dart # Tema oscuro premium
│ │ │ └── glassmorphism.dart
│ │ ├── features/
│ │ │ ├── overview/ # Pantalla principal
│ │ │ ├── compass/ # Compass rose animada
│ │ │ ├── rudder_indicator/
│ │ │ ├── modes/
│ │ │ ├── knob_control/ # Diálogo armado del knob
│ │ │ ├── alarms/
│ │ │ ├── tuning/ # Solo Técnico+
│ │ │ ├── trim_display/ # Si aplica
│ │ │ └── settings/
│ │ └── widgets/
│ │ ├── compass_rose.dart
│ │ ├── rudder_bar.dart
│ │ ├── mode_button.dart
│ │ ├── disengage_button.dart
│ │ └── pending_value.dart
│ ├── assets/
│ ├── android/
│ ├── ios/
│ ├── linux/ # Para Raspberry Pi
│ ├── windows/ # Para Mini-PC
│ └── macos/
├── docs/
│ ├── architecture.md
│ ├── pid_tuning_guide.md # Sprint 7+ (documento separado)
│ ├── ekf_implementation.md # Sprint 8+ (documento separado)
│ ├── nmea2000_protocol.md
│ ├── safety_functional.md
│ └── operator_manual.md
├── installer/ # WiX MSI scripts
└── tools/
```
---
## 12. Plan de sprints
### Sprint 0 — Fundaciones (2 semanas)
**Objetivo**: estructura completa + modelo de datos + biblioteca seed mínima.
**Entregables:**
- Repositorio Git inicializado con estructura completa (stubs)
- `pyproject.toml`, `requirements.txt`, `.gitignore`
- Modelo de datos core: VesselConfig, ActuatorConfig, PidConfig, Modes, Alarms, KnobState
- Biblioteca seed mínima: 2 tipos de actuador (hidráulico, eléctrico), 2 perfiles de buque (yate motor 30m, yate motor 40m)
- Tests unitarios del core
- Pinout inicial del firmware en `firmware/ar_autopilot_v1/src/hal/pinout.h` (sin firmware funcional aún)
**Criterio de aceptación**: pytest pasa todo, se puede crear/guardar/leer configuración de proyecto programáticamente.
### Sprint 1 — Firmware ESP32 base (3-4 semanas)
- Pinout funcional, lectura AI/DI, comando DO
- Modbus RTU esclava básica con el display
- Lectura NMEA 2000 (PGN 127250 heading mínimo, 127251 ROT)
- Stub del PID sin lazo cerrado
- Modo STANDBY funcional
- Comunicación bidireccional display ↔ ESP32
### Sprint 2 — PID inner loop (control de timón) (3 semanas)
- PID completo del lazo interno (posición timón)
- Anti-windup, deadband, saturación, rate limit
- Compensación de no-linealidades del actuador (deadband, asimetría, histéresis)
- Configuración de ganancias vía Modbus
- Filtros clásicos (mediana para sensor de timón, low-pass)
- Tests con simulador de timón (modelo simple inercia + fricción)
### Sprint 3 — PID outer loop + Heading Hold (3 semanas)
- PID externo de rumbo → setpoint de timón
- **Feed-forward de Rate of Turn** del BNO085
- **Gain scheduling por velocidad**
- Modo HEADING HOLD funcional
- Filtros para rumbo (anti-spike, suavizado)
- Pruebas en banco con sensor de rumbo simulado
### Sprint 4 — Studio + Display básico (3-4 semanas)
- Studio Python+PySide6: crear proyecto, configurar tipo de actuador, ganancias iniciales
- Generador de paquete `.appack`
- Display Flutter Desktop:
- Tema oscuro cockpit con glassmorphism
- Vista principal con compass rose animada
- Indicador de timón
- Cambio de modo
- Botón DISENGAGE prominente
- Conexión Modbus display ↔ tarjeta funcional
### Sprint 5 — True Course + Track Keeping (3 semanas)
- Cálculo de set/leeway (filtros clásicos)
- Modo TRUE COURSE HOLD funcional
- Consumo de PGN 129284 (waypoint activo del ECDIS)
- Cálculo de XTE
- Modo TRACK KEEPING con compensación suave automática:
- Saturación del término XTE
- Approach angle scheduling
- Velocity-aware tuning
- Rate of approach limiter
- Modo DODGE temporal
### Sprint 6 — Seguridad y alarmas (3 semanas)
- Watchdog hardware funcional
- Pulsadores físicos de override (DI1, DI5)
- Alarmas completas (off course, rudder no responde, sensor perdido, sobrecarga, voltaje bajo, final de carrera, watchdog)
- Auto-desenganche en condiciones críticas
- Publicación NMEA 2000 al backbone (PGN 127245, 127237)
- Lectura de alarmas del VMS por NMEA 2000
### Sprint 7 — Knob físico + comisionado + auto-tuning offline (3-4 semanas)
- Driver del knob encoder con push button (3 DI: A, B, SW)
- Decoder en hardware (PCNT del ESP32) para no perder pulsos
- Filosofía "armado por software" del knob completa
- Diálogo de armado en display Flutter
- Auto-desarme por timeout/alarma/cambio de modo
- Wizard de comisionado en campo desde el display (modo Técnico)
- Rangos reales de timón (límites mecánicos detectados)
- Ajuste fino de ganancias en campo
- Auto-tuning Ziegler-Nichols o relay test
- Tres niveles de acceso (Operador / Técnico / Integrador con PIN)
- Capas de configuración (base + comisionado + owner_prefs)
- Deltas firmados
### Sprint 8 — EKF + adaptive tuning + telemetría (3-4 semanas)
- Extended Kalman Filter para fusión sensorial (BNO085 + GPS + sensor timón)
- Estimación robusta de heading, ROT, set/leeway, posición lever-arm-corrected
- Auto-tuning adaptive online con salvaguardas (±50% máx, cambios lentos, auto-disable si diverge)
- Telemetría de salud del sistema (visible al cliente, pausable)
- Acceso VPN para soporte remoto
- Activación HWID
### Sprint 9 — Hardening + pruebas integradas (3 semanas)
- Pruebas en banco completas con simulador de buque
- Pruebas de fallo (cable cortado, tarjeta sin energía, bus colgado, sensor mintiendo)
- Stress test (alarmas masivas, cambios rápidos de rumbo, condiciones límite)
- Watchdog y recovery automático
- Documentación de operador y mantenimiento
- Manual técnico de comisionado
### Sprint 10+ — Fase 2 y refinamientos
- Modo Vane (apparent wind angle hold) para veleros
- Modo True Wind
- Auto-tack
- Integración Seakeeper como periférico
- Integraciones específicas (Volvo IPS, Mercury Zeus) — Fase 3
- Mejoras de UI basadas en feedback de clientes reales
---
## 13. Stack tecnológico
| Componente | Tecnología |
|---|---|
| Studio | Python 3.11 + PySide6 |
| Display dedicado | Flutter Desktop (Linux para RPi5, Windows para Mini-PC) |
| Firmware ESP32 | PlatformIO + Arduino framework o ESP-IDF (decidir en Sprint 1) |
| Hardware tarjeta | AR-NMEA-IO-v1.0 (la misma que VMS-Sailor) |
| Modbus | pymodbus (Studio), Modbus library en firmware |
| NMEA 2000 | NMEA2000_esp32 library |
| Base de datos local Studio | SQLite |
| Empaquetado | PyInstaller + WiX Toolset MSI |
| Tests Python | pytest, pytest-qt |
| Tests firmware | Unity + PlatformIO test framework |
| Tests Flutter | flutter_test |
| Activación HWID | UUID + MAC + Disk Serial firmados |
---
## 14. Reglas de oro
1. **Antes de cada sprint**, me presentas plan detallado y esperas mi OK. No improvises features.
2. **Cada cambio importante** se discute primero. Yo decido alcance.
3. **Tests obligatorios** en firmware (Unity) y en core Python (pytest). Display Flutter con flutter_test en flujos críticos.
4. **No agregues dependencias** sin preguntarme.
5. **Documentar normativa** cuando aplique:
- ISO 11674 (heading control systems)
- ISO 16329 (heading control systems for high-speed craft)
- IMO MSC.64(67) (autopilot performance standards)
- NMEA 2000 (PGNs)
- Wheelmark si se busca certificación europea
6. **Sin red de salida** en producto final, salvo VPN administrativa auditada y activación inicial.
7. **Seguridad primero**: cualquier duda → más conservador, no menos. Un piloto que se desengancha por error es molesto pero seguro. Un piloto que no se desengancha en emergencia es peligroso.
8. **Coherencia con la suite AR**: misma filosofía UX, español por defecto, sistema de coordenadas naval donde aplique, mismo hardware AR-NMEA-IO.
9. **Las ganancias PID son IP del integrador**. Las que vienen en biblioteca son resultado de mi experiencia. No se exponen al cliente final.
10. **El sistema de gobierno es CRÍTICO de seguridad**: cumplir con principios de seguridad funcional aunque no busquemos certificación formal inicialmente. Auditoría completa de todas las acciones operativas.
11. **El PID corre en firmware ESP32, no en el display**. Esto es no-negociable: latencia determinística, seguridad ante caída del display, eficiencia.
12. **El display puede fallar y el piloto debe seguir funcionando**. La tarjeta ESP32 mantiene el estado y reporta al backbone NMEA 2000. Al recuperarse el display, retoma comunicación.
13. **Conformidad con arquitectura de capas** (base + comisionado + preferencias) idéntica a VMS-Sailor. Para que ambos productos compartan filosofía de actualización y mantenimiento.
14. **Auditoría siempre activa**: cada engage/disengage, cada cambio de modo, cada armado de knob, cada confirmación, cada alarma con su ack, cada conexión VPN del fabricante. Inmutable y firmado.
---
## 15. Cómo proceder
**Paso 1.** Confirma que entendiste el alcance. Pregunta dudas ANTES de tocar código.
**Paso 2.** Verifica si existe `D:/Proyectos Software/AR-Autopilot/`. Si está vacía, OK. Si tiene contenido, pregúntame.
**Paso 3.** Presenta tu plan detallado del Sprint 0: archivos a crear, librerías a usar, tests a escribir. Espera mi OK.
**Paso 4.** Ejecuta Sprint 0. Al final me presentas:
- Commit `sprint-0`
- pytest verde
- Script demo que cree configuración de proyecto de ejemplo, la guarde y la lea de vuelta
**Paso 5.** Yo reviso, doy feedback, apruebo, taggeas `sprint-0-approved`, pasamos al Sprint 1.
---
## 16. Documentos futuros
Estos se generarán cuando lleguemos a su sprint correspondiente. No se crean ahora:
- `pid_tuning_guide.md` — Sprint 7 (guía completa de tuning en campo)
- `ekf_implementation.md` — Sprint 8 (derivación matemática del Kalman, matrices de covarianza, código de referencia)
- `nmea2000_protocol.md` — Sprint 6 (detalle de cada PGN consumido y publicado)
- `ui_design_system.md` — Sprint 4 (design system Flutter completo: colores, tipografía, animaciones)
- `safety_functional.md` — Sprint 6 (documento de análisis de seguridad funcional)
- `operator_manual.md` — Sprint 9 (manual de usuario final del display)
---
## 17. Notas finales
- AR-Autopilot **tiene riesgo de daño físico real** si funciona mal. Toda decisión técnica debe priorizar seguridad sobre conveniencia.
- Reusamos la tarjeta AR-NMEA-IO v1.0 **sin modificar hardware**. Si en el camino descubrimos que algún I/O no alcanza, lo discutimos antes de cambiar hardware.
- AR-ECDIS es producto **separado**, no se desarrolla en este repositorio. Solo asumimos que publica al backbone NMEA 2000 los PGNs estándar de navegación y actitud.
- El **EKF, adaptive tuning y modo viento** son features avanzadas que solo se implementan cuando el sistema base funciona perfecto. No nos saltamos sprints.
- Hardware del knob: **encoder rotativo de panel** (montaje pasante, no PCB) con push button, 24 detents, eje 6 mm. Modelo concreto se elige al hacer compras (Grayhill, Bourns serie panel, o encoder + knob aluminio por separado).
---
**Fin del brief.**
Comienza confirmando que entendiste el alcance y preséntame tu plan del Sprint 0.