Descrição do protocolo e da mensagem NMEA
Índice
A protocolo É um conjunto de regras que define como os dados são formatados, transmitidos e interpretados entre dois ou mais dispositivos para que possam se entender.
Imagine uma língua com regras gramaticais rígidas — tanto o remetente quanto o destinatário devem seguir exatamente as mesmas regras, caso contrário a mensagem não faz sentido. Sem protocolos, cada fabricante criaria seu próprio formato e dispositivos de marcas diferentes seriam incapazes de se comunicar entre si.
O protocolo NMEA-0183 (doravante NMEA) é o padrão da indústria para a tecnologia GNSS.
Preparamos esta página como referência para a definição do protocolo NMEA e também para fornecer uma descrição das mensagens mais comuns. Se você não encontrar alguma mensagem ou algum erro de digitação, entre em contato connosco E nós vamos resolver isso 🙂
Mensagens NMEA populares
| Mensagem | Descrição | Disponibilidade |
|---|---|---|
| GGA | Dados de localização do Sistema de Posicionamento Global (GPS) — posição, altitude, qualidade da localização e número de satélites. | Todos os receptores |
| GLL | Posição geográfica — latitude e longitude com hora e status | Todos os receptores |
| GNS | Dados de fixação GNSS — semelhante ao GGA, mas suporta múltiplas constelações (GPS, GLONASS, Galileo...) | Todos os receptores |
| GRS | Resíduos de alcance GNSS — resíduos dos alcances usados na solução de navegação | Todos os receptores |
| GSA | GNSS DOP e satélites ativos — tipo de sinal (2D/3D) e satélites utilizados | Todos os receptores |
| GST | Estatísticas de erro de pseudodistância GNSS — estimativas de erro de posição (RMS, latitude, longitude, altitude) | Todos os receptores |
| GSV | Satélites GNSS visíveis — número, elevação, azimute e intensidade do sinal dos satélites visíveis | Todos os receptores |
| HDT | Rumo verdadeiro — rumo real da embarcação em relação ao norte verdadeiro. | Septentrio Mosaic-H simpleRTK3B Heading |
| INSPVAXA | Dados de fusão de sensores — posição, velocidade, atitude integradas e seus erros estimados. | Unicore UM981 simpleRTK3B Fusion |
| PUBX,00 | Dados de posição — latitude, longitude, altitude e qualidade da fixação (u-blox dispositivos) | Todas as u-blox receptores |
| PUBX,04 | Hora do dia — Datas de hora e relógio UTC (u-blox dispositivos) | Todas as u-blox receptores |
| RMC | Dados GNSS específicos mínimos recomendados — posição, velocidade, rumo e data. | Todos os receptores |
| RED | Taxa de rotação — velocidade de rotação da embarcação em graus por minuto | Septentrio Mosaic-H simpleRTK3B Heading |
| VTG | Rota sobre o solo e velocidade em relação ao solo — rumo e velocidade em nós e km/h | Todos os receptores |
| EUA | Hora e data — Hora UTC, dia, mês, ano e fuso horário local | Todos os receptores |
Estrutura da mensagem NMEA
Cada mensagem começa com um $ sinal seguido de um código curto que identifica o tipo de dados que contém (consulte a tabela na próxima seção).
O receptor preenche então todos os campos de dados separados por vírgulas — latitude, longitude, altitude, hora, número de satélites, etc. — e finaliza a mensagem com um ponto. checksum, que é um número pequeno que permite ao dispositivo receptor verificar se os dados não foram corrompidos durante a transmissão.
A mensagem termina com uma quebra de linha e a próxima mensagem começa imediatamente em seguida.
A imagem abaixo resume como uma mensagem NMEA é gerada.

Geração de checksum NMEA
Exemplos de código para gerar o checksum NMEA com base em uma 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)
Validação de checksum NMEA
Se você deseja validar se uma mensagem NMEA é legítima ou não, use o código de exemplo abaixo:
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 online de checksum NMEA
Soma de verificação (hexadecimal)
--
Soma de verificação (decimal)
--
comprimento da carga útil
--
Frase completa
-
Verifique uma frase
e