Operator manual

Running the GS10 RTK base station

For whoever runs the base: how the Leica GS10, the Raspberry Pi guta.local and the caster at ntrip.pavlokostiuk.cloud fit together. Flying a drone? Use the pilot guide instead.

1Status

PieceStateNotes
GS10 web UI over BluetoothworkingThrough the Pi bridge, opened on the Mac at http://localhost:8253
NTRIP caster /GS10liveNTRIP v1 and v2 (Aircast QGC, Mission Planner, RTKLIB). Connection from Aircast QGC verified on 2026-10-10
Live dashboardliveCaster, correction stream and GS10 status (battery, satellites, fix). The GS10 part needs gs10status.py running on the Pi
Pi → caster relayreadyConnects to both the GS10 and the caster; nothing to send yet
RTCM 3 output on the GS10blockedBoth RTK base outputs use Leica’s own format. Changing it needs a Leica controller (step 4)
Drone GPScheckMust be RTK-capable (u-blox F9P, Unicore UM980/UM982 or similar). Pilots connect with the pilot guide

2The receiver

Model
Leica Viva GS10, serial 1532392, firmware 5.50 (1418)
Bluetooth
Name GS1532392, address 00:13:43:02:E9:EF, PIN 0000, Class 2 (about 10 m range)
Web UI
192.168.253.2, reachable only over a Bluetooth network link (PAN)
Serial over BT
RFCOMM channel 11. Silent until an output is assigned to it
Licences
RTK base, DGPS/RTCM, NMEA output, GPS L2, GLONASS, 20 Hz. No Galileo or BeiDou. No OWI command interface
Mode
Base, antenna AS10 Pole
Stored base position
41°43′20.409″ N, 44°52′37.545″ E, ellipsoidal height 576.661 m (WGS84)
Power
Two Li-ion batteries under the lid (A was at 0%, B at 100%), or 12 V through the Lemo PWR port

3Open the GS10 web UI

macOS 27 can’t join a Bluetooth network link, so the Pi does it. A small bridge script on the Pi talks to the GS10 over Bluetooth and serves its web UI on the Pi. An SSH tunnel brings it to the Mac. The script needs no sudo and no pairing.

  1. Power the GS10 on, check that its Bluetooth LED is lit, and keep the Pi within about 10 m.
  2. Start the bridge on the Pi:
    ssh pi@guta.local 'curl -fsSO https://rtk.pavlokostiuk.cloud/gs10pan.py && nohup python3 gs10pan.py > gs10pan.log 2>&1 < /dev/null &'
    ssh pi@guta.local 'cat gs10pan.log'
    The log should end with ready: 127.0.0.1:8253 -> 192.168.253.2:80.
  3. Open the tunnel on the Mac:
    ssh -fN -L 8253:127.0.0.1:8253 pi@guta.local
  4. Browse to http://localhost:8253. http://192.168.253.2 won’t load from the Mac.

To stop the bridge and the tunnel:

ssh pi@guta.local 'pkill -f "^python3 gs10pan.py"'
pkill -f 'ssh -fN -L 8253'

Browsing only. The bridge is a minimal network link built for viewing pages and changing settings. Don’t upload firmware through it.

What the web UI can change

Base or rover mode, antenna type and height, base position, satellite systems and cut-off angle, raw data logging to the SD card, licence keys and firmware. It has no setting for the RTK output format or port.

4One-time setup: switch the base output to RTCM 3

Needs a Leica CS10 or CS15 controller running SmartWorx Viva. Borrow one, buy a used one, or ask a Leica dealer. The GS10 keeps the settings afterwards, so it’s needed only once.

  1. Connect the controller to the GS10 (Instrument → Connections → connect to the GS sensor).
  2. Open the RTK base 1 connection: Instrument → Instrument connections → All other connections → RTK Base 1 → Edit. Menu names can differ slightly between Viva versions.
  3. Set Connect using to the GS Bluetooth port if the list offers it. Otherwise pick a GS serial port, and the Pi will need a Lemo-to-serial cable.
  4. Set RTK data format to RTCM v3 (MSM if offered), GPS + GLONASS, 1 s rate. It must include the base position message (1005 or 1006).
  5. Confirm the base coordinates and the antenna height, then start the base and disconnect the controller.

Check on the web UI: Current Status → RTK base should show RTCM instead of Leica.

5Stream corrections to the caster

Once the GS10 sends RTCM 3 on its Bluetooth port, gs10ntrip.py on the Pi forwards it to the caster. It reconnects on its own if either side drops. The source password is in Vaultwarden under NTRIP caster — ntrip.pavlokostiuk.cloud.

