NMEA 0183¶
NMEA 0183 là giao thức văn bản ASCII mà gần như mọi module GNSS đều xuất ra qua UART. Trang này trình bày lịch sử và phạm vi ứng dụng của giao thức, sau đó đến cấu trúc câu và các bản tin thường gặp. Cách đọc NMEA bằng gpsd và dùng cùng PPS xem GNSS trên Linux.
Lịch sử và ứng dụng¶
Tổ chức NMEA¶
NMEA (National Marine Electronics Association) là hiệp hội thương mại của ngành điện tử hàng hải, thành lập năm 1957 tại Mỹ. Hiệp hội không phát triển GNSS mà định nghĩa chuẩn kết nối các thiết bị điện tử trên tàu, để thiết bị của các hãng khác nhau giao tiếp được với nhau.
Vì sao có NMEA 0183¶
Trên tàu, mỗi thiết bị (máy dò sâu, la bàn, radar, máy đo gió, bộ thu định vị) ban đầu dùng giao tiếp riêng của hãng. Để hiển thị vị trí lên máy vẽ hải đồ hoặc đưa hướng đi cho lái tự động, cần một định dạng dữ liệu chung. NMEA 0183, công bố từ năm 1983, đáp ứng nhu cầu này:
- Một chiều, một nguồn phát, nhiều thiết bị nhận: thiết bị nguồn (talker) liên tục phát, các thiết bị khác (listener) chỉ nhận. Không cần thiết lập kết nối hay địa chỉ.
- Văn bản ASCII: đọc trực tiếp được, gỡ lỗi bằng terminal.
- Tốc độ thấp: chuẩn gốc dùng 4800 baud, 8 bit dữ liệu, không parity, 1 stop bit, đường tín hiệu kiểu RS-422. Tốc độ này đủ cho vài câu mỗi giây, phù hợp với dữ liệu hàng hải vốn thay đổi chậm.
Khi bộ thu GPS dân dụng xuất hiện, NMEA 0183 là giao diện sẵn có để đưa dữ liệu vị trí ra các thiết bị hiển thị, nên trở thành định dạng đầu ra phổ biến của bộ thu GPS.
Từ tàu biển ra mọi nơi¶
| Giai đoạn | Điều xảy ra |
|---|---|
| Thập niên 1980 | NMEA 0183 ra đời cho điện tử hàng hải |
| Thập niên 1990 | GPS dân dụng phổ biến, bộ thu thường xuất dữ liệu theo NMEA |
| Thập niên 2000 | Module GNSS được tích hợp vào thiết bị nhúng và di động, NMEA là định dạng chung để lấy vị trí và giờ |
| 2001 trở đi | NMEA 2000 (nền CAN) thay thế dần NMEA 0183 trên tàu mới |
| Về sau | NMEA OneNet (nền Ethernet) cho tàu cần băng thông lớn |
Hiện nay NMEA 0183 có hai vai trò: trên tàu, nó đang dần được thay bằng NMEA 2000 và OneNet; trong hệ thống nhúng, nó vẫn là định dạng chung của module GNSS nhờ đơn giản và phổ biến.
Các phiên bản sau chuẩn gốc bổ sung dần các trường mới. Ví dụ bộ chỉ thị chế độ (mode indicator) trong RMC, GLL, VTG, và các talker ID cho thêm hệ thống vệ tinh như Galileo, BeiDou khi chúng ra đời. Do đó parser không nên giả định số trường cố định, xem phần lưu ý bên dưới.
Về tài liệu chuẩn¶
Đặc tả NMEA 0183 do NMEA phát hành và không công khai miễn phí. Tài liệu thường dùng là mô tả của nhà sản xuất (như u-blox, Quectel) và tài liệu của gpsd, đã tổng hợp lại các câu phổ biến. Các định dạng bên dưới dựa trên những nguồn này, nên với một module cụ thể cần đối chiếu với datasheet của module đó.
Cấu trúc một câu¶
Dạng tổng quát:
| Phần | Ý nghĩa |
|---|---|
$ |
Ký tự bắt đầu câu. Câu đóng gói (như AIS) dùng ! thay cho $ |
| Talker ID (2 ký tự) | Nguồn của câu: GP (GPS), GL (GLONASS), GA (Galileo), GB (BeiDou), GN (kết hợp nhiều hệ thống) |
| Sentence ID (3 ký tự) | Loại bản tin: GGA, RMC, GSV... |
| Các trường | Phân cách bằng dấu phẩy. Trường rỗng vẫn giữ dấu phẩy |
* + checksum |
2 chữ số hex, là XOR của mọi ký tự nằm giữa $ và * |
CR LF |
Kết thúc câu. Độ dài tối đa là 82 ký tự gồm cả $ và CR LF |
Tính checksum¶
Ví dụ câu $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47. Lấy XOR từng ký tự của chuỗi GPGGA,123519,...,M,, (không tính $ và *) thì được 0x47:
from functools import reduce
def nmea_checksum(body: str) -> str:
return "%02X" % reduce(lambda a, c: a ^ ord(c), body, 0)
body = "GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,"
print(nmea_checksum(body)) # 47
Parser nên bỏ qua câu có checksum sai, đặc biệt khi đường UART có nhiễu.
Định dạng vị trí và thời gian¶
- Vĩ độ:
ddmm.mmmm, sau đó làNhoặcS. Kinh độ:dddmm.mmmm, sau đó làEhoặcW. Đây là độ và phút thập phân, không phải độ thập phân. - Đổi sang độ thập phân:
độ + phút/60. Ví dụ4807.038,Nlà 48 + 7.038/60 = 48.1173°. - Thời gian:
hhmmsshoặchhmmss.ss, tính theo UTC. - Ngày:
ddmmyy.
Các bản tin thường gặp¶
| Bản tin | Nội dung |
|---|---|
GGA |
Dữ liệu fix: vị trí, độ cao, chất lượng fix, số vệ tinh, HDOP |
RMC |
Dữ liệu tối thiểu: giờ UTC, ngày, vị trí, tốc độ, hướng, trạng thái hợp lệ |
GSA |
Chế độ fix và vệ tinh đang dùng, PDOP/HDOP/VDOP |
GSV |
Vệ tinh đang thấy: elevation, azimuth, C/N0 |
GLL |
Vị trí và giờ (dạng rút gọn) |
VTG |
Hướng và tốc độ trên mặt đất |
ZDA |
Ngày giờ đầy đủ và múi giờ |
GGA: Global Positioning System Fix Data¶
| # | Trường | Ví dụ | Ý nghĩa |
|---|---|---|---|
| 1 | Thời gian UTC | 123519 |
12:35:19 |
| 2, 3 | Vĩ độ, N/S | 4807.038,N |
48°07.038' Bắc |
| 4, 5 | Kinh độ, E/W | 01131.000,E |
11°31.000' Đông |
| 6 | Chất lượng fix | 1 |
0 không có fix, 1 GNSS fix, 2 DGPS, 4 RTK fixed, 5 RTK float |
| 7 | Số vệ tinh dùng | 08 |
|
| 8 | HDOP | 0.9 |
Độ loãng độ chính xác theo phương ngang, càng nhỏ càng tốt |
| 9, 10 | Độ cao so với mực nước biển | 545.4,M |
Mét |
| 11, 12 | Độ lệch geoid | 46.9,M |
Mét |
| 13, 14 | Tuổi dữ liệu DGPS, ID trạm | (rỗng) | Chỉ có khi dùng hiệu chỉnh |
Trường 6 cho biết đã có fix hay chưa. Nếu bằng 0 thì các trường vị trí thường rỗng hoặc không đáng tin.
RMC: Recommended Minimum¶
| # | Trường | Ví dụ | Ý nghĩa |
|---|---|---|---|
| 1 | Thời gian UTC | 123519 |
|
| 2 | Trạng thái | A |
A dữ liệu hợp lệ, V cảnh báo (chưa hợp lệ) |
| 3, 4 | Vĩ độ, N/S | 4807.038,N |
|
| 5, 6 | Kinh độ, E/W | 01131.000,E |
|
| 7 | Tốc độ mặt đất | 022.4 |
Knot (hải lý/giờ) |
| 8 | Hướng thật | 084.4 |
Độ |
| 9 | Ngày | 230394 |
23/03/1994 |
| 10, 11 | Độ lệch từ | 003.1,W |
|
| 12 | Chỉ thị chế độ | (có ở bản mới) | A tự động, D vi sai, E ước lượng, N không hợp lệ |
RMC là câu quan trọng khi lấy thời gian vì có cả ngày và giờ. Trường 2 phải là A thì mới dùng được. Đây là câu gpsd dùng để xác định giây (xem GNSS trên Linux).
GSA: DOP and Active Satellites¶
| # | Trường | Ý nghĩa |
|---|---|---|
| 1 | Chế độ chọn | A tự động 2D/3D, M thủ công |
| 2 | Loại fix | 1 không fix, 2 2D, 3 3D |
| 3 đến 14 | ID vệ tinh dùng | Tối đa 12, trường không dùng để rỗng |
| 15, 16, 17 | PDOP, HDOP, VDOP | Càng nhỏ càng tốt |
Ở bản mới có thêm trường cuối cho biết hệ thống (GPS, GLONASS...) vì câu GN không còn đủ thông tin.
GSV: Satellites in View¶
| # | Trường | Ý nghĩa |
|---|---|---|
| 1 | Tổng số câu GSV | Danh sách vệ tinh dài nên chia nhiều câu |
| 2 | Số thứ tự câu | |
| 3 | Số vệ tinh nhìn thấy | |
| 4 đến 7 | Vệ tinh thứ nhất | PRN, elevation (độ), azimuth (độ), C/N0 (dB-Hz) |
| 8 đến 19 | Tối đa 3 vệ tinh tiếp theo | Cùng cấu trúc 4 trường |
Mỗi câu GSV chứa tối đa 4 vệ tinh. Khi thu nhiều hệ thống, module xuất GSV riêng cho từng hệ thống (GPGSV, GLGSV, GAGSV...). C/N0 trống nghĩa là vệ tinh thấy nhưng chưa bám được. C/N0 là chỉ số dùng để đánh giá chất lượng ăng-ten và phát hiện nhiễu.
Các câu còn lại¶
GLL: vĩ độ, kinh độ, giờ, trạng thái. Cùng thông tin vị trí nhưGGAnhưng gọn hơn.VTG: hướng thật, hướng từ, tốc độ bằng knot và km/h.ZDA: giờ, ngày, tháng, năm và độ lệch múi giờ. Ví dụ$GNZDA,123519.00,23,03,1994,00,00*72cho đầy đủ năm 4 chữ số, hữu ích vìRMCchỉ có năm 2 chữ số.
Câu riêng của hãng¶
Câu bắt đầu bằng $P theo sau là mã nhà sản xuất 3 ký tự là câu proprietary, nằm ngoài chuẩn. Ví dụ u-blox dùng $PUBX,... để cấu hình module hoặc xuất thêm thông tin (PUBX,00 cho vị trí, PUBX,04 cho thời gian). Phần này khác nhau nhiều giữa các hãng, cần tra tài liệu của hãng.
Lưu ý khi viết parser¶
- Không giả định số trường cố định. Phiên bản mới có thể thêm trường ở cuối, parser nên bỏ qua trường thừa thay vì báo lỗi.
- Trường rỗng là trường hợp bình thường, nhất là khi chưa fix: kiểm tra
RMCtrạng tháiAhoặcGGAchất lượng khác0trước khi dùng vị trí. - Kiểm tra checksum trước khi xử lý.
- Câu có thể bị cắt hoặc ghép khi UART bị tràn, nên đọc theo từng dòng và bỏ câu không đủ.
- Talker ID
GNxuất hiện khi module kết hợp nhiều hệ thống. Không nên chỉ lọcGP. - Độ trễ: NMEA đi qua UART ở tốc độ baud hữu hạn, nên câu đến trễ so với thời điểm đo. Để lấy thời gian chính xác thì dùng PPS, xem GNSS trên Linux.
Kiểm tra nhanh¶
Hoặc dùng gpspipe -r để xem câu NMEA thô khi đang chạy gpsd.
Đọc thêm¶
- NMEA 0183 standard: trang chính thức của NMEA (đặc tả bán).
- NMEA Revealed (Eric Raymond): tài liệu tổng hợp các câu NMEA của dự án
gpsd. - GNSS: nguyên lý và độ chính xác.
- GNSS trên Linux:
gpsd, PPS,chrony.