RTCM Unpacked: The Binary Protocol Your RTK Fix Actually Depends On

AUTHOR: Zero Jiang | TITLE: Founder, Kalmix


If you've built an RTK system, you likely already speak NMEAโ€”that readable ASCII stream telling you where you are. You've probably configured an NTRIP client to pull correction data over the internet. But have you ever looked inside the binary payload NTRIP is actually carrying?

That payload is RTCM. It contains the raw satellite observations from a reference station, encoded into a compact binary format. Your receiver consumes this data to jump from meter-level standalone positioning to centimeter-level RTK. If NMEA is the final answer your receiver gives you, RTCM is the cheat sheet it needs to get the answer right.

In this volume of the Kalmix GNSS Handbook, we crack open the RTCM binary stream. We'll cover what's inside it, which messages actually matter, how to choose between MSM4 and MSM7, and what to check when your rover stubbornly refuses to Fix.

๐Ÿ“š Need-to-Know Terms
  • MSM (Multiple Signal Messages): The modern RTCM 3.2+ message family supporting all GNSS constellations.
  • OSR (Observation Space Representation): Corrections sending raw base station observations.
  • SSR (State Space Representation): Corrections sending modeled error components.
  • ARP (Antenna Reference Point): The base station's physical ECEF coordinates, broadcast in MT1005/1006.

Where RTCM Fits in the RTK Data Chain

RTK Data Chain Diagram: Base Station to NTRIP Caster to Rover

Every RTK system relies on two data flows moving in opposite directions:

  • RTCM flows IN: Carrying correction data from the reference station.
  • NMEA flows OUT: Carrying the computed position to your host controller.

NTRIP is just the delivery truck; RTCM is the cargo. Your receiver takes the base station's RTCM observations, differences them against its own, and resolves carrier-phase ambiguities to produce centimeter-level coordinates.

๐ŸŽฏ Engineer's Takeaway

The quality of your RTK solution is fundamentally bounded by the RTCM input. You can parse GGA perfectly, but if the RTCM stream is misconfigured or dropping packets, your Fix Quality (GGA Field 6) will never reach 4. If you can't Fix, start debugging upstream.

RTCM vs. NMEA: Inputs and Outputs

If you read Vol. 2 of this handbook, you know NMEA inside and out. Here is how RTCM compares:

Property RTCM 3.x NMEA 0183
Direction Input (Corrections โ†’ Receiver) Output (Receiver โ†’ Host)
Encoding Binary (Compact) ASCII (Human-readable)
Error Check CRC-24Q (24-bit) XOR Checksum (8-bit)
Frame Delimiter Preamble 0xD3 + Length Field $ start, * checksum, CR LF

RTCM's binary encoding is roughly 5โ€“10x more bandwidth-efficient than ASCII. This is why it survives on constrained serial radio links where every byte counts.

A Brief History of RTCM 3

Version Standard No. Official Title Year
RTCM V1 10401 Differential GPS Services 1985
RTCM V2.0 10402.0 Differential GPS Services โ€“ Version 2 1990
RTCM V2.3 10402.3 Differential GPS Services โ€“ Version 2 (Final V2) 2001
RTCM V3.0 10403.0 Differential GNSS Services โ€“ Version 3 2004
RTCM V3.1 10403.1 Differential GNSS Services โ€“ Version 3 2006
RTCM V3.2 10403.2 Differential GNSS Services โ€“ Version 3 2013
RTCM V3.3 10403.3 Differential GNSS Services โ€“ Version 3 (incl. Amendments) 2016
RTCM V4.0 10403.4 Differential GNSS Services โ€“ Version 4 2023

Versions 1 and 2 were built in the 80s and 90s for maritime DGPS. They used rigid, 30-bit words unsuited for the high data volumes of modern RTK. Forget them.

The modern era began with Version 3 (2004), featuring variable-length frames and robust 24-bit CRCs. But the true landmark was V3.2 (2013), which introduced Multiple Signal Messages (MSM).

Before MSM, legacy messages (MT1001โ€“1012) were hard-coded strictly for GPS and GLONASS. The standard literally had no numbering space for Galileo or BeiDou. MSM fixed this architectural dead-end with a constellation-agnostic matrix design.

