Description du protocole NMEA et des messages
Table des matières
A protocole Il s'agit d'un ensemble de règles qui définissent comment les données sont formatées, transmises et interprétées entre deux ou plusieurs appareils afin qu'ils puissent se comprendre.
Imaginez une langue aux règles grammaticales strictes : l’émetteur et le récepteur doivent respecter scrupuleusement les mêmes règles, sans quoi le message est incompréhensible. Sans protocoles, chaque fabricant inventerait son propre format et les appareils de marques différentes seraient incapables de communiquer entre eux.
Le protocole NMEA-0183 (désormais NMEA) est la norme industrielle pour la technologie GNSS.
Nous avons préparé cette page comme référence pour la définition du protocole NMEA et pour fournir également une description des messages les plus courants. Si un message manque ou si vous trouvez une faute de frappe, contactez-nous. et nous allons régler ça 🙂
Messages NMEA populaires
| Message | Description | Disponibilité |
|---|---|---|
| GGA | Données de positionnement global (GPS) — position, altitude, qualité du positionnement et nombre de satellites | Tous les récepteurs |
| GLL | Position géographique — latitude et longitude avec l'heure et le statut | Tous les récepteurs |
| GPS | Données de positionnement GNSS — similaires à GGA mais prennent en charge plusieurs constellations (GPS, GLONASS, Galileo...) | Tous les récepteurs |
| GRS | Résidus de portée GNSS — résidus des portées utilisées dans la solution de navigation | Tous les récepteurs |
| GSA | GNSS DOP et satellites actifs — type de correction (2D/3D) et satellites utilisés | Tous les récepteurs |
| GST | Statistiques d'erreur du pseudo-système GNSS — estimations d'erreur de position (RMS, latitude, longitude, altitude) | Tous les récepteurs |
| GSV | Satellites GNSS visibles — nombre, élévation, azimut et puissance du signal des satellites visibles | Tous les récepteurs |
| HDT | Cap vrai — cap réel du navire par rapport au nord vrai | Septentrio Mosaic-H simpleRTK3B Heading |
| INSPVAXA | Données de fusion de capteurs — position, vitesse, attitude intégrées et leurs erreurs estimées | Unicore UM981 simpleRTK3B Fusion |
| PUBX,00 | Données de position — latitude, longitude, altitude et qualité de la position (u-blox dispositifs) | Tous u-blox récepteurs |
| PUBX,04 | Heure du jour — Données d'heure et d'horloge UTC (u-blox dispositifs) | Tous u-blox récepteurs |
| RMC | Données GNSS minimales recommandées : position, vitesse, cap et date | Tous les récepteurs |
| POURRIR | Vitesse de rotation — vitesse de rotation du navire en degrés par minute | Septentrio Mosaic-H simpleRTK3B Heading |
| VTG | Cap et vitesse sol — route et vitesse en nœuds et km/h | Tous les récepteurs |
| Etats-Unis | Date et heure — Heure UTC, jour, mois, année et fuseau horaire local | Tous les récepteurs |
structure des messages NMEA
Chaque message commence par un $ signe suivi d'un code court qui identifie le type de données qu'il contient (voir tableau dans la section suivante).
Le récepteur remplit ensuite tous les champs de données séparés par des virgules — latitude, longitude, altitude, heure, nombre de satellites, etc. — et termine le message par un somme de contrôle, un petit nombre permettant au dispositif de réception de vérifier que les données n'ont pas été corrompues lors de la transmission.
Le message se termine par un saut de ligne et le message suivant commence immédiatement après.
L'image ci-dessous résume comment un message NMEA est généré.

Génération de somme de contrôle NMEA
Exemples de code pour générer la somme de contrôle NMEA à partir d'une charge utile 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)
Validation de la somme de contrôle NMEA
Pour vérifier la légitimité d'un message NMEA, utilisez l'exemple de code ci-dessous :
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"
Calculateur de somme de contrôle NMEA en ligne
Somme de contrôle (hexadécimal)
--
Somme de contrôle (décimal)
--
longueur de la charge utile
--
Phrase complète
-
Vérifier une phrase
et