NMEA 0183 — GPS receiver communication standard: from marine electronics to GPS logs

2026-06-2712 min read
NMEANMEA-0183GPSGNSSmarinenavigationserialprotocol

NMEA 0183 isn't a file format in the usual sense — it's a text-based serial protocol over which a GPS receiver talks to any consumer device: marine radar, autopilot, fishfinder, aviation navigator, mobile app, plain laptop. The specification belongs to the National Marine Electronics Association — a US trade association of marine electronics manufacturers founded in 1957. The 0183 standard itself was published in 1983 and remains in use forty-plus years later: the vast majority of GPS chipsets in the world — from u-blox NEO-M9N in a handheld logger to industrial Septentrio in marine equipment — emit NMEA 0183 as one of their working ASCII output streams.

Map generation of New York city center
Manhattan, midtown. Any on-board GPS receiver passing under the Brooklyn Bridge emits $GPGGA sentences with coordinates — record them to a file, run through gpsbabel, and you have a ready GPX track with millisecond-level timing.

History: from RS-422 on the bridge to USB on the laptop

In 1983 the National Marine Electronics Association — an organization of North American marine-electronics manufacturers — released the third revision of its inter-device communication standard and called it NMEA 0183. Previous versions 0180 and 0182 were limited to Loran-C and earlier radio-navigation data; 0183 expanded the protocol into a universal text language any navigation sensor could speak to any consumer.

The original NMEA 0183 physical layer was a differential RS-422 line at 4800 baud. One transmitter, up to four receivers on the bus, cable length up to fifty meters. Enough for a typical yacht: a GPS receiver on the upper deck transmits strings into the chartplotter in the cabin, autopilot at the helm, and radar in the wheelhouse simultaneously. The standard explicitly describes: one device — talker (transmitter), several devices — listeners (receivers), communication strictly unidirectional.

By the early 2000s NMEA 0183-HS — High Speed, 38400 baud — appeared for AIS vessel-identification data, where 4800 baud physically could not keep up. Today's GPS chipsets like u-blox NEO-M9N now emit NMEA 0183 through USB virtual COM port (CDC-ACM), Bluetooth Serial Port Profile (SPP), and UART at 115200 baud. Physical RS-422 survives only on semi-industrial marine installations; new electronics work over USB or wireless, but the textual protocol above formally remains 0183, because manufacturers find it easier to stick with the familiar format than migrate every minor device to NMEA 2000 CAN-bus.

The latest specification — NMEA 0183 v4.11 — was published in 2018. The document remains paid and is distributed by the association under license; in practice most manufacturers either buy access once or rely on community documentation from open sources like gpsd and the kplex project.

Inside an NMEA sentence

NMEA 0183 is text. Each line (sentence) fits in a single ASCII line, starts with $, ends with CRLF, and never exceeds 82 characters including framing. The format is utterly transparent:

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

Field by field. $GP — talker ID: the two characters after $ identify the transmitter type. GP means GPS receiver; GL — GLONASS, GA — Galileo, BD — BeiDou, GN — combined GNSS receiver merging several constellations. GGA — sentence ID: the message type. GGA is Global Positioning System Fix Data — the most important sentence carrying current position. Then comma-separated fields: time as HHMMSS, latitude, latitude hemisphere (N/S), longitude, longitude hemisphere (E/W), fix-quality flag (0 = no fix, 1 = autonomous GPS, 2 = DGPS), satellite count, HDOP, altitude above mean sea level, altitude unit, geoidal separation and unit, age of DGPS correction, reference station ID. After the final comma comes * and a two-digit hex checksum: XOR of all bytes between $ and *. The line ends in CRLF.

Beyond GGA, several other sentences matter for GPS logging:

  • $GPRMC — Recommended Minimum Course: the minimum required set. Time, status (A — valid, V — invalid), position, speed in knots, track angle, date, magnetic variation. If you want to keep a track with one sentence type — RMC covers everything.
  • $GPGSA — GPS DOP and Active Satellites: fix mode (2D/3D), list of active satellite PRNs, PDOP, HDOP, VDOP. Useful for evaluating positioning quality.
  • $GPGSV — Satellites in View: per-satellite PRN, elevation, azimuth, SNR. Several lines in a row when more than four satellites are visible.
  • $GPVTG — Track Made Good and Ground Speed: course over ground (true and magnetic) and speed in knots and km/h.
  • $GPGLL — Geographic Position Latitude/Longitude: position and time only.