The bottom line: If you are still using Legacy messages in 2025, you are artificially handicapping your receiver's multi-constellation capabilities.

Inside the Packet: Frame Structure

Every RTCM 3.x frame follows the exact same envelope:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ Preamble โ”‚ Reserved โ”‚  Length  โ”‚ Payload  โ”‚ CRC-24Q  โ”‚

โ”‚  8 bit   โ”‚  6 bit   โ”‚  10 bit  โ”‚ Variable โ”‚  24 bit  โ”‚

โ”‚  0xD3    โ”‚  000000  โ”‚ 0-1023   โ”‚ (binary) โ”‚          โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Unlike NMEA, there are no newline characters. You cannot just "read a line." You must synchronize on 0xD3, read the length field, extract exactly that many payload bytes, and verify the CRC.

Here is the canonical pattern in Python:

"""

RTCM 3.x frame sync & extraction from a TCP/serial stream.

CRITICAL: TCP delivers arbitrary byte chunks. Never assume

one recv() = one complete RTCM frame. Always buffer.

"""

import struct



CRC24Q_POLY = 0x1864CFB



def crc24q(data: bytes) -> int:

    crc = 0

    for byte in data:

        crc ^= byte << 16

        for _ in range(8):

            crc <<= 1

            if crc & 0x1000000:

                crc ^= CRC24Q_POLY

    return crc & 0xFFFFFF



def extract_frames(buf: bytearray) -> list[bytes]:

    frames = []

    while True:

        idx = buf.find(0xD3)                          # Step 1: Find preamble

        if idx < 0 or idx + 3 > len(buf): break

        

        length = ((buf[idx+1] & 0x03) << 8) | buf[idx+2]  # Step 2: Read 10-bit length

        frame_len = 3 + length + 3                    # header + payload + CRC

        

        if idx + frame_len > len(buf): break          # Wait for more data

            

        frame = bytes(buf[idx : idx + frame_len])

        if crc24q(frame[:-3]) == struct.unpack('>I', b'\x00' + frame[-3:])[0]:  # Step 3: Verify CRC

            msg_type = (frame[3] << 4) | (frame[4] >> 4)   

            frames.append(frame)

            

        del buf[:idx + frame_len]

    return frames

The Message Groups & The Two "Silent Killers"

RTCM 3.x defines hundreds of message types, but RTK only requires a handful:

Group Typical MTs Purpose RTK Required?
Observations (MSM) 1071โ€“1127 All constellations, multi-signal โœ… Yes
Station Coordinates 1005 / 1006 Base station ARP (ECEF) โœ… Mandatory
GLONASS Bias 1230 FDMA inter-frequency bias โœ… If using GLO
Observations (Legacy) 1001โ€“1012 GPS/GLONASS only Legacy only
Antenna / Ephemeris 1033 / 1019+ Receiver info, broadcast ephemeris Optional

While observations (MSM) are obvious, developers constantly trip over two "silent killers":

  1. MT1005/1006 (Base Station Identity): These carry the base station's physical coordinates. Without them, your rover cannot compute a baseline vector. No station coordinates = no baseline = no Fix.
  2. MT1230 (GLONASS Interoperability): GLONASS uses FDMA (Frequency Division Multiple Access), creating hardware biases between different receiver brands. MT1230 carries the code-phase bias compensation. Without it, your rover will see GLONASS satellites in the sky, but silently refuse to use them in the RTK math.

The MSM Dilemma: Which Version?

MSM numbers are logical. The prefix identifies the constellation (e.g., 107x for GPS, 112x for BeiDou). The last digit (1โ€“7) indicates the payload richness.

Scenario Recommend Why
UHF Radio / 9600 baud MSM4 Full carrier phase + CNR. No Doppler. Low bandwidth.
Standard 4G / WiFi MSM5 Adds Doppler for velocity and cycle-slip detection.
Max Precision / PPK MSM7 Full high-resolution data. High bandwidth.
Sub-meter IoT MSM1 Pseudorange only. Extreme bandwidth efficiency.
๐ŸŽฏ Engineer's Takeaway

MSM4 and MSM5 are the industry standard. While MSM7 is the "safe default" for mixed hardware fleets, do not run four-constellation MSM7 over a 9600 bps serial radio. It generates ~1,300 bytes/second on a link that only holds ~960 bytes/second. You will choke the serial buffer.