ssh pi@guta.local 'curl -fsSO https://rtk.pavlokostiuk.cloud/gs10ntrip.py && NTRIP_SOURCE_PASS=<source password> nohup python3 gs10ntrip.py > gs10ntrip.log 2>&1 < /dev/null &'
ssh pi@guta.local 'tail -f gs10ntrip.log'

Data is flowing when the log shows … bytes sent. Stop it with ssh pi@guta.local 'pkill -f "^python3 gs10ntrip.py"'.

Both scripts run until the Pi reboots. To keep the relay running across reboots, install it as a systemd service (needs sudo once). Do it through the Pi’s deploy scripts rather than by hand.

systemd unit
[Unit]
Description=GS10 RTCM to NTRIP caster
After=bluetooth.service network-online.target

[Service]
User=pi
Environment=NTRIP_SOURCE_PASS=<source password>
ExecStart=/usr/bin/python3 /home/pi/gs10ntrip.py
Restart=always

[Install]
WantedBy=multi-user.target

Feed the dashboard

gs10status.py reads the GS10’s status pages through the bridge every 20 s and sends them to the dashboard. It needs the bridge from step 3 running, and the dashboard token, which is in the same Vaultwarden item.

ssh pi@guta.local 'curl -fsSO https://rtk.pavlokostiuk.cloud/gs10status.py && DASH_TOKEN=<dashboard token> nohup python3 gs10status.py > gs10status.log 2>&1 < /dev/null &'

The bridge reconnects to the GS10 by itself, for example after the receiver restarts or goes out of range.

6Caster administration

Endpoint
ntrip.pavlokostiuk.cloud:2101, NTRIP v1 and v2
Mountpoint
/GS10, clients log in with HTTP Basic auth. The base logs in with the source password (NTRIP v1 SOURCE)
Hosting
Dokploy project ntrip → compose caster, service web. One Python process (/home/admin/ntrip/dash.py) runs the caster on 2101 and the manual, dashboard and API on this site
Config
Environment in Dokploy: NTRIP_SOURCE_PASS, NTRIP_USERS (user:pass,user2:pass2), DASH_TOKEN. The sourcetable line is NTRIP_STR in the compose file. Change them, then redeploy
DNS
Cloudflare A record, DNS-only. Cloudflare can’t proxy port 2101
Credentials
Vaultwarden → NTRIP caster — ntrip.pavlokostiuk.cloud

Give a pilot a login

  1. In Dokploy → ntrip → caster → Environment, add the pilot to NTRIP_USERS, comma-separated: drone:pass1,anna:pass2. One login per pilot lets you revoke one without breaking the others.
  2. Redeploy. Connected drones reconnect by themselves within a few seconds.
  3. Send the pilot the pilot guide and their username and password.

Check the sourcetable from anywhere:

printf 'GET / HTTP/1.0\r\nUser-Agent: NTRIP test\r\n\r\n' | nc -w 5 ntrip.pavlokostiuk.cloud 2101

7Without a Leica controller

OptionCostHow
GEOCORS, Georgia’s national correction serviceregistrationSign up at geocors.napr.gov.ge, then put their caster details into RTK/GPS Inject. No base or Pi needed
Own base, F9P or UM980$150–250Plug it into the Pi and stream with str2str -in serial://ttyACM0:115200 -out ntrips://:<source password>@ntrip.pavlokostiuk.cloud:2101/GS10 (from the Debian rtklib package)
Public castersfreeNot usable here. The nearest base on rtk2go, Centipede or CRTK is 688 km away; RTK needs one within about 30 km

8Troubleshooting

SymptomFix
Pi can’t see the GS10; bluetoothctl show says off-blockedThe radio is blocked: echo 0 | sudo tee /sys/class/rfkill/rfkill0/soft
Bridge log says BNEP channel closedThe GS10 turned off or went out of range. Start the bridge again
Browser times out on 192.168.253.2Use http://localhost:8253 with the tunnel open
Tunnel says Address already in useIt’s already running: pgrep -fl 'ssh -fN -L 8253'
Relay log says ERROR - Bad PasswordWrong source password. Check Vaultwarden
Mission Planner gets 401 Unauthorized, or QGC says Authentication failed (401)Wrong client user or password
QGC or Mission Planner connects, then drops with “not found”No base is pushing to /GS10. The dashboard shows “No base connected”
Relay connected but no bytes sentThe GS10 isn’t sending RTCM on Bluetooth yet (step 4), or it has no satellite fix
Stuck at RTK FloatCheck sky view at both ends, the baseline distance, GPS + GLONASS on the rover, and the base coordinates
Mac doesn’t list the GS10 in Bluetooth settingsNormal: it announces itself as a computer. blueutil --inquiry 20 finds it