Descripción del protocolo y del mensaje NMEA
Tabla de contenidos.
A protocolo Es un conjunto de reglas que define cómo se formatean, transmiten e interpretan los datos entre dos o más dispositivos para que puedan entenderse entre sí.
Imagínelo como un idioma con reglas gramaticales estrictas: tanto el emisor como el receptor deben seguir las mismas reglas, de lo contrario el mensaje carece de sentido. Sin protocolos, cada fabricante inventaría su propio formato y los dispositivos de diferentes marcas no podrían comunicarse entre sí.
El protocolo NMEA-0183 (en adelante, NMEA) es el estándar de la industria para la tecnología GNSS.
Hemos preparado esta página como referencia para la definición del protocolo NMEA y para proporcionar también una descripción de los mensajes más populares. Si falta algún mensaje o encuentra algún error tipográfico, Contactar con nosotros y lo arreglaremos 🙂
Mensajes NMEA populares
| Mensaje | Descripción | Disponibilidad |
|---|---|---|
| GGA | Datos de corrección del Sistema de Posicionamiento Global (GPS): posición, altitud, calidad de la corrección y número de satélites. | Todos los receptores |
| GLL | Posición geográfica: latitud y longitud con hora y estado. | Todos los receptores |
| GPS | Datos de corrección GNSS: similar a GGA pero admite múltiples constelaciones (GPS, GLONASS, Galileo...) | Todos los receptores |
| GRS | Residuos de rango GNSS: residuos de los rangos utilizados en la solución de navegación. | Todos los receptores |
| GSA | GNSS DOP y satélites activos: tipo de corrección (2D/3D) y satélites utilizados | Todos los receptores |
| GST | Estadísticas de error de pseudodistancia GNSS: estimaciones de error de posición (RMS, latitud, longitud, altitud) | Todos los receptores |
| VSG | Satélites GNSS visibles: número, elevación, acimut e intensidad de la señal de los satélites visibles. | Todos los receptores |
| HDT | Rumbo verdadero: rumbo real del buque con respecto al norte verdadero. | Septentrio Mosaic-H simpleRTK3B Heading |
| INSPVAXA | Datos de fusión de sensores: posición, velocidad, actitud integradas y sus errores estimados. | Unicore UM981 simpleRTK3B Fusion |
| PUBX,00 | Datos de posición: latitud, longitud, altitud y calidad de la corrección (u-blox dispositivos) | Todos u-blox receptores |
| PUBX,04 | Hora del día: hora UTC y datos del reloj (u-blox dispositivos) | Todos u-blox receptores |
| RMC | Datos GNSS específicos mínimos recomendados: posición, velocidad, rumbo y fecha. | Todos los receptores |
| ROJO | Velocidad de giro: velocidad de rotación del buque en grados por minuto. | Septentrio Mosaic-H simpleRTK3B Heading |
| VTG | Rumbo y velocidad respecto al terreno: ruta y velocidad en nudos y km/h. | Todos los receptores |
| Estados Unidos | Hora y fecha: hora UTC, día, mes, año y zona horaria local. | Todos los receptores |
Estructura de mensajes NMEA
Cada mensaje comienza con un $ signo seguido de un código corto que identifica el tipo de datos que contiene (ver tabla en la siguiente sección).
El receptor luego completa todos los campos de datos separados por comas —latitud, longitud, altitud, hora, número de satélites, etc.— y finaliza el mensaje con un suma de comprobación, que es un número pequeño que permite al dispositivo receptor verificar que los datos no se corrompieron durante la transmisión.
El mensaje finaliza con un salto de línea y el siguiente mensaje comienza inmediatamente después.
La siguiente imagen resume cómo se genera un mensaje NMEA.
Generación de suma de verificación NMEA
Ejemplos de código para generar la suma de verificación NMEA a partir de una carga útil NMEA:
def nmea_checksum(payload):
checksum = 0
for char in payload:
checksum ^= ord(char)
return f"{checksum:02X}"
# Pass only the part between $ and *
print(nmea_checksum("GNGGA,092725.00,4717.11399,N,00833.91986,E,1,08,1.01,499.6,M,48.0,M,,"))
# Returns: '4E' (or whatever the correct checksum is)
Validación de suma de comprobación NMEA
Si desea validar si un mensaje NMEA es legítimo o no, utilice el siguiente código de ejemplo:
def validate_nmea(sentence):
sentence = sentence.strip()
if not sentence.startswith('$') or '*' not in sentence:
return False
payload, claimed = sentence[1:].split('*', 1)
checksum = 0
for char in payload:
checksum ^= ord(char)
return f"{checksum:02X}" == claimed.strip()[:2].upper()
print(validate_nmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A")) # True
print(validate_nmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*FF")) # False
print(validate_nmea("invalid sentence")) # False
#include
#include
#include
#include
bool validate_nmea(const char *sentence) {
if (!sentence || *sentence != '$') return false;
const char *star = strchr(sentence, '*');
if (!star || strlen(star) < 3) return false;
uint8_t checksum = 0;
const char *p = sentence + 1;
while (p != star) {
checksum ^= (uint8_t)*p++;
}
uint8_t claimed;
if (sscanf(star + 1, "%2hhX", &claimed) != 1) return false;
return checksum == claimed;
}
int main() {
printf("%d\n", validate_nmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A")); // 1
printf("%d\n", validate_nmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*FF")); // 0
printf("%d\n", validate_nmea(NULL)); // 0
printf("%d\n", validate_nmea("invalid")); // 0
return 0;
}
function validateNmea(sentence) {
sentence = sentence.trim();
if (!sentence.startsWith('$') || !sentence.includes('*')) return false;
const starIdx = sentence.indexOf('*');
const payload = sentence.slice(1, starIdx);
const claimed = sentence.slice(starIdx + 1, starIdx + 3).toUpperCase();
if (claimed.length < 2 || !/^[0-9A-F]{2}$/.test(claimed)) return false;
let checksum = 0;
for (let i = 0; i < payload.length; i++) {
checksum ^= payload.charCodeAt(i);
}
return checksum.toString(16).toUpperCase().padStart(2, '0') === claimed;
}
validateNmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"); // true
validateNmea("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*FF"); // false
validateNmea("invalid"); // false
#include
#include
#include
uint8_t nmea_checksum(const char *sentence) {
// Skip leading '$' if present
if (*sentence == '$') sentence++;
uint8_t checksum = 0;
while (*sentence && *sentence != '*') {
checksum ^= (uint8_t)*sentence++;
}
return checksum;
}
int main() {
const char *sentence = "$GNGGA,092725.00,4717.11399,N,00833.91986,E,1,08,1.01,499.6,M,48.0,M,,";
printf("Checksum: %02X\n", nmea_checksum(sentence));
return 0;
}
function nmeaChecksum(sentence) {
// Strip leading $ and everything from * onwards
sentence = sentence.replace(/^\$/, '').split('*')[0];
let checksum = 0;
for (let i = 0; i < sentence.length; i++) {
checksum ^= sentence.charCodeAt(i);
}
return checksum.toString(16).toUpperCase().padStart(2, '0');
}
nmeaChecksum("GNGGA,092725.00,4717.11399,N,00833.91986,E,1,08,1.01,499.6,M,48.0,M,,");
// Returns: "4E"
Calculadora de suma de verificación NMEA en línea
Suma de verificación (hexadecimal)
--
Suma de verificación (decimal)
--
longitud de carga útil
--
Oración completa
-
Verificar una oración