Files
AR-Autopilot/docs/concentrador_protocol.md
T
alro65 4cc5b19f0c docs: spec protocolo NMEA 0183/2000 del concentrador USB
Define el protocolo completo de la tarjeta concentrador NMEA2000-USB:
- Sentencias NMEA 0183 estandar emitidas por el ESP32 hacia los puertos OUT
- Sentencias propietarias $PARP para comandos del autopilot
- Protocolo de transferencia de mando entre estaciones (puente, cockpit, flybridge)
- Mapeo completo NMEA 0183 <-> NMEA 2000 PGNs
- Seguridad: validacion de checksum, permisos por estacion, alarmas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 01:07:06 -04:00

8.6 KiB
Raw Blame History

Protocolo Concentrador NMEA2000-USB

AR-Autopilot — Tarjeta Concentrador Versión 1.0 — 2026-05-23


Arquitectura general

Software (J6412 / Tablet / PC)
        │
        │  NMEA 0183 ASCII  @115200 bps  por USB (CH340N)
        ▼
┌─────────────────────────────────────┐
│   ESP32 Concentrador                │
│   NMEA 0183 ←→ NMEA 2000 gateway   │
└─────────────────────────────────────┘
        │
        │  NMEA 2000 (CAN 250 kbps)
        ▼
   Backbone del barco
  • USB → ESP32 (IN) : sentencias NMEA 0183 que el software envía como comandos
  • ESP32 → USB (OUT): sentencias NMEA 0183 que el ESP32 emite con datos del backbone
  • Formato: ASCII, terminado en \r\n, checksum NMEA estándar *XX
  • Velocidad: 115200 bps en todos los puertos USB

Hardware — Puertos USB

UART1 TX → CH340N #1 → USB-OUT1   (puente     — solo lectura)
         → CH340N #2 → USB-OUT2   (cockpit    — solo lectura)
         → CH340N #3 → USB-OUT3   (flybridge  — solo lectura)
         → CH340N #4 → USB-OUT4   (reserva    — solo lectura)

UART2 RX ← CH340N #5 ← USB-IN1   (puente     — manda comandos)
         ← CH340N #6 ← USB-IN2   (cockpit    — manda si tiene el mando)
         ← CH340N #7 ← USB-IN3   (flybridge  — manda si tiene el mando)
         ← CH340N #8 ← USB-IN4   (reserva    — futuro)

IDs de estación:

ID Estación Prioridad
01 Puente Máxima — override sin confirmación
02 Cockpit Normal
03 Flybridge Normal
04 Reserva Normal

Sentencias NMEA 0183 estándar (salida ESP32 → USB-OUT)

El ESP32 convierte los PGNs del backbone a estas sentencias y las emite por todos los puertos OUT cada vez que recibe datos nuevos del bus.

Sentencia Contenido PGN fuente Frecuencia
$IIHDT,x.x,T*XX Heading verdadero 127250 10 Hz
$IIROT,x.x,A*XX Rate of turn (°/min) 127251 10 Hz
$IIVHW,,,x.x,N,x.x,K*XX Velocidad agua 128259 1 Hz
$IIDPT,x.x,0.0*XX Profundidad 128267 1 Hz
$GPGLL,x.x,N,x.x,W,hhmmss,A*XX Posición GPS 129025 1 Hz
$GPRMC,...*XX GPS completo (COG, SOG) 129026 1 Hz
$IIMTW,x.x,C*XX Temperatura agua 130310 0.5 Hz
$IIMWV,...*XX Viento 130306 1 Hz

Sentencias propietarias AR-Autopilot (salida ESP32 → USB-OUT)

Prefijo $PARP (P=Proprietary, ARP=AR-Pilot).

Estado del autopilot (broadcast continuo, 2 Hz)

$PARP,STATUS,<modo>,<setpoint>,<heading>,<rudder>,<commander>*XX
Campo Valores
modo STANDBY HEADING_HOLD TRACK ALARM
setpoint heading objetivo en grados (000.0359.9)
heading heading actual en grados
rudder posición timón en grados (-35.0 a +35.0, + = estribor)
commander ID estación con el mando (0104, 00 = nadie)

Ejemplo:

$PARP,STATUS,HEADING_HOLD,045.5,044.8,-3.2,01*4F

Estado de transferencia de mando (broadcast al ocurrir)

$PARP,CMDTRANSFER,<desde>,<hacia>*XX
$PARP,CMDREQUEST,<estacion>*XX

Ejemplos:

$PARP,CMDTRANSFER,01,02*3A   ← el puente cedió el mando al cockpit
$PARP,CMDREQUEST,02*1B       ← cockpit pide el mando (pendiente de confirmación)

Sentencias propietarias AR-Autopilot (entrada USB-IN → ESP32)

El ESP32 solo acepta estas sentencias de la estación que tiene el mando, excepto TAKECMD y REQCMD que tienen reglas propias.

Formato general

$PARP,<COMANDO>,<parametro>,<station_id>*XX\r\n

Comandos de control del autopilot

Sentencia Acción → PGN NMEA 2000
$PARP,ENGAGE,000.0,01*XX Activar autopilot en heading actual PGN 127237 mode=heading_hold
$PARP,DISENGAGE,000.0,01*XX Desactivar autopilot PGN 127237 mode=standby
$PARP,SETHEADING,045.5,01*XX Fijar heading objetivo PGN 127237 commanded_heading
$PARP,PORTONE,000.0,01*XX Girar 1° a babor PGN 127237 (setpoint -= 1°)
$PARP,STBDONE,000.0,01*XX Girar 1° a estribor PGN 127237 (setpoint += 1°)
$PARP,PORTTEN,000.0,01*XX Girar 10° a babor PGN 127237 (setpoint -= 10°)
$PARP,STBDTEN,000.0,01*XX Girar 10° a estribor PGN 127237 (setpoint += 10°)

