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

AUTHOR: Zero Jiang | TITLE: Founder, Kalmix | READ: 8 min

TL;DR

  • RTCM is the binary correction-data format that lets an RTK rover compare its own satellite observations against a reference station.
  • For modern multi-constellation RTK, use RTCM 3.x with MSM messages rather than legacy MT1001โ€“1012 streams.
  • A usable RTK correction stream normally needs observation messages, base station coordinates such as MT1005/1006, and MT1230 when GLONASS is used.
  • MSM4 or MSM5 is usually the practical default; MSM7 can overload low-bandwidth radio links.
  • If the rover refuses to reach RTK Fixed, debug the correction stream before changing the NMEA parser.

RTCM is the correction-data layer behind an RTK fix: NTRIP often transports it, NMEA reports the result, but RTCM is the binary stream that gives the rover the reference observations needed for centimeter-level positioning.

If you've built an RTK system, you likely already speak NMEA โ€” the 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 satellite observations from a reference station, encoded into a compact binary format. Your receiver consumes this data to move from meter-level standalone positioning toward centimeter-level RTK. If NMEA is the final answer your receiver gives you, RTCM is the input it needs to make that answer precise.

In this volume of the Kalmix GNSS Handbook, we crack open the RTCM binary stream. We will 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 reach Fixed.

Need-to-Know Terms

  • MSM (Multiple Signal Messages): the modern RTCM 3.2+ message family supporting multiple GNSS constellations and signals.
  • OSR (Observation Space Representation): a correction model that sends base-station observations for the rover to difference locally.
  • SSR (State Space Representation): a correction model that sends modeled orbit, clock, and atmosphere errors instead of local base observations.
  • Rover: the moving GNSS receiver that consumes RTCM corrections and outputs position. For a field-ready rover example, see Kalmix SCOUT PRO.

Where RTCM Fits in the RTK Data Chain

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

  • RTCM flows in: carrying correction data from the reference station to the rover.
  • NMEA flows out: carrying the computed position, status, and fix quality from the receiver to your host controller.
RTCM data flow in an RTK system, showing base station observations carried through NTRIP to a rover, with NMEA position output to the host

NTRIP is 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, stale, or dropping packets, your Fix Quality will never reach 4 = RTK Fixed. If you cannot Fix, start debugging upstream.

RTCM vs. NMEA: Inputs and Outputs

If you read our NMEA 0183 guide, you already know the receiver-output side of the positioning stack. RTCM is the opposite side: compact, binary, and intended for machines rather than humans.

Property RTCM 3.x NMEA 0183
Direction Input: corrections into receiver Output: position and status from receiver
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> ending
Typical role in RTK Feeds the ambiguity engine Reports fix status, coordinates, speed, and time

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

A Brief History of RTCM 3

Modern RTK work should be built around RTCM 3.x. The older versions explain the standard's origin, but they are not where most current multi-constellation RTK systems should start.

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, MSM introduced 2013
RTCM V3.3 10403.3 Differential GNSS Services โ€” Version 3, including amendments 2016
RTCM V4.0 10403.4 Differential GNSS Services โ€” Version 4 2023

Versions 1 and 2 were built in the 1980s and 1990s for maritime DGPS. They used rigid, 30-bit words that were not well suited for the higher data volumes of modern RTK. In most current rover integrations, you can treat them as legacy. For the official standards body behind the protocol, see the Radio Technical Commission for Maritime Services.

The modern era began with Version 3 in 2004, featuring variable-length frames and robust 24-bit CRCs. The structural shift came with V3.2 in 2013, which introduced Multiple Signal Messages, or MSM.

Before MSM, legacy messages such as MT1001โ€“1012 were hard-coded mainly for GPS and GLONASS. The standard had no clean multi-constellation structure for Galileo or BeiDou. MSM fixed this architectural dead-end with a constellation-agnostic matrix design.

In practice, using legacy observation messages on a modern receiver caps the receiver's ability to use today's multi-constellation sky.

For the field-level frame and message reference, use the companion document AN-002: RTCM SC-104 v3.3 Frame Structure & Message Type Reference.

Inside the Packet: Frame Structure

