> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.stereolabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.stereolabs.com/_mcp/server.

# 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](https://gpsd.gitlab.io/gpsd/index.html) is the simplest way to retrieve GNSS data on Linux. `gpsd` is 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 recommended to install `gpsd` from source, at the tested commit used below:

```bash
# 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:

```bash
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:

```bash
ls /dev/tty*
```

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

```bash
# 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` runs as a systemd service. However, as this service has reliability issues with USB GNSS modules, we recommend running the daemon manually and creating a *cron job* to start it at boot.

To run the daemon, use the following command:

```bash
gpsd -nG -s 115200 /dev/ttyACM0
```

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

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

> **Note**
>
> Replace `ttyACM0` with the communication port of your GNSS sensor

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

```bash
# GNSS and satellite data in graphical interface
xgps
```

![](/_fern-files/stereolabs.docs.buildwithfern.com/b5ff2e3425587e96b0bad2d0cc59514f2d3d3e9dfd8a9072f3c887fddaf02583/docs/products/embedded/zed-box-orin/images/xgps.webp)

## 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:

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

> **Note**
>
> Replace `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 estimated position accuracy; with an RTK FIX status this value should be of about *a few centimeters*)

### Set RTK configuration at boot

`gpsd` runs as a cron job set to run at the system's startup. Update the cron job with the following command so that `gpsd` connects to the base station at every boot:

```bash
crontab -e
```

And replace the gpsd line already present with the following:

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

> **Note**
>
> Replace `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 [Global Localization samples on our GitHub](https://github.com/stereolabs/zed-sdk/tree/master/global%20localization/live) 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](https://github.com/tfeldmann/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:

```bash
pip install gpsdclient
```

Here is an example of a simple script using `gpsdclient`:

**`Python`**

```python Python
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 [Global Localization samples on GitHub](https://github.com/stereolabs/zed-sdk/tree/master/global%20localization/live).

### C++

To access GNSS data in C++, you can use the [libgpsmm](https://gpsd.io/libgpsmm.html) library.

You can install `libgpsmm` with:

```bash
sudo apt install libgps-dev
```

Here is an example of a simple script using `libgpsmm`:

**`C++`**

```cpp C++
#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)) {
            struct gps_data_t* new_data = gps_data.read();
            if (new_data == nullptr) {
                std::cerr << "Error while reading GPS data." << std::endl;
            } else {
                std::cout << "Latitude: " << new_data->fix.latitude << ", Longitude: " << new_data->fix.longitude << std::endl;
            }
        }
    }

    gps_data.stream(WATCH_DISABLE);

    return 0;
}
```

You can find a full code example of how to use the library in our [Global Localization samples on GitHub](https://github.com/stereolabs/zed-sdk/tree/master/global%20localization/live).