The Format Landscape: RTCM vs. The Rest

GNSS Format Relationship Diagram: RTCM, CMRx, SPARTN, and RINEX

You will likely encounter three alternatives to RTCM in the field:

  • CMRx (Trimble Proprietary): Created to save bandwidth, CMRx is ~30% smaller than RTCM MSM. The catch: It locks you into Trimble hardware. For cross-manufacturer interoperability, RTCM is the only choice.
  • SPARTN (Openly Specified): Built for mass-market PPP-RTK and low-bandwidth satellite broadcasts (e.g., u-blox PointPerfect). While RTCM (OSR) sends raw observations for local differencing, SPARTN (SSR) sends modeled error components (orbit, clock, atmosphere) for the rover to reconstruct.
  • RINEX (Offline Archival): RINEX and RTCM carry the exact same data. RTCM is compact binary for real-time streams; RINEX is text for offline post-processing.
๐Ÿ’ก Pro Tip: PPK Fallback Strategy

Log your raw RTCM stream to an SD card during fieldwork. If the real-time link drops, you can seamlessly convert that raw log to RINEX using open-source tools like RTKLIB's convbin to secure a reliable PPK fallback.

The Developer's Debugging Checklist

When your rover refuses to Fix, use RTKLIB's str2str to inspect the incoming stream.

  • GGA Fix Quality stuck at 1 You are missing MT1005/1006. The rover cannot find the base station.
  • GLONASS visible (GSV) but not used (GSA) You are missing MT1230. Switch to a mountpoint that includes it, or disable GLONASS to save processing cycles.
  • Correction Age climbing steadily The TCP connection dropped. Implement exponential backoff reconnection.
  • Fix is very slow / Correction Age jumps erratically You are bandwidth-choked. You are likely pushing full-constellation MSM7 over a slow radio link. Drop to MSM4, reduce constellations, or lower the update rate to 0.5 Hz.
  • Position offset by exactly ~2 meters Frame mismatch (e.g., ITRF2020 vs. NAD83). See Vol. 4 (GCS) to resolve.

Conclusion

RTCM is not a protocol you need to "learn" to write; it is a data stream you need to correctly route.

  1. Verify your receiver supports RTCM 3.x MSM.
  2. Select a mountpoint broadcasting MSM + MT1005/1006 + MT1230.
  3. Monitor your GGA Correction Age. If it climbs, the problem is your input chain.

For a complete field-by-field breakdown of the binary structure, the CRC algorithm, and the MSM mask matrix, see our companion deep-dive: AN-002: RTCM SC-104 v3.3 โ€” Frame Structure & Message Type Reference.

Frequently Asked Questions

What is the difference between RTCM and NMEA?

RTCM carries correction data into the receiver (binary, CRC-24Q protected). NMEA carries position results out (ASCII, XOR checksum). They flow in opposite directions in the RTK data chain โ€” RTCM is the input your receiver needs to compute a fix, NMEA is the output your application reads.

What RTCM version should I use?

RTCM 3.x with MSM messages (MSM4 or MSM5). This is the current industry standard, supported by all major correction services including Point One Polaris, Swift Skylark, HxGN SmartNet, and state CORS networks. Legacy messages (MT1001โ€“1012) cannot support Galileo or BeiDou.

What is MT1230 and why does it matter?

MT1230 carries GLONASS code-phase biases needed for cross-manufacturer interoperability. Because GLONASS uses FDMA, different receiver brands have different hardware biases. Without MT1230, your rover will see GLONASS satellites but silently refuse to include them in the RTK solution โ€” reducing satellite count, geometric strength, and fix reliability.

Can I mix RTCM messages from different base stations?

No. The rover forms a baseline to a single base station identified by the Station ID in the RTCM header. Mixing observations from Station A with coordinates from Station B โ€” different IDs, different clock references โ€” will produce an incorrect or completely failed solution. All messages in a correction stream must originate from the same reference station.

Zero Jiang - Founder of Kalmix

Zero Jiang

Founder, Kalmix

Dedicated to making high-precision GNSS positioning accessible and reliable for global developers. Passionate about autonomous systems, RTK technology, and robust hardware engineering.

Back to blog