beta-tester / RPi-GPS-PPS-StratumOne

setup a Raspberry Pi as a Stratum One time server (GPS with PPS)
GNU General Public License v3.0
129 stars 27 forks source link
chrony gps gpsd ntp ntp-server pps raspberry-pi raspberrypi raspbian rpi stratum

RPi-GPS-PPS-StratumOne

setup a Raspberry Pi as an Stratum One NTP server.
it is a private project i have made for myself.
i did not keep an eye on network security.

the script will override some existing configurations
(a backup of the changed configuration files will be stored to backup.tar.xz)

USE IT AT YOUR OWN RISK

Please give me a 'Star', if you find that project useful.

overview schematic:

                     ╔═══╗       ╔══════╗         ╔══════╗  GPS-Antenna
                   ──╢ s ║       ║RPi as╟RX───────╢GPS-  ║    ═╪═
                     ║ w ║       ║NTP-  ╟TX───────╢module║     │
                     ║ i ║       ║server║         ╠═══╗  ║     │
       ╔══════╗      ║ t ╟───eth0╢      ╟GPIO#4───╢PPS║  ╟─────┘
       ║ RPi  ╟──────╢ c ║       ║      ║         ╚═══╩══╝
       ╚══════╝   ┌──╢ h ╟──┐    ║      ╟GPIO#7╴╴╴╢PPS║  ╟╴╴
                  │  ╚═══╝  │    ╚══════╝         ╚═══╩══╝
               ╔══╧══╗   ╔══╧══╗
               ║ PC1 ║   ║ PC2 ║
               ╚═════╝   ╚═════╝

overview: path of time source

(without external NTP servers)

╔═══════╗       ╔══════════════════╗
║ GPS   ╫──RX───╫──┐ KERNEL        ║
║ ╔═════╣       ║  │               ║                                     ╔══════════════
║ ║NMEA─╫──TX───╫─[+]─/dev/ttyAMA0─╫────────┬───NMEA──x                  ║ CHRONY
║ ╠═════╣       ║                  ║        │                            ║
║ ║ PPS─╫─GPIO4─╫─────/dev/pps0────╫──────┬─)────────────────────────────╫──[+]────PPS0
╚═╩═════╝      ╴╫╴╴┐               ║      │ │                            ║   │
  ╠═════╣      ╴╫╴[+]╴/dev/ttyAMA1╴╫╴╴╴┐  │ │                            ║   │
║ ║*PPS╴╫╴GPIO7╴╫╴╴╴╴╴/dev/pps1╴╴╴╴╫╴┬╴)╴╴)╴)╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╫╴╴╴)╴[+]╴PPS1*
╚═╩═════╝       ╚══════════════════╝ ╵ ╵  │ │ ╔══════════════════╗       ║   │  ╵
                                     ╵ ╵  │ │ ║ GPSD             ║       ║   │  ╵
                                     ╵ ╵  │ │ ║                  ║       ║   │  ╵
                                     ╵ ╵  │ └─╫─GPS0──┬──────────╫─SHM0──╫───)──)──GPS0
                                     ╵ ╵  │   ║       │        ┌─╫─SHM1──╫───┴──)──PSM0
                                     ╵ ╵  └───╫─PPS0─[+]───────┴─╫─SOCK0─╫──────)──PST0
                                     ╵ ╵      ║                  ║       ║      ╵
                                     ╵ └╴╴╴╴╴╴╫╴GPS1╴╴╴╴╴┬╴╴╴╴╴╴╴╫╴SHM2╴╴╫╴╴╴╴╴╴)╴╴GPS1*
                                     ╵        ║          │     ┌╴╫╴SHM3╴╴╫╴╴╴╴╴╴┴╴╴PSM1*
                                     └╴╴╴╴╴╴╴╴╫╴PPS1╴╴╴╴[+]╴╴╴╴┴╴╫╴SOCK1╴╫╴╴╴╴╴╴╴╴╴PST1*
                                              ╚══════════════════╝       ╚══════════════
