RTK Base, Rover & NTRIP Server
Complete RTK setup for centimeter-level positioning: a base station, a rover with an NTRIP client, and a variant that pushes corrections to a remote NTRIP caster instead of serving them locally.
Source: examples/cpp/rtk/, examples/c/rtk/, examples/python/rtk_base.py, examples/python/rtk_rover.py, examples/python/ntrip_server.py
NoteHAT Compatibility — RTK is available only on the L1/L5 RTK HAT (NEO-F9P).
NoteLooking for a ready-to-deploy service instead of example source code? See RTK Base Station — a productiongnsshat-rtk-baseCLI tool with TOML config, systemd service, and its own NTRIP caster/server, covering the same functionality as thertk-base/rtk-serverexamples below without writing any code.
config.rtk = RtkConfig {
.mode = ERtkMode::Base,
.base = BaseConfig {
.mode = BaseConfig::SurveyIn {
.minimumObservationTime_s = 60,
.requiredPositionAccuracy_m = 2.0
}
}
};
hat_base->start(config);
auto corrections = hat_base->rtk()->base()->getTinyCorrections();
from jimmypaputto import gnsshat
config = {
'measurement_rate_hz': 1,
'dynamic_model': gnsshat.DynamicModel.STATIONARY,
'timepulse_pin_config': {
'active': True,
'fixed_pulse': {'frequency': 1, 'pulse_width': 0.1},
'pulse_when_no_fix': None,
'polarity': gnsshat.TimepulsePolarity.RISING_EDGE
},
'geofencing': None,
'rtk': {
'mode': gnsshat.RtkMode.BASE,
'base': {
'base_mode': gnsshat.BaseMode.SURVEY_IN,
'survey_in': {
'minimum_observation_time_s': 120,
'required_position_accuracy_m': 50.0
}
}
}
}
hat = gnsshat.GnssHat()
hat.start(config)
rtk_base.py also includes ready-made Fixed Position (LLA and ECEF) config builders (create_fixed_position_lla_config() / create_fixed_position_ecef_config()) — swap which one main() calls to try them instead of Survey-In. --port/--mountpoint select the local NTRIP caster’s bind port and mountpoint.
The rover connects to an NTRIP caster with the library’s built-in NtripClient, then feeds every received RTCM3 frame into rtk_apply_corrections() in a background thread while the main loop keeps reading navigation:
config.rtk = RtkConfig { .mode = ERtkMode::Rover };
hat_rover->start(config);
hat_rover->rtk()->rover()->applyCorrections(corrections);
from jimmypaputto import gnsshat
config = {
'measurement_rate_hz': 1,
'dynamic_model': gnsshat.DynamicModel.STATIONARY,
'timepulse_pin_config': {
'active': True,
'fixed_pulse': {'frequency': 1, 'pulse_width': 0.1},
'pulse_when_no_fix': None,
'polarity': gnsshat.TimepulsePolarity.RISING_EDGE
},
'geofencing': None,
'rtk': {'mode': gnsshat.RtkMode.ROVER}
}
hat = gnsshat.GnssHat()
hat.start(config)
ntrip = gnsshat.NtripClient(host, port, mountpoint, username, password)
ntrip.connect()
# Background thread: forward every received frame to the receiver
while running:
frames = ntrip.receive()
if frames:
hat.rtk_apply_corrections(frames)
# Main thread: read fix quality
nav = hat.wait_and_get_fresh_navigation()
# nav.pvt.fix_quality == FixQuality.FIXED_RTK → ~1-2 cm accuracy
Instead of accepting incoming rover connections, the base can push its corrections outward to a remote NTRIP caster using NtripServer — useful when the base station is behind NAT/a firewall and can’t accept inbound connections:
NtripServer server(host, port, mountpoint, username, password);
server.setAutoReconnect(true, 1000, 30000);
server.connect();
auto corrections = hat->rtk()->base()->getFullCorrections();
if (!corrections.empty())
server.feed(corrections);
server = gnsshat.NtripServer(
host=caster_host, port=caster_port, mountpoint=mountpoint,
username=username, password=password)
server.set_auto_reconnect(True, 1000, 30000)
server.connect()
while running:
corrections = hat.rtk_get_full_corrections()
if corrections:
server.feed(corrections)
Both RtkServer (C++) and ntrip_server.py (Python) wait for a TimeOnlyFix before pushing corrections and use exponential-backoff auto-reconnect if the connection to the remote caster drops.
# rtk-base and rtk-rover are symlinked into examples/bin/
sudo examples/bin/rtk-base
sudo examples/bin/rtk-rover
# rtk-server is not symlinked — run it from the build tree
sudo build/examples/cpp/rtk/rtk-server <caster_host> <port> <mountpoint> [username] [password]
sudo build/examples/c/rtk/rtk-base
sudo build/examples/c/rtk/rtk-rover
The C example does not include an NTRIP-server (push-to-remote-caster) variant — use the C++ or Python one.
# Base station (runs a local caster the rover connects to directly)
python3 examples/python/rtk_base.py
# Rover — connects to a caster and applies corrections
python3 examples/python/rtk_rover.py --host <caster-host> --port 2101 --mountpoint <mount>
# Push corrections from the base to a remote caster
python3 examples/python/ntrip_server.py --caster-host <host> --caster-port 2101 \
--mountpoint <mount> --password <pwd>
- GPS 2D/3D — standard fix (~2–5 m)
- Float RTK — corrections applied, ambiguities resolving (~0.2–1 m)
- Fixed RTK — full centimeter accuracy (~1–2 cm)
See RTK Feature and RTK Config.