A typical 1 Hz GPS stream is the chain GGA + RMC + GSA + 2-4×GSV + VTG repeating every second. At 10 Hz it's the same ten times per second — about 1 KB/s of text traffic over UART.

Who needs NMEA 0183: five roles

Marine captain or yacht owner. This is the standard's original audience. On a yacht bridge the GPS receiver, via an NMEA 0183 bus, feeds several devices at once: chartplotter shows position on a chart, autopilot holds course toward a waypoint, radar overlay anchors the radar image to geographic coordinates, fishfinder pins fishing spots with coordinates. One RS-422 wire — four independent consumers. If one breaks, the others keep working.

Surveyor or geodesist. In field work with an RTK receiver NMEA 0183 is the main way to read the coordinate stream from base station or rover. Trimble, Leica, Topcon, Sokkia — all these brands emit proprietary binary formats for their own software plus standard NMEA 0183 for everything else. The field application connects via Bluetooth, reads $GPGGA and $GPGSA, fixes the point, saves it with a label.

Embedded developer. A GPS chipset on a board is a UART interface emitting NMEA 99% of the time. ESP32 or Arduino with a u-blox NEO-M9N module connects via two wires (TX/RX), and within seconds of cold start begins streaming $GPGGA lines. A C parser fits in 200-300 lines and runs on any microcontroller. This is why NMEA 0183 survives: alternative binary protocols like UBX or SiRF are faster and tighter but require chipset-specific documentation, while NMEA is the same everywhere.

Mobile navigation app developer. OsmAnd, Locus Map, Marine Tracker, Navionics — all consume an NMEA stream from a Bluetooth GPS receiver or the phone's built-in chipset. Modern Android offers the high-level LocationManager API, but low-level NMEA access is still needed — for example, a multi-GNSS receiver with improved precision or recording raw RINEX observations.

GPS-logging hobbyist. Runners, cyclists, RC-aircraft pilots, drone operators — all log tracks. The aging Holux M-1200, Garmin GLO, Bad Elf GPS Pro+ emit clean NMEA 0183 via Bluetooth. Years ago they were piped through GPSBabel into GPX; today most apps convert on the fly. Raw .nmea log files are kept for future re-processing — for example, post-processing with RTK corrections.

Software for NMEA: seven tools

OpenCPN. Open chart plotter for PC and Mac, originally written by a sailor community. Accepts NMEA 0183 stream via serial, USB, TCP/UDP, displays position on vector and raster charts. Supports AIS, autopilot integration, route planning, weather GRIB. Free, cross-platform. opencpn.org

gpsd (Linux GPS daemon). A system daemon that reads the NMEA stream from a connected device and serves parsed coordinates via JSON API on TCP port 2947. Used by any Linux software needing GPS: cgps, foxtrotgps, GPSDrive, navit, mobile apps via libgps. The de facto Linux GPS standard. gpsd.gitlab.io/gpsd

pynmea2. Python library for parsing and building NMEA strings. pip install pynmea2. Minimal code: msg = pynmea2.parse(line), then msg.latitude, msg.longitude, msg.timestamp are accessible as plain attributes. Convenient for batch log processing. github.com/Knio/pynmea2

u-center. Free GUI for u-blox GPS receivers. Connects to the chipset via USB or UART, shows real-time satellite map, SNR plots, surveys, allows chipset configuration (enable/disable sentences, change rate, configure SBAS/QZSS). Indispensable for embedded-device debugging. Windows-only, runs under Wine. u-blox.com/en/product/u-center

kplex (NMEA Multiplexer). Linux daemon for combining NMEA streams from multiple sources. For example, GPS + AIS + wind sensor on a yacht — three different physical ports, kplex merges into one TCP stream. Open source, written in C. github.com/stripydog/kplex

NMEA Simulator. Windows program for generating an NMEA stream without a real GPS. Parameterizes route, speed, sentence types. Used for chartplotter testing, navigation-app development without dragging hardware outside. nmeasimulator.com

MarineTraffic AIS apps. Family of apps and the MarineTraffic website for tracking marine vessels via AIS — AIS is carried in NMEA 0183 sentences like $AIVDM. Integration with one's own NMEA stream lets you see your own yacht on the shared map. marinetraffic.com

Pitfalls and tips

