NMEA протокол и опис поруке
Преглед садржаја
A протокол је скуп правила који дефинише како се подаци форматирају, преносе и интерпретирају између два или више уређаја како би се могли међусобно разумети.
Замислите то као језик са строгим граматичким правилима — и пошиљалац и прималац морају да се придржавају потпуно истих правила, иначе је порука бесмислена. Без протокола, сваки произвођач би измислио свој формат и уређаји различитих брендова не би могли да комуницирају једни са другима.
NMEA-0183 протокол (од сада NMEA) је индустријски стандард за GNSS технологију.
Ову страницу смо припремили као референцу за дефиницију NMEA протокола и да бисмо пружили опис најпопуларнијих порука. Ако пропустите неку поруку или пронађете неку грешку у куцању, контактирајте нас и ми ћемо то поправити 🙂
Популарне NMEA поруке
| Poruka | Opis | Доступност |
|---|---|---|
| ГГА | Подаци о фиксирању глобалног позиционог система — положај, надморска висина, квалитет фиксирања и број сателита | Сви примачи |
| ГЛЛ | Географски положај — географска ширина и дужина са временом и статусом | Сви примачи |
| ГНС | Подаци о фиксирању ГНСС-а — слични ГГА-у, али подржавају више констелација (ГПС, ГЛОНАСС, Galileo...) | Сви примачи |
| ГРС | ГНСС резидуали домета — резидуали домета коришћени у навигационом решењу | Сви примачи |
| ГСА | ГНСС DOP и активни сателити — тип фиксирања (2Д/3Д) и коришћени сателити | Сви примачи |
| GST | Статистика грешака GNSS псеудорајзи — процене грешака позиције (RMS, географска ширина, географска дужина, надморска висина) | Сви примачи |
| ГСВ | ГНСС сателити у видљивом положају — број, елевација, азимут и јачина сигнала видљивих сателита | Сви примачи |
| ХДТ | Прави смер — стварни смер пловила у односу на прави север | Septentrio Mosaic-H simpleRTK3B Heading |
| ИНСПВАКСА | Подаци сензорске фузије — интегрисана позиција, брзина, став и њихове процењене грешке | Unicore УМКСНУМКС simpleRTK3B Fusion |
| PUBX,00 | Подаци о позицији — географска ширина, дужина, надморска висина и квалитет фиксирања (u-blox уређаји) | Sve u-blox пријемници |
| PUBX,04 | Време дана — UTC време и подаци о сату (u-blox уређаји) | Sve u-blox пријемници |
| РМЦ | Препоручени минимални специфични GNSS подаци — позиција, брзина, курс и датум | Сви примачи |
| ЦРВЕНА | Брзина окрета — брзина ротације пловила у степенима у минути | Septentrio Mosaic-H simpleRTK3B Heading |
| ВТГ | Курс у односу на тло и брзина у односу на тло — путања и брзина у чворовима и км/х | Сви примачи |
| сад | Време и датум — UTC време, дан, месец, година и локална временска зона | Сви примачи |
Структура NMEA поруке
Свака порука почиње са $ знак праћен кратким кодом који идентификује врсту података које садржи (видети табелу у следећем одељку).
Пријемник затим попуњава сва поља са подацима одвојена зарезима — географску ширину, дужину, надморску висину, време, број сателита итд. — и завршава поруку са цхецкум, што је мали број који омогућава пријемном уређају да провери да ли су подаци оштећени током преноса.
Порука се завршава преломом реда, а следећа порука почиње одмах након тога.
Слика испод сумира како се генерише NMEA порука.

Генерисање NMEA контролне суме
Примери кода за генерисање NMEA контролне суме на основу 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)
NMEA валидација контролне суме
Ако желите да проверите да ли је NMEA порука легитимна или не, користите пример кода испод:
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 контролне суме
Контролни збир (хекс)
--
Контролни збир (децимални)
--
Дужина носивости
--
Пуна реченица
-
Провери реченицу