NMEA-protokolla ja viestikuvaus
Sisällysluettelo
A protokolla on joukko sääntöjä, jotka määrittelevät, miten dataa muotoillaan, lähetetään ja tulkitaan kahden tai useamman laitteen välillä, jotta ne ymmärtävät toisiaan.
Ajattele sitä kielenä, jolla on tiukat kielioppisäännöt – sekä lähettäjän että vastaanottajan on noudatettava täsmälleen samoja sääntöjä, muuten viesti on merkityksetön. Ilman protokollia jokainen valmistaja keksisi oman muotonsa, eivätkä eri merkkien laitteet pystyisi kommunikoimaan keskenään.
NMEA-0183-protokolla (jäljempänä NMEA) on GNSS-teknologian alan standardi.
Olemme laatineet tämän sivun NMEA-protokollan määritelmän viitteeksi ja tarjotaksemme myös kuvauksen suosituimmista viesteistä. Jos jokin viesti puuttuu tai löydät kirjoitusvirheen, ota meihin yhteyttä ja me korjaamme sen 🙂
Suosittuja NMEA-viestejä
| Viesti | Tuotetiedot | Saatavuus: |
|---|---|---|
| GGA | GPS-paikannusjärjestelmän paikannustiedot — sijainti, korkeus, paikannuksen laatu ja satelliittien lukumäärä | Kaikki vastaanottajat |
| GLL | Maantieteellinen sijainti — leveys- ja pituusaste ajan ja tilan kanssa | Kaikki vastaanottajat |
| GPS | GNSS-paikannustiedot – samanlaisia kuin GGA, mutta tukevat useita tähtikuvioita (GPS, GLONASS, Galileo...) | Kaikki vastaanottajat |
| GRS | GNSS-alueen jäännökset — navigointiratkaisussa käytettyjen alueiden jäännökset | Kaikki vastaanottajat |
| GSA | GNSS DOP ja aktiiviset satelliitit — paikannustyyppi (2D/3D) ja käytetyt satelliitit | Kaikki vastaanottajat |
| GST | GNSS Pseudorange -virhetilastot — sijaintivirheiden arviot (RMS, leveysaste, pituusaste, korkeus) | Kaikki vastaanottajat |
| GSV | Näkyvissä olevat GNSS-satelliitit — näkyvissä olevien satelliittien lukumäärä, korkeus, atsimuutti ja signaalin voimakkuus | Kaikki vastaanottajat |
| HDT | Heading True — aluksen todellinen suunta suhteessa todelliseen pohjoiseen | Septentrio Mosaic-H simpleRTK3B Heading |
| INSPVAXA | Sensor Fusion -data — integroitu sijainti, nopeus, asento ja niiden arvioidut virheet | Unicore UM981 simpleRTK3B Fusion |
| PUBX,00 | Sijaintitiedot — leveysaste, pituusaste, korkeus ja paikannuksen laatu (u-blox laitteet) | Kaikki u-blox vastaanottimet |
| PUBX,04 | Kellonaika — UTC-aika ja kellotiedot (u-blox laitteet) | Kaikki u-blox vastaanottimet |
| RMC | Suositellut vähimmäisspesifiset GNSS-tiedot — sijainti, nopeus, kurssi ja päivämäärä | Kaikki vastaanottajat |
| RED | Kääntönopeus — aluksen pyörimisnopeus asteina minuutissa | Septentrio Mosaic-H simpleRTK3B Heading |
| VTG | Kurssi pohjan suhteen ja nopeus pohjan suhteen — reitti ja nopeus solmuina ja km/h | Kaikki vastaanottajat |
| ZDA | Aika ja päivämäärä — UTC-aika, päivä, kuukausi, vuosi ja paikallinen aikavyöhyke | Kaikki vastaanottajat |
NMEA-viestin rakenne
Jokainen viesti alkaa $ merkki, jota seuraa lyhyt koodi, joka ilmaisee sen sisältämän datan tyypin (katso seuraavan osan taulukko).
Vastaanottaja täyttää sitten kaikki pilkuilla erotetut tietokentät – leveysaste, pituusaste, korkeus, aika, satelliittien lukumäärä jne. – ja päättää viestin tarkistussumma, joka on pieni luku, jonka avulla vastaanottava laite voi varmistaa, ettei dataa ole vioittunut lähetyksen aikana.
Viesti päättyy rivinvaihtoon ja seuraava viesti alkaa heti sen perään.
Alla oleva kuva havainnollistaa NMEA-viestin luomista.
NMEA-tarkistussumman generointi
Koodiesimerkkejä NMEA-tarkistussumman luomiseksi NMEA-hyötykuorman perusteella:
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)
NMEA-tarkistussumman validointi
Jos haluat varmistaa, onko NMEA-viesti aito vai ei, käytä alla olevaa esimerkkikoodia:
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"
NMEA-tarkistussummalaskuri verkossa
Tarkistussumma (heksa)
--
Tarkistussumma (desimaali)
--
Hyötykuorman pituus
--
Koko lause
-
Vahvista lause