Every RTCM 3.x frame follows the 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()
equals one complete RTCM frame. Always buffer.
"""

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):
    frames = []

    while True:
        # 1. Find preamble
        try:
            start = buf.index(0xD3)
        except ValueError:
            buf.clear()
            return frames

        # Drop noise before preamble
        if start > 0:
            del buf[:start]

        # Need at least 3 header bytes
        if len(buf) < 3:
            return frames

        # 2. Validate reserved bits and parse payload length
        if buf[1] & 0xFC:
            del buf[0]
            continue

        length = ((buf[1] & 0x03) << 8) | buf[2]
        frame_len = 3 + length + 3

        if len(buf) < frame_len:
            return frames

        frame = bytes(buf[:frame_len])

        # 3. Verify CRC-24Q
        received_crc = int.from_bytes(frame[-3:], "big")
        computed_crc = crc24q(frame[:-3])

        if received_crc == computed_crc:
            frames.append(frame)
            del buf[:frame_len]
        else:
            # False sync. Advance one byte and rescan.
            del buf[0]

Implementation Note

The most common RTCM parser bug is assuming transport boundaries match protocol boundaries. They do not. A single TCP packet may contain half a frame, one frame, or several frames. Buffer first, parse second.

The Message Groups and the Two Silent Killers

RTCM 3.x defines many message types, but an RTK rover only needs a practical subset for most field work.

Group Typical MTs Purpose RTK Required?
Observations, MSM 1071โ€“1127 Multi-constellation, multi-signal observation data Yes
Station Coordinates 1005 / 1006 Base station antenna reference point in ECEF coordinates Mandatory
GLONASS Bias 1230 FDMA inter-frequency bias information Required if GLONASS is used
Observations, Legacy 1001โ€“1012 GPS / GLONASS-only observation messages Legacy only
Antenna / Ephemeris 1033 / 1019+ Receiver info and broadcast ephemeris Optional, depending on workflow

While observation messages are obvious, developers often lose time on two missing message types that fail less visibly:

  • 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 means no baseline, and no baseline means no Fix.
  • MT1230, GLONASS Interoperability: GLONASS uses FDMA, which creates hardware biases between different receiver brands. MT1230 carries the code-phase bias compensation. Without it, your rover may see GLONASS satellites but refuse to use them in the RTK solution.

Silent Failure Pattern

A rover can show plenty of satellites in GSV while still refusing to use some of them in the actual fix solution. That is why you should compare NMEA GSV, GSA, GGA status, correction age, and the incoming RTCM message list rather than trusting satellite count alone.

The MSM Dilemma: Which Version?

MSM, or Multiple Signal Messages, is the RTCM 3.2+ observation-message family introduced in 2013 to replace legacy single-constellation messages such as MT1001โ€“1012. Each MSM message ID encodes both the constellation family and the payload richness level.

MSM numbers are logical. The prefix identifies the constellation, such as 107x for GPS and 112x for BeiDou. The last digit, from 1 to 7, indicates payload richness.

Scenario Recommended MSM Why
UHF radio / 9600 baud MSM4 Full carrier phase and CNR without Doppler; lower bandwidth.
Standard 4G / Wi-Fi correction link MSM5 Adds Doppler for velocity and cycle-slip detection.
Maximum precision / PPK workflow MSM7 Full high-resolution data; higher bandwidth requirement.
Sub-meter IoT or extreme bandwidth constraints MSM1 Pseudorange only; minimal payload, not ideal for centimeter RTK.

Engineerโ€™s Takeaway

MSM4 and MSM5 are the practical industry defaults. MSM7 is not automatically better if your link cannot carry it. Do not run four-constellation MSM7 over a 9600 bps serial radio; it can choke the serial buffer and create exactly the correction gaps you are trying to avoid.

The Format Landscape: RTCM vs. The Rest

RTCM is the interoperability default for RTK correction streams, but you will encounter other correction or logging formats in the field.

Comparison of correction and logging data formats including RTCM, CMRx, SPARTN, and RINEX

Beyond RTCM, the GNSS correction and logging format landscape is generally categorized into proprietary bandwidth-saving protocols like CMRx, state-space representation (SSR) models like SPARTN for mass-market PPP-RTK, and raw receiver-independent logging formats like RINEX:

  • CMRx, Trimble proprietary: created to save bandwidth. It can be smaller than RTCM MSM, but it ties the workflow to Trimble hardware. For cross-manufacturer interoperability, RTCM remains the safer choice.
  • SPARTN, openly specified: built for mass-market PPP-RTK and low-bandwidth satellite or IP broadcasts. While RTCM OSR sends base-station observations for local differencing, SPARTN SSR sends modeled error components such as orbit, clock, and atmosphere corrections.
  • RINEX: a receiver-independent logging format used for post-processing. It is not normally the real-time correction stream, but it matters when you need PPK fallback or forensic analysis.

Pro Tip: PPK Fallback Strategy

Log your raw correction stream during fieldwork. If the real-time link drops, you may still be able to recover a high-quality result with a PPK workflow. Open-source tools such as RTKLIB are often used to inspect, convert, and post-process GNSS logs.

The Developerโ€™s Debugging Checklist

When your rover โ€” whether it is a custom board or a field-ready receiver like the Kalmix SCOUT PRO โ€” refuses to reach Fixed, inspect the incoming stream before assuming the GNSS hardware or parser is wrong. Tools such as RTKLIB's str2str can help verify what the rover is actually receiving.

Common RTK debugging patterns share a single principle: when the rover refuses to Fix, the failure is usually in what the rover is receiving โ€” not in what it is computing. The five most frequent symptoms below all point to specific upstream gaps.

  • GGA Fix Quality stuck at 1 You may be missing MT1005/1006. The rover cannot identify the base station position and therefore cannot compute a baseline.
  • GLONASS visible in GSV but not used in GSA You may be missing MT1230. Switch to a mountpoint that includes it, or disable GLONASS to reduce processing load if your correction service does not support it.
  • Correction Age climbing steadily The TCP, radio, or cellular correction link is stale or dropped. Implement reconnection logic and monitor correction age in your host application.
  • Fix is very slow, or Correction Age jumps erratically You may be bandwidth-choked. Full-constellation MSM7 over a slow radio link can overflow the link. Drop to MSM4, reduce constellations, or lower the correction update rate.
  • Position offset is stable but wrong by meters This is likely not an RTCM decoding issue. Check coordinate frame and datum alignment. See Beyond WGS84 for why a technically precise fix can still land in the wrong map frame.

Conclusion

RTCM is not a protocol most developers need to hand-write. It is a correction stream your system must route, validate, and monitor correctly.

Verify that your receiver supports RTCM 3.x MSM. Select a mountpoint broadcasting MSM observations, MT1005/1006 station coordinates, and MT1230 if GLONASS is part of your solution. Monitor NMEA GGA Fix Quality and Correction Age. If Correction Age climbs, the problem is upstream in the input chain, even if the receiver keeps outputting position sentences.

For a complete field-by-field breakdown of binary frame structure, CRC-24Q, and MSM mask handling, read the companion reference: AN-002: RTCM SC-104 v3.3 Frame Structure & Message Type Reference.

Key Takeaway

For RTK debugging, treat RTCM as the first thing to verify, not the last thing to suspect. A rover cannot produce a reliable RTK Fixed solution without valid observation messages, base station coordinates, compatible constellation data, and a fresh correction stream.

Frequently Asked Questions

What is the difference between RTCM and NMEA in an RTK system?

RTCM and NMEA sit on opposite sides of the receiver workflow. RTCM is a compact binary correction-data input used by the rover to compute an RTK solution. NMEA is a human-readable ASCII output format used by the receiver to report coordinates, time, velocity, and fix status to the host system.

Which RTCM messages are required for RTK Fixed?

A practical RTK correction stream usually needs MSM observation messages, base station coordinates such as MT1005 or MT1006, and MT1230 when GLONASS is used. Without station coordinates, the rover cannot compute a baseline; without compatible observation messages, it cannot resolve carrier-phase ambiguities reliably.

Should I use legacy RTCM, MSM4, MSM5, or MSM7?

Use RTCM 3.x with Multiple Signal Messages (MSM) for modern RTK. For most real-time applications, MSM4 or MSM5 is the practical default. MSM4 reduces bandwidth, while MSM5 adds Doppler for velocity and cycle-slip detection. MSM7 carries higher-resolution data, but it consumes more bandwidth and can overload constrained radio links. Avoid legacy MT1001โ€“1012 messages for modern multi-constellation receivers.

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.

How much bandwidth or baud rate is required for RTCM 3.x MSM streams?

It depends on the MSM version, constellation count, update rate, and transport overhead. A minimal GPS/GLONASS MSM4 stream may work over a 9600 bps serial radio, while a full four-constellation MSM5 or MSM7 stream usually needs a higher baud rate such as 38400 or 115200, or a reliable 4G/Wi-Fi connection, to avoid buffer overflow and correction-age jumps.

Why is my rover stuck in Float even though RTCM is streaming?

Check whether the stream includes MSM observations, MT1005/1006 station coordinates, fresh correction age, and MT1230 if GLONASS is enabled. Also verify that the correction stream is not too large for the link, because buffer overflow can make corrections arrive late even when the stream appears connected.

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.

Need to evaluate RTCM streams or RTK status in your own product?
Back to blog