*) optional second PPS device

requirements

hardware:

software:

installation:

assuming,

  1. clone this repository with: git clone https://github.com/beta-tester/RPi-GPS-PPS-StratumOne.git
    and change into the folder where it was cloned to (e.g.: RPi-GPS-PPS-StratumOne).
    (in case it fails, because git is not installed yet, please do sudo apt update; sudo apt install git and try to clone the repository again)
  2. run bash install-gps-pps.sh to install necessary packages and setup Kernel PPS, GPSD, and NTP with PPS support.
  3. reboot your RPi with sudo reboot
  4. in case you have a RPi3, RPi3+, RPi4 or RPi0w with a built-in Bluetooth adapter, and the script didn't disabled Bluetooth successfully, please run sudo raspi-conf and disable the Bluetooth adapter there. otherwise the built-in Bluetooth adapter will block the serial port of the GPIO pins.

done.

NOTES:

gpsd v3.20 available on bullseye repository may have an issue with autobaud feature (finding the correct baud rate of the gps device automatically).
you may have to set the correct baud rate explicitly in the file /etc/default/gpsd
e.g. for baud rate 115200:
GPSD_OPTIONS="--listenany --nowait --badtime --passive --speed 115200"

note1:

the chrony configuration files are in the /etc/chrony/statum1 folder. only files with *.conf will be included to the configuration. all other files in that folder will be ignored. by renaming the files you easily can enable and disable different configuration files.

note2:

PPS is a high precise pulse, without a time information.
GPS (NMEA) has date/time information, but with mostly lower precision.

to combine GPS and PPS in chrony, there is a specific requirement, (link)
that GPS data and PPS signal must have a time offset of less than +/-200ms
otherwise the PPS signal is seen as false-ticker and will be rejected by chrony.

depending on your GPS device the offset used in my script can be way too off.

to adjust the offset of GPS0 edit the file /etc/chrony/stratum1/10-refclocks-pps0.conf

refclock SHM 0 refid GPS0 precision 1e-1 offset 0.0 ...

to find the actual offset, you can use gnuplot (already installed by the script) and run the plot script 99-calibrate-offset-gps0.gnuplot to visualize the actual histogram of the measured offsets.

# stop gpsd and chrony, delete all log files, restart chrony and gpsd
# wait few seconds to give time to create a log file,
# and start the histogram.

sudo systemctl stop --now gpsd.{service,socket} && sudo systemctl stop --now chrony && \
sudo rm -f /var/log/chrony/*.log && \
sudo systemctl start --now chrony && sudo systemctl start --now gpsd && \
sleep 10 && \
gnuplot ~/RPi-GPS-PPS-StratumOne/gnuplot/99-calibrate-offset-gps0.gnuplot

the histogram will updated every minute. keep it running for at least 30 minutes. the longer you keep it running the better offset value you can find. (but not longer than 24h. every 24h a new log will started from zero)

the x-value of the highest spike in the histogram is the offset value for the GPS0 you can once you got a good offset, you can use your RPi + GPS offline.

for more information, see also:
/etc/chrony/chrony.conf
/etc/chrony/statum1/99-calibrate-offset.gps0

note3:

to properly restart chrony, use:

sudo systemctl stop --now gpsd.{service,socket} && \
sudo systemctl restart --now chrony && \
sudo systemctl start --now gpsd

this will disconnect all connected gpsd-clients.

enable second PPS:

to enable a second PPS source (/dev/pps1), please uncomment the prepared lines in the following files:

and reboot the system.

be warned: as long the kernel of the RPi uses "soft"-interrupts for the second PPS its accuracy is questionable.
for tests i feeded both gpio-pins with the same signal from the same pps-device (shorted both pins) and noticed a time difference of about 20µs in chrony between /dev/pps0 and /dev/pps1
see (two gpio pins has different delays?)