# 03 - RouteTrack Pi — gpsd Installation & GPS Validation

#### **Date:** December 24th, 2025  
**Category:** Raspberry Pi / GPS / Linux Services  
**Backlink:** [RouteTrack Pi — Connecting GPS Hardware](https://docs.natenetworks.com/books/06-raspberry-pi-python-linux-tips/page/02-routetrack-pi-connecting-gps-hardware)

---

## Goal

This page covers:

- Installing `gpsd` and GPS tools (Global Positioning Satellite Daemon Tools)
- Confirming the USB GPS receiver is outputting raw NMEA sentences
- Creating a stable `/dev/gps0` device symlink via udev rules
- Running `gpsd` reliably as a **standalone systemd service**
- Validating that GPS data is readable through `gpspipe`
- I had to use a stand alone service because `gpsd` wouldn't work out of the box with my GPS Reciever.
- This is a workaround for that on this page.
- Some GPS units will work without bypassing TTP and using a seperate standalone systemd service.
- This page is specific to the GPS I used that needed a workaround.

#### **Device:** GlobalSat BU‑353N USB GPS Receiver

---

## Install gpsd + tools

Run:

```bash
sudo apt update
sudo apt install -y gpsd gpsd-clients
```

This installs:

- `gpsd` (daemon)
- `gpspipe`, `cgps` (client tools)

---

## Confirm the GPS receiver is detected

Plug in the USB GPS receiver, then verify the device appears:

```bash
ls -l /dev/ttyUSB*
```

example:

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/KxVqI2dyRiXtFMU9-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/KxVqI2dyRiXtFMU9-image.png)

Linux sees the GPS receiver.

---

## Validate raw NMEA output from the GPS

Before involving gpsd, verify the GPS is actually transmitting:

```bash
sudo stty -F /dev/ttyUSB0 4800 cs8 -cstopb -parenb -ixon -ixoff -crtscts -echo
sudo timeout 8 cat /dev/ttyUSB0 | head -n 20
```

Expected output should look like:

```text
$GPGGA,...
$GPGSA,...
$GPRMC,...

```

If you see NMEA sentences, the receiver is working at **4800 baud**.

---

## Create a stable GPS symlink `/dev/gps0` (udev rule)

The GPS device may sometimes appear as a different tty device, so we create a stable symlink called `/dev/gps0`.

### Create the udev rule

```bash
sudo nano /etc/udev/rules.d/10-gps-pl2303.rules
```

Paste:

```text
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="23a3", SYMLINK+="gps0"
```

These id's come from udev's info:

- `idVendor=067b`
- `idProduct=23a3`

Reload udev and trigger:

```bash
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo udevadm settle
```

Verify:

```bash
ls -l /dev/gps0
```

Expected:

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/bRye2nBFV92WFIka-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/bRye2nBFV92WFIka-image.png)

---

## Disable gpsd.socket and build a standalone gpsd service

Socket activation can cause inconsistent behavior during testing, so this project uses a dedicated standalone systemd service.

### Disable/mask the socket unit

```bash
sudo systemctl disable --now gpsd.socket
sudo systemctl mask gpsd.socket
```

---

## Create `gpsd-standalone.service`

Create the service:

```bash
sudo nano /etc/systemd/system/gpsd-standalone.service
```

This is the code for setting up the new service:

```ini
[Unit]
Description=GPSD Standalone (RouteTrack)
After=network.target
Wants=network.target

[Service]
Type=simple
User=gpsd
Group=dialout
ExecStart=/usr/sbin/gpsd -N -n -b -s 4800 -S 2947 /dev/gps0
Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target

```

### Important Notes

- `-s 4800` forces correct baud rate
- `-S 2947` binds gpsd to port 2947 (localhost)
- We intentionally **do not use** `-F /run/gpsd.sock` because it caused permission errors for the `gpsd` user under systemd.
- This service uses `/dev/gps0` so the device name stays consistent.

Enable + start:

```bash
sudo systemctl daemon-reload
sudo systemctl enable --now gpsd-standalone.service
```

Check status:

```bash
systemctl status gpsd-standalone.service --no-pager -l
```

**Notice it is enabled, active and running the line from the ExecStart:**

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/pJUOP9mxsosnWHDu-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/pJUOP9mxsosnWHDu-image.png)

---

## Confirm gpsd is listening on port 2947

Run:

```bash
ss -ltnp | grep 2947
```

It is listening on ipv4 and ipv6 ports:

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/3A4nRGQPpGNF0kIR-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/3A4nRGQPpGNF0kIR-image.png)

---

## Validate GPS data through gpsd (JSON output)

Run:

```bash
gpspipe -w -n 25
```

✅ Expected:

- `TPV` messages
- `SKY` messages
- `mode: 3` when a fix is established
- latitude/longitude values updating

Example indicators showing some GPS coordinates:

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/PA3lEqgczyiP5lUy-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/PA3lEqgczyiP5lUy-image.png)

---

Verifying Satellites and that everything is working:  
  
use:

```powershell
cgps
```

[![image.png](https://docs.natenetworks.com/uploads/images/gallery/2025-12/scaled-1680-/jFpCHUAAECJvmyEj-image.png)](https://docs.natenetworks.com/uploads/images/gallery/2025-12/jFpCHUAAECJvmyEj-image.png)

### Next Steps

The GPS subsystem is now stable, validated, and running as a dedicated systemd service. Upcoming work will build on this foundation:

- **Integrate gpsd with RouteTrack**
    
    
    - Consume GPS data via localhost port `2947`
    - Parse TPV updates for real-time position tracking
- **Add health checks**
    
    
    - Monitor gpsd service status
    - Alert if GPS fix drops below `mode: 3`
- **Visualization**
    
    
    - Map GPS coordinates to a live or logged route view
    - Export NMEA or JSON logs for later analysis