Comandos de transferencia de mando

Sentencia Acción Regla
$PARP,REQCMD,000.0,02*XX Solicitar el mando Avisa al commander actual; auto-transfer en 10s si no responde
$PARP,RELCMD,000.0,01*XX Ceder el mando voluntariamente Solo el commander actual
$PARP,TAKECMD,000.0,01*XX Tomar el mando por override Solo estación 01 (puente); inmediato, sin confirmación
$PARP,ACKCMD,000.0,01*XX Confirmar o denegar solicitud de mando Solo el commander actual
$PARP,DENYCMD,000.0,01*XX Denegar solicitud de mando Solo el commander actual

Protocolo de transferencia de mando

Estado normal: Puente (01) tiene el mando
                    │
Cockpit quiere mando:
    Cockpit ──► $PARP,REQCMD,000.0,02*XX
    ESP32 ──► broadcast $PARP,CMDREQUEST,02*XX  (todos se enteran)
                    │
           ┌────────┴────────┐
     Puente confirma     Puente deniega     Puente no responde (10s)
           │                  │                      │
  $PARP,RELCMD,02     $PARP,DENYCMD,02      auto-transfer
           │                  │                      │
  commander = 02      commander = 01         commander = 02
  $PARP,CMDTRANSFER,01,02*XX              $PARP,CMDTRANSFER,01,02*XX

Override del puente (siempre posible):
    Puente ──► $PARP,TAKECMD,000.0,01*XX
    ESP32 ──► commander = 01 inmediatamente
    ESP32 ──► broadcast $PARP,CMDTRANSFER,XX,01*XX

Mapeo NMEA 0183 → NMEA 2000

Sentencia IN PGN generado Descripción PGN
$PARP,ENGAGE 127237 Heading/Track Control — mode: heading_hold
$PARP,DISENGAGE 127237 Heading/Track Control — mode: standby
$PARP,SETHEADING 127237 commanded_heading field
$PARP,PORT* / $PARP,STBD* 127237 commanded_heading ± delta

Mapeo NMEA 2000 → NMEA 0183

PGN recibido Sentencia generada
127250 — Vessel Heading $IIHDT
127251 — Rate of Turn $IIROT
127237 — Heading/Track Control $PARP,STATUS
128259 — Speed Through Water $IIVHW
128267 — Water Depth $IIDPT
129025 — Position Rapid $GPGLL
129026 — COG & SOG $GPRMC
130310 — Water Temperature $IIMTW
130306 — Wind $IIMWV

Cálculo de checksum NMEA

def nmea_checksum(sentence: str) -> str:
    """sentence: contenido entre $ y * (sin incluir ambos)"""
    chk = 0
    for c in sentence:
        chk ^= ord(c)
    return f"{chk:02X}"

# Ejemplo:
# sentence = "PARP,STATUS,HEADING_HOLD,045.5,044.8,-3.2,01"
# checksum = "4F"
# resultado = "$PARP,STATUS,HEADING_HOLD,045.5,044.8,-3.2,01*4F\r\n"

Seguridad y validación en el ESP32

  1. Checksum inválido → descartar silenciosamente, no ejecutar
  2. Comando de estación sin mando → descartar, emitir $PARP,STATUS con commander actual
  3. Heading fuera de rango (< 0° o > 359.9°) → normalizar a rango válido
  4. Pérdida de datos del backbone (> 3s sin PGNs) → emitir alarma $PARP,STATUS,ALARM,...
  5. Desconexión USB-IN → no afecta la operación; el mando permanece asignado
  6. Power-on: commander = 00 (nadie), autopilot en STANDBY

Ejemplo de sesión completa

[t=0s]  OUT → $PARP,STATUS,STANDBY,000.0,182.3,+0.0,00*XX
[t=1s]  IN1 ← $PARP,REQCMD,000.0,01*XX          (puente toma el mando)
[t=1s]  OUT → $PARP,CMDTRANSFER,00,01*XX
[t=2s]  OUT → $PARP,STATUS,STANDBY,000.0,182.5,+0.0,01*XX
[t=3s]  IN1 ← $PARP,ENGAGE,000.0,01*XX
[t=3s]  OUT → $PARP,STATUS,HEADING_HOLD,182.5,182.5,+0.0,01*XX
[t=5s]  IN1 ← $PARP,STBDTEN,000.0,01*XX
[t=5s]  OUT → $PARP,STATUS,HEADING_HOLD,192.5,183.1,+2.5,01*XX
[t=10s] IN2 ← $PARP,REQCMD,000.0,02*XX          (cockpit pide mando)
[t=10s] OUT → $PARP,CMDREQUEST,02*XX
[t=15s] IN1 ← $PARP,RELCMD,000.0,01*XX          (puente lo cede)
[t=15s] OUT → $PARP,CMDTRANSFER,01,02*XX
[t=16s] IN2 ← $PARP,SETHEADING,200.0,02*XX
[t=16s] OUT → $PARP,STATUS,HEADING_HOLD,200.0,193.4,+3.8,02*XX