Setting up GNSS / RTK on Linux

This guide will walk you through setting up your GNSS / RTK module on Linux, in order to use it with the ZED SDK’s Global Localization module.

While the guide focuses on the ublox ZED F9P GNSS module, the instructions provided should also be applicable to other GNSS modules. By leveraging the power of GNSS / RTK technology, you will be able to enhance the accuracy and reliability of your positioning data, opening up new possibilities for your ZED-based applications.

Installation #

Using gpsd is the simplest way to retrieve the GNSS data on Linux.

To access GNSS data in a program, we are going to use gpsd, a service daemon that retrieves and parses GNSS data from multiple formats and provides multiple APIs to access this data easily.

gpsd is used to connect applications with the GPS receiver hardware. It manages USB GPS devices so the applications don’t have to. In Linux, if you set up the gpsd properly with GPS receivers hardware, most GNSS location-aware applications can get the GNSS data by calling gpsd. Furthermore, gpsd shares the GPS receiver to all applications running on this Linux machine.

It is required to install gpsd from source to get the most recent stable version:

# Install the dependencies
sudo apt update && sudo apt install scons libgtk-3-dev

# Compile the latest gpsd version from the source
git clone https://gitlab.com/gpsd/gpsd.git
cd gpsd && git checkout 8910c2b60759490ed98970dcdab8323b957edf48
sudo ./gpsinit vcan
scons && scons check && sudo scons udev-install

# Add additional python path to .bashrc to access the tools
echo 'export PYTHONPATH="$PYTHONPATH:/usr/local/lib/python3/dist-packages"' >> ~/.bashrc

In order to run without root privileges, it is recommended to add your user to the dialout and tty groups:

sudo adduser $USER dialout
sudo adduser $USER tty

Log out of the session or reboot the device for these changes to take effect.

To verify that the GNSS module is properly detected, you can use the following command:

ls /dev/tty*

You should see a file named /dev/ttyACM0 or dev/ttyUSB0 containing the GNSS raw data. The streamed data should look as such:

# Note: the cat command should be able to work without sudo
$ cat /dev/ttyACM0

$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,1*33
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,2*30
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,3*31
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,4*36
$GPGSV,1,1,00,0*65
$GLGSV,1,1,00,0*79
$GAGSV,1,1,00,0*74
$GBGSV,2,1,05,10,,,29,11,,,28,12,,,28,13,,,29,3*72
$GBGSV,2,2,05,14,,,29,3*7F
$GNGLL,,,,,082018.00,V,N*57
$GNTXT,01,01,01,NMEA unknown msg*46
$GNTXT,01,01,01,NMEA unknown msg*46
$GNRMC,082019.00,V,,,,,,,230623,,,N,V*1D
$GNVTG,,,,,,,,,N*2E
$GNGGA,082019.00,,,,,0,00,99.99,,,,,,*7A
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,1*33
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,2*30
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,3*31
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99,4*36

Usage of GPSD #

By default, gpsd uses a systemctl service to run, however as the service has reliability issues for USB GNSS modules, we recommend running the daemon by hand, and create a cron job to start the service at boot.

To run the daemon, use the following command:

gpsd -nG -s 115200 /dev/ttyACM0

The following cron job can be added with crontab -e :

@reboot sleep 10 && /usr/local/sbin/gpsd -nG -s 115200 /dev/ttyACM0

📌 Note: Change ttyACM0 with the communication port of your GNSS sensor

You can test that gpsd is working properly with the xgps tool installed with gpsd:

# GNSS and satellite data in graphical interface
xgps

Enabling RTK on your GNSS module #

Enabling RTK (Real-Time Kinematic) functionality brings significant advantages over traditional GNSS positioning.

RTK uses a network of reference stations and a rover receiver to provide highly accurate and precise positioning in real-time. Unlike standard GNSS, which typically offers accuracy within a few meters, RTK can achieve centimeter-level accuracy. By leveraging carrier-phase measurements and advanced algorithms, RTK overcomes common limitations of GNSS, such as atmospheric disturbances and signal multipath.

