ADSB Receiver with GPS Precision Time
Here is an upgrade for my ADSB receiver - GPS precision time. The MLAT position calculation for aircrafts depends on a precise time. While there is already a time synchronization between MLAT receivers in a specific area it is also possible to add a precise time source to improve the calculation result. A GPS receiver is such source when equipped with a PPS (pulse per second) output. The PPS is a signal with a width of less than one second and a sharply rising or abruptly falling edge that accurately repeats once per second with low jitter. The GPS time and PPS signal are then used to sync the internal ntp time service and keep a low offset and jitter.
My choice for GPS receiver was the Adafruit GPS v3 breakout board as it was a spare in my boxes. Beside the small size and high channel GPS receiver it has a PPS output and operates at 3.3V-5V input, but 3.3V TTL logic output, perfect for the Raspberry Pi. The additional backup battery come in handy in case of a power cut.
GPS board connection to Raspberry Pi 2/3 #
Adafruit GPS v3 pin Raspberry Pi I/O header pin VIN Pin 2 = 5V GND Pin 14 = GND TX Pin 10 = GPIO 15 RX Pin 8 = GPIO 14 PPS Pin 12 = GPIO 18
Enable PPS input and set UART baudrate #
To enable the PPS input and setting the correct baudrate for the GPS the Raspberry Pi config file
/boot/config.txt must be changed. Add at the end:
# GPS PPS input dtoverlay=pps-gpio,gpiopin=18 init_uart_baud = 9600
Disable serial console on UART0 #
The GPS is connected to the UART0 serial interface (ttyAMA0) that is usually occupied by the Raspberry Pi serial console. That needs to be disabled. So we edit
/boot/cmdline.txt and change
Also the getty instance on ttyAMA0 needs to be disabled:
$ sudo systemctl disable serial-getty@ttyAMA0.service
Install GPS service #
This service is required to access the GPS and it provides a shared memory the for the ntp service with its own time informations.
$ sudo apt-get install gpsd gpsd-clients python-gps
To successfully run the GPS service, its configuration needs to be changed to access the UART0. So edit
/etc/default/gpsd as follows.
# Default settings for the gpsd init script and the hotplug wrapper. # Start the gpsd daemon automatically at boot time START_DAEMON="true" # Use USB hotplugging to add new USB devices automatically to the daemon USBAUTO="true" # Devices gpsd should collect to at boot time. # They need to be read/writeable, either by user gpsd or the group dialout. DEVICES="/dev/ttyAMA0 /dev/pps0" # Other options you want to pass to gpsd GPSD_OPTIONS="-n"
Now we reboot and check that PPS and GPS are working.
$ dmesg | grep pps [ 5.957377] pps_core: LinuxPPS API ver. 1 registered [ 5.957515] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti firstname.lastname@example.org; [ 5.973778] pps pps0: new PPS source pps.-1 [ 5.973907] pps pps0: Registered IRQ 184 as PPS source
Installing pps-tools will provide some additional informations. This is a mandatory step in order to get ntp service with PPS working. Compiling ntp has a dependency for timepps.h that comes with pps-tools.
$ sudo apt-get install pps-tools $ sudo ppstest /dev/pps0 trying PPS source "/dev/pps0" found PPS source "/dev/pps0" ok, found 1 source(s), now start fetching data... source 0 - assert 1482268186.000006148, sequence: 4647 - clear 0.000000000, sequence: 0 source 0 - assert 1482268187.000003768, sequence: 4648 - clear 0.000000000, sequence: 0 source 0 - assert 1482268188.000003324, sequence: 4649 - clear 0.000000000, sequence: 0
Checking that GPS service is running:
$ sudo service gpsd status gpsd.service - GPS (Global Positioning System) Daemon Loaded: loaded (/lib/systemd/system/gpsd.service; static) Active: active (running) since Tue 2016-12-20 19:45:08 UTC; 1h 26min ago Main PID: 745 (gpsd) CGroup: /system.slice/gpsd.service └─745 /usr/sbin/gpsd -N -n /dev/ttyAMA0</pre> Dec 20 19:45:08 raspberrypi systemd: Started GPS (Global Positioning System) Daemon.
$ cgps -s should output something like:
x Time: 2016-12-20T21:14:35.000Z xxPRN: Elev: Azim: SNR: Used: x x Latitude: xx.xxxxxx N xx 12 78 291 24 Y x x Longitude: xx.xxxxxx E xx 24 67 133 00 Y x x Altitude: xxx.x m xx 25 36 261 29 Y x x Speed: 1.1 kph xx 32 33 303 15 Y x x Heading: 71.1 deg (true) xx 19 32 050 17 Y x x Climb: 0.0 m/min xx 6 21 087 00 N x x Status: 3D FIX (5 secs) xx 17 18 042 00 N x x Longitude Err: +/- 16 m xx 2 15 122 00 N x x Latitude Err: +/- 27 m xx 14 14 322 21 N x x Altitude Err: +/- 19 m xx 15 10 182 19 N x x Course Err: n/a xx 29 04 203 00 N x x Speed Err: +/- 199 kph xx 10 01 268 00 N x x Time offset: 0.506 xx 136 00 000 00 N x x Grid Square: xxxxxx xx x
Getting an NTP with PPS ("ATOM") support #
Unfortunately, the version of NTP supplied with the Raspberry Pi Linux does not support PPS. These are the steps to download, compile and install NTP. You can choose between a release and a development version. The lines below are shown for release version ntp-4.2.8p9, but you will need to alter the version number to suit the version you wish to compile.
$ sudo cp /usr/include/sys/timepps.h /usr/include/. $ mkdir ntp # make a convenient working directory, if you don't already have one $ cd ntp # enter that directory $ sudo apt-get install libcap-dev # once-off, required to prevent later file not found error $ sudo apt-get install libssl-dev # once-off, you may not need this, but reports suggest you might to build keygen $ wget https://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-4.2.8p9.tar.gz $ tar xvfz ntp-4.2.8p9.tar.gz $ cd ntp-4.2.8p9 $ ./configure --enable-linuxcaps # takes some minutes $ make -j5 # takes some minutes (use "make -j5" for faster execution on the four-core Raspberry Pi 2/3.) $ sudo make install # puts ntp* in /usr/local/bin/ntp*, takes some seconds $ sudo service ntp stop $ sudo cp /usr/local/bin/ntp* /usr/bin/ && sudo cp /usr/local/sbin/ntp* /usr/sbin/ $ sudo service ntp start
Optional check for version and basic function
$ ntpq -crv -pn
Before we can alter the ntp service configuration we need to overcome a problem on Raspberry Pi's Debian OS. In fact, when you edit /etc/ntp.conf to use PPS and GPS time the DHCP or DHCP3 service will stealthy replace your ntp configuration by its own. So after reboot the ntp service will most like not use PPS and GPS as configured. This is why we disabled the DHCP behavior with overwriting the ntp configuration. Edit
From: request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, dhcp6.name-servers, dhcp6.domain-search, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; To: request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, dhcp6.name-servers, dhcp6.domain-search, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes;</pre> Remove the DHCP service hook and the stealthy created ntp configuration: $ sudo rm /etc/dhcp/dhclient-exit-hooks.d/ntp $ sudo rm /var/lib/ntp/ntp.conf.dhcp
No we can edit the ntp service configuration to use PPS and GPS inputs for precision time. My configuration in
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help driftfile /var/lib/ntp/ntp.drift # coarse time ref-clock, not really needed here as we have LAN & WAN servers server 127.127.28.2 minpoll 4 maxpoll 4 iburst true prefer fudge 127.127.28.2 flag1 1 refid SHM2 stratum 1 # Kernel-mode PPS ref-clock for the precise seconds server 127.127.22.0 minpoll 4 maxpoll 4 fudge 127.127.22.0 refid PPS # Enable this if you want statistics to be logged. #statsdir /var/log/ntpstats/ statistics loopstats peerstats clockstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable # pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will # pick a different set every time it starts up. Please consider joining the # pool: <http://www.pool.ntp.org/join.html> server 0.de.pool.ntp.org minpoll 10 iburst prefer server 1.de.pool.ntp.org minpoll 10 iburst server 2.de.pool.ntp.org minpoll 10 iburst prefer server 3.de.pool.ntp.org minpoll 10 iburst server fritz.box minpoll 5 maxpoll 5 iburst
Note that when using a PPS source you must have one other server marked "prefer". In the example above I have added prefer to the shared memory driver (type 28) so that the combination of PPS and GPSD would provide the correct time even with no Internet servers. The ntp service needs a restart then.
$ sudo service ntp force-reload
Now the ntp service should use PPS and GPS input for precision time keeping.
$ ntpq -crv -pn
associd=0 status=0115 leap_none, sync_pps, 1 event, clock_sync, version="ntpd email@example.com Tue Dec 20 15:33:14 UTC 2016 (1)", processor="armv7l", system="Linux/4.4.38-v7+", leap=00, stratum=1, precision=-19, rootdelay=0.000, rootdisp=1.075, refid=PPS, reftime=dc042552.9b78088d Tue, Dec 20 2016 21:46:58.607, clock=dc042558.9751bae5 Tue, Dec 20 2016 21:47:04.591, peer=44360, tc=4, mintc=3, offset=0.011402, frequency=-8.472, sys_jitter=0.001907, clk_jitter=0.107, clk_wander=0.011 remote refid st t when poll reach delay offset jitter ============================================================================== 127.127.28.0 .GPS. 1 l 7 16 377 0.000 4.899 5.445 o127.127.22.0 .PPS. 0 l 6 16 377 0.000 0.011 0.002 192.168.178.255 .BCST. 16 B - 64 0 0.000 0.000 0.002 +192.168.178.1 18.104.22.168 2 u 44 64 77 0.515 0.967 0.038 *22.214.171.124 .DCFp. 1 u 359 1024 1 34.215 0.470 0.172 +2003:63:2737:e7 126.96.36.199 2 u 30 32 377 0.547 0.910 0.114
The PPS and GPS drivers are present and connected (reach = 377).