NMEA protokol i opis poruke
Sadržaj
A protokol je skup pravila koji definira kako se podaci formatiraju, prenose i interpretiraju između dva ili više uređaja kako bi se mogli međusobno razumjeti.
Zamislite to kao jezik sa strogim gramatičkim pravilima - i pošiljatelj i primatelj moraju slijediti potpuno ista pravila, inače je poruka besmislena. Bez protokola, svaki bi proizvođač izmislio vlastiti format i uređaji različitih marki ne bi mogli međusobno komunicirati.
NMEA-0183 protokol (od sada NMEA) je industrijski standard za GNSS tehnologiju.
Ovu stranicu smo pripremili kao referencu za definiciju NMEA protokola i kako bismo pružili opis najpopularnijih poruka. Ako propustite neku poruku ili pronađete tipografsku grešku, kontaktirajte nas i popravit ćemo to 🙂
Popularne NMEA poruke
| Poruka | Opis | Dostupnost |
|---|---|---|
| GGA | Podaci o fiksaciji globalnog pozicijskog sustava — položaj, nadmorska visina, kvaliteta fiksacije i broj satelita | Svi primatelji |
| GLL | Geografski položaj — zemljopisna širina i dužina s vremenom i statusom | Svi primatelji |
| GPS | Podaci o fiksaciji GNSS-a — slični GGA-u, ali podržavaju više konstelacija (GPS, GLONASS, Galileo...) | Svi primatelji |
| GR proširenje | Ostaci dometa GNSS-a — ostaci dometa korištenih u navigacijskom rješenju | Svi primatelji |
| GSA | GNSS DOP i aktivni sateliti — vrsta fiksacije (2D/3D) i korišteni sateliti | Svi primatelji |
| GST | Statistika pogreške pseudo-udaljenosti GNSS-a — procjene pogreške položaja (RMS, zemljopisna širina, zemljopisna dužina, nadmorska visina) | Svi primatelji |
| GSV | GNSS sateliti u vidnom polju — broj, elevacija, azimut i jačina signala vidljivih satelita | Svi primatelji |
| HDT | Pravi smjer — stvarni smjer plovila u odnosu na pravi sjever | Septentrio Mosaic-H simpleRTK3B Heading |
| INSPVAXA | Podaci fuzije senzora — integrirani položaj, brzina, stav i njihove procijenjene pogreške | Unicore UM981 simpleRTK3B Fusion |
| PUBX,00 | Podaci o položaju — zemljopisna širina, dužina, nadmorska visina i kvaliteta fiksne lokacije (u-blox uređaji) | Svi u-blox prijemnici |
| PUBX,04 | Vrijeme dana — UTC vrijeme i podaci o satu (u-blox uređaji) | Svi u-blox prijemnici |
| RMC | Preporučeni minimalni specifični GNSS podaci — položaj, brzina, kurs i datum | Svi primatelji |
| RED | Brzina okretanja - brzina rotacije plovila u stupnjevima u minuti | Septentrio Mosaic-H simpleRTK3B Heading |
| VTG | Kurs u odnosu na tlo i brzina u odnosu na tlo — putanja i brzina u čvorovima i km/h | Svi primatelji |
| SAD | Vrijeme i datum — UTC vrijeme, dan, mjesec, godina i lokalna vremenska zona | Svi primatelji |
Struktura NMEA poruke
Svaka poruka počinje s $ znak nakon kojeg slijedi kratki kod koji identificira vrstu podataka koje sadrži (vidi tablicu u sljedećem odjeljku).
Primatelj zatim ispunjava sva podatkovna polja odvojena zarezima - zemljopisnu širinu, dužinu, nadmorsku visinu, vrijeme, broj satelita itd. - i završava poruku s Kontrolni zbroj, što je mali broj koji omogućuje prijemnom uređaju da provjeri jesu li podaci oštećeni tijekom prijenosa.
Poruka završava prijelomom retka, a sljedeća poruka počinje odmah nakon toga.
Donja slika sažima kako se generira NMEA poruka.
Generiranje NMEA kontrolnog zbroja
Primjeri koda za generiranje NMEA kontrolnog zbroja na temelju NMEA korisnog tereta:
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)
Validacija NMEA kontrolnog zbroja
Ako želite provjeriti je li NMEA poruka legitimna ili ne, upotrijebite primjer koda u nastavku:
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"
Online kalkulator NMEA kontrolne sume
Kontrolni zbroj (hex)
--
Kontrolni zbroj (decimalni)
--
Duljina korisnog tereta
--
Puna rečenica
-
Provjerite rečenicu