Using NTRIP #

gpsd can act as an NTRIP client in order to retrieve RTK corrections from an RTK base station.

We will go through how to set up the NTRIP connection in order to get RTK centimeter-level accuracy.

For this you will need:

  • url: the NTRIP URL address of the base station
  • port: the NTRIP port of the base station
  • mountpoint: the mountpoint you choose to use (Note: for good performance, the base station is recommended to be less than 25km away from the rover)
  • username: the username used for the NTRIP connection (optional)
  • password: the password used for the NTRIP connection (optional)

You can now run gpsd as an NTRIP client with:

pkill gpsd # Kill gpsd if it is already running
gpsd -nG ntrip://<username>:<password>@<url>:<port>/<mountpoint> -s 115200 /dev/ttyACM0

📌 Note: Change ttyACM0 with the communication port of your GNSS sensor

You can now run xgps and wait for the GNSS to get an RTK fix. (The ECEF pAcc gives the horizontal accuracy; with an RTK FIX status this value should be of about a few centimeters)

Set RTK configuration at boot #

gpsd runs as a cronjob set to run at the system’s startup. Update the cron job with the following command, so that gpsd will connect to the base station at every boot:

crontab -e

And replace the gpsd line already present with the following:

@reboot sleep 10 && /usr/local/sbin/gpsd -nG ntrip://<username>:<password>@<url>:<port>/<mountpoint> -s 115200 /dev/ttyACM0

📌 Note: Change ttyACM0 with the communication port of your GNSS sensor

Using GNSS in your applications #

With the successful setup and configuration of GNSS, it’s time to explore how to leverage GNSS data in your ZED SDK application.

To help you get started, we provide Geotracking samples on our GitHub repository. These samples allow you to view live fused GNSS global data, record GNSS sequences, and even replay them for testing purposes.

Python #

To access GNSS data in Python, you can use the gpsdclient library. This library provides a Python interface to the gpsd daemon, allowing you to easily retrieve GNSS data in your Python scripts. With gpsdclient, you can access a range of GNSS data, including latitude, longitude, altitude, speed, and more. This makes it a powerful tool for building GNSS-enabled applications in Python.

You can install gpsdclient with:

pip install gpsdclient

Here is an example of a simple script using gpsdclient:

from gpsdclient import GPSDClient

# get your data as json strings:
with GPSDClient(host="127.0.0.1") as client:
    for result in client.json_stream():
        print(result)

# or as python dicts (optionally convert time information to `datetime` objects)
with GPSDClient() as client:
    for result in client.dict_stream(convert_datetime=True, filter=["TPV"]):
        print("Latitude: %s" % result.get("lat", "n/a"))
        print("Longitude: %s" % result.get("lon", "n/a"))

# you can optionally filter by report class
with GPSDClient() as client:
    for result in client.dict_stream(filter=["TPV", "SKY"]):
        print(result)

You can find a full code example of how to use the library in our Geotracking samples on GitHub.

C++ #

To access GNSS data in C++, you can use the libgpsmm library.

You can install libgpsmm with:

sudo apt install libgps-dev

Here is an example of a simple script using libgpsmm:

#include <libgpsmm.h>
#include <iostream>

int main() {
    gpsmm gps_data("localhost", DEFAULT_GPSD_PORT);

    if (gps_data.stream(WATCH_ENABLE | WATCH_JSON) == nullptr) {
        std::cerr << "Failed to open GPS connection." << std::endl;
        return 1;
    }

    while (true) {
        if (gps_data.waiting(500)) {
            if (gps_data.read() == nullptr) {
                std::cerr << "Error while reading GPS data." << std::endl;
            } else {
                std::cout << "Latitude: " << gps_data.fix->latitude << ", Longitude: " << gps_data.fix->longitude << std::endl;
            }
        }
    }

    gps_data.stream(WATCH_DISABLE);
    gps_data.close();

    return 0;
}

You can find a full code example of how to use the library in our Global Localization samples on GitHub.