Talker ID isn't always GPS. Modern multi-constellation receivers (u-blox M9N, M10, Septentrio Mosaic, Quectel LC79D) emit $GN instead of $GP for combined fix. This means: position computed from GPS+GLONASS+Galileo simultaneously. A parser strictly expecting $GP will skip such lines. Correct matching — by the last three characters of the sentence ID, ignoring the talker ID or accepting any.

Always verify the checksum. In a real serial channel lines occasionally arrive corrupted: cable interference, USB hub glitches, buffer overruns. Not checking the *XX checksum means occasionally getting coordinates with a shifted decimal point and ending up a thousand miles into the ocean. Any decent NMEA library checks automatically, but if you're writing a parser from scratch — checksum is mandatory.

Map generation of Tokyo city center
Shibuya, Tokyo. Urban canyon is the classic GPS-degradation zone: in these conditions $GPGSA reports HDOP above 5, and an automotive navigator refuses fix until the car emerges from the skyscraper shadow.

Position precision matches the string. The latitude field in $GPGGA is DDMM.MMMM — degrees, minutes with a decimal part. Four digits after the dot in minutes means 0.0001-minute resolution, about 18 cm at the equator. On consumer GPS this is excessive: real error is 3-5 m. But an RTK receiver with 1-2 cm accuracy emits DDMM.MMMMMMM (seven digits), and the parser must accommodate.

Altitude isn't WGS84 altitude. The altitude field in $GPGGA is height above geoid (mean sea level), not above the WGS84 ellipsoid. To get ellipsoidal height (the GIS standard), add the geoidal separation field (the 46.9,M in the example). GPX converters sometimes forget this, and tracks acquire a 100-meter altitude offset in mountainous regions.

Antimeridian. A GPS receiver on Chukotka or in Kamchatka Bay may emit longitude 179.999 on one line and -179.999 on the next. The NMEA parser must handle this transition, otherwise a "jump" across half the globe appears on the map. In practice 99% of consumer apps don't handle it, because the average user never sails across the antimeridian.

NMEA 2000 is a different protocol. Despite the similar name, NMEA 2000 (released 2001) is not the next version of 0183 but a separate standard: CAN-bus 250 kbit/s, binary PGN packets, completely incompatible with 0183 physically and logically. Modern marine systems use NMEA 2000 as the internal bus between ECUs and convert to 0183 for compatibility with older electronics via gateways. If two devices don't talk to each other — verify that one isn't emitting 2000 while the other reads only 0183.

Using NMEA 0183 in an osm2cdr.ru workflow

osm2cdr.ru generates vector and raster OSM maps — those are outputs. NMEA 0183 is an input from a device. There's no direct connection, but two classic pipeline chains exist.

Scenario 1: record a device track, overlay on an osm2cdr map. Connect a GPS receiver via USB or Bluetooth, record raw NMEA into a text file (e.g., via screen /dev/ttyUSB0 4800 or a phone app). Then convert to GPX through gpsbabel:

gpsbabel -i nmea -f track.nmea -o gpx -F track.gpx

Open the resulting GPX in QGIS alongside the osm2cdr.ru export in SHP or GeoJSON for the target area. This gives ground-truth mapping: for instance, verify that new buildings missing from OSM appear in the track from a real walk.

Scenario 2: osm2cdr route → OpenCPN → yacht. You plan a harbor entry on osm2cdr.ru, export the coastline as SHP or GPX, import into OpenCPN, which can emit an NMEA 0183 stream to a physical port. Over an NMEA cable that stream flows into the onboard chartplotter, and the yacht gets an updated coastline database.

Python parser — minimal. If you need to quickly analyze your own log:

import pynmea2

with open('track.nmea') as f:
    for line in f:
        if line.startswith('$GPGGA') or line.startswith('$GNGGA'):
            try:
                msg = pynmea2.parse(line)
                if msg.gps_qual > 0:  # fix present
                    print(f"{msg.timestamp}: {msg.latitude:.6f}, {msg.longitude:.6f}, alt={msg.altitude}m")
            except pynmea2.ParseError:
                pass  # corrupted line — skip

Such a script processes a 100 MB daily log in 5 seconds and produces CSV for further pandas analysis or PostGIS import.

Map generation of Sydney city center
Sydney Harbour. Entering under the Harbour Bridge the GPS signal reflects off the steel structure — single-GPS yachts see position jitter 10-20 meters, and an NMEA 0183 chartplotter draws a "snake" around the real heading.

Sources

← All articles