5 minute guide to making a GPS Locked Stratum 1 NTP Server with a Raspberry Pi

This is an article on making a network attached Stratum 1 NTP Server using a Raspberry Pi+ Model 2 or 3 and the Uputronics Raspberry Pi+ GPS Expansion Board. If you need a standalone ready to go solution or need more performance please consider the LeoNTP Networked Time server unit which is available here.

Due to significant changes to Raspbian we have decided to retire the old guide here https://ava.upuaut.net/?p=726 and redo it.This guide assumes Raspbian Stretch Lite November 2018 released 2018-11-13. No other version or distribution is supported.

This solution will not give you a standalone off grid NTP server. NTP isn’t designed to work off grid using just the NMEA derived time and PPS to discipline it. You need an external server and then use PPS to discipline it.

Uputronics Raspberry Pi+ GPS Expansion Board

Ideally rather than supplying a premade image I would have a set of concise instructions on making your own install from scratch so you could use the latest versions of the software. With assistance from David Taylor who did lots of background work on this here I present the following instructions on making a cheap PPS disciplined NTP Time server using one of the Raspberry Pi+ GPS boards sold on Uputronics.

The guide assumes you have a cursory knowledge of Linux, enough to install Raspbian and login should do.

You will need a Raspberry Pi 2 or 3 B+, the Uputronics Raspberry Pi+ GPS Expansion Board and a suitable GPS antenna.

This guide is assuming you’re using Raspbian Stretch Lite November 2018 released 2018-11-13 image. Download and write this to an SD card (See http://www.raspberrypi.org/documentation/installation/installing-images/README.md). Other distributions may work but these instructions are known to work with Raspbian Stretch Lite.

Attach the Uputronics Raspberry Pi+ GPS Expansion Board to the Pi, insert the SD card, connect the antenna and network cable and boot the Pi up. Either connect locally or via SSH to the Pi (If you can’t SSH in and don’t have a monitor see this https://www.raspberrypi.org/documentation/configuration/wireless/headless.md)

Follow the instructions carefully if you miss steps things won’t work.

Text in italics is what you type.
Text in red indicates editing inside a file.

Prerequisite Settings

sudo raspi-config
5 Interfacing Options
P2 SSH -> Would you like the SSH server to be enabled – YES (Recommended)
P6 Serial -> Login Shell (no) Hardware (yes) (Optional)
Quit but no need to reboot at this point.

sudo nano /boot/config.txt
Add at the bottom :

dtoverlay=pps-gpio,gpiopin=18
Save and Quit Nano.

sudo apt-get update
sudo systemctl disable hciuart
sudo systemctl mask [email protected]
sudo apt-get install pps-tools ntp dnsutils
sudo reboot

Verifying PPS Is Working

Ensure the GPS has a lock and the Green PPS LED on the Uputronics Pi+ GPS Expansion Board is blinking once a second.

dmesg | grep pps

Output should be similar to :

[ 2.443494] pps_core: LinuxPPS API ver. 1 registered
[ 2.446699] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <[email protected]>
[ 2.471796] pps pps0: new PPS source pps.-1
[ 2.471886] pps pps0: Registered IRQ 498 as PPS source
[ 6.965166] pps_ldisc: PPS line discipline registered
[ 6.966569] pps pps1: new PPS source ttyAMA0
[ 6.966664] pps pps1: source "/dev/ttyAMA0" added

sudo ppstest /dev/pps0

Output should be similar to:

 trying PPS source "/dev/pps0"
 found PPS source "/dev/pps0"
 ok, found 1 source(s), now start fetching data...
 source 0 - assert 1418933982.998042450, sequence: 970 - clear  0.000000000, sequence: 0
 source 0 - assert 1418933983.998045441, sequence: 971 - clear  0.000000000, sequence: 0

(Press CTRL+C to quit). This indicates the PPS Module is loaded (top example) and is working (bottom).

GPS board mounted in Geaux Robot Dog Bone Case for Raspberry Pi B+ also available from HAB Supplies

GPS board mounted in Geaux Robot Dog Bone Case for Raspberry Pi B+ also available from Uputronics

Enabling PPS/ATOM Support in NTPD

The supplied version of NTPD on the Raspberry Pi now supports PPS so there is no need to roll your own NTP.

You need to pick a few local NTP servers to use. The easiest way to do this is pick your region:

https://support.ntp.org/bin/view/Servers/NTPPoolServers
Select your region then you get a list of the country servers. E.g for the UK its uk.pool.ntp.org.
Type:

dig uk.pool.ntp.org

You will get four IP’s back:

; <<>> DiG 9.10.3-P4-Raspbian <<>> +answer uk.pool.ntp.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51647
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;uk.pool.ntp.org. IN A

;; ANSWER SECTION:
uk.pool.ntp.org. 24 IN A 193.150.34.2
uk.pool.ntp.org. 24 IN A 176.58.109.199
uk.pool.ntp.org. 24 IN A 195.195.221.100
uk.pool.ntp.org. 24 IN A 185.53.93.157


sudo nano /etc/ntp.conf
Add
server 127.127.22.0 minpoll 4 maxpoll 4
fudge 127.127.22.0 flag3 1 refid PPS
tos mindis 0.2

Comment out all the pool lines:

#pool 0.debian.pool.ntp.org iburst
#pool 1.debian.pool.ntp.org iburst
#pool 2.debian.pool.ntp.org iburst
#pool 3.debian.pool.ntp.org iburst

Add the four servers from the dig command with the top one saying prefer on it:

server 193.150.34.2 iburst prefer
server 176.58.109.199 iburst
server 195.195.221.100 iburst
server 185.53.193.157 iburst

You may also want to add your local lan to so you can query the NTP Server by adding:
restrict 192.168.1.0 mask 255.255.255.0

Note You MUST add a preferred server or PPS doesn’t work. Its worth at this point seeing if you’re ISP has its own NTP server you can use and adding that.

Save and close nano.

sudo service ntp restart

After a few minutes run

ntpq –p

if you get oPPS(0) this indicates source selected, Pulse Per Second (PPS) used and everything is working.

If you aren’t seeing the settings its possible the NTP server is picking up the NTP information via DHCP which is over riding your settings above. Do this :

rm /etc/dhcp/dhclient-exit-hooks.d/ntp
rm /var/lib/ntp/ntp.conf.dhcp

At this point you have a NTP server which will use an external time source and use your local PPS to discipline it.

Setting Stationary Mode

Grab this small program code here : https://pastebin.com/YTc9Nd3D
Compile + link:

gcc -o gpsControl gpsControl.c

sudo ./gpsControl -p -d /dev/ttyAMA0 = Portable Mode
sudo ./gpsControl -s -d /dev/ttyAMA0 = Stationary Mode

May take a few goes to set it.

pi@hypatia:~ $ sudo ./gpsControl -s -d /dev/ttyAMA0
Set GPS for stationary mode
Configuring device /dev/ttyAMA0
>>>>>>>>>>>>>>>>>>>>> SENDING >>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> SENDING >>>>>>>>>>>>>>>
GPS mode set OK

Static IP + Hostname

If you want to fix your LAN IP you do it by amending /etc/dhcpcd.conf adding the following lines:

interface eth0
static ip_address=192.168.1.7/24
static routers=192.168.1.254
static domain_name_servers=8.8.8.8 8.8.4.4

Amend your hostname by editing /etc/hostname and then adding this to /etc/hosts as well. I.e if you call your machine ‘eleanor’ add this after localhost in /etc/hosts:

127.0.0.1 localhost eleanor

Further Reading

David Taylor’s website here http://satsignal.eu/ntp/Raspberry-Pi-NTP.html goes into much further detail about the process above and covers graphing, remote access monitoring etc and I highly recommend you read it.

Hope this helps, let me know how you get on with these instructions and I’ll try keep them up to date.

Thanks to:

David Taylor
Dave Akerman
sout + others on #ntp irc.freenode.org

Mounting Uputronics LNA’s on the mast

One question we get asked at Uputronics is do you offer a mast head enclosure for your amps ? Well unfortunately not the current case design doesn’t lend itself to being mast mounted. However you can utilise one of the mast mount cases sold by Uputronics to mount the Uputronics LNA‘s on the mast. Here I’ve mounted a pair of LNA’s in one enclosure:

 

The cases are supplied with a blank plate so you can drill to your own requirements. I removed the ends from two Uputronics LNA’s and used the end plates as templates (be careful the endplates are asymetric so make sure you copy the right side or the screws won’t mount).

2016-10-19-15-30-02

Drill the holes (SMA’s ~ 6.5mm and the screws are ~ 3.5mm).
Mount the LNA’s on the plates using the original screws. Use some 15 cms SMA 90′ to SMA panel to bring the output back out to the plate:
2016-10-19-19-20-16

Stick it all back together and mount it on the mast. Obviously this setup assumes you are using bias tee.

It’s not about the gain its about the signal to noise…

Stick a preamp in front of your radio. Will make reception better right ? Well, as with most things in life its not as simple as that. It may have a beneficial effect but it depends on a number of factors, where your preamp is and what your radio is.

Let me explain. Its about the signal to noise, not the gain. Gain is helpful but the noise figure (NF) and the linearity (IP3) will ultimately determine the quality of your signal.

Wikipedia defines the NF as :

Noise figure (NF) and noise factor (F) are measures of degradation of the signal-to-noise ratio (SNR), caused by components in a radio frequency (RF) signal chain

Put simply as the signal passes from your antenna to your radio it will degrade in quality (S/N Ratio). You can mitigate against this with low loss coax and short runs but you are always going to get some loss. The end game is simple you need to keep that noise figure as low as possible to maintain the signal you’re actually interested in.

As for the IP3, Wikipedia defines it as:

In telecommunications, a third-order intercept point (IP3 or TOI) is a measure for weakly nonlinear systems and devices, for example receivers, linear amplifiers and mixers.

The linearity metrics used in the industry (IIP3 and OIP3) are a relatively complex subject (See here for a good article) but the thing to keep in mind is that the linearity of a system should be as high as possible. Lower linearity can cause overloading which will lead to a raise in noise floor, intermodulation products (spurs) and finally the desensitizing of the receiver.

Let’s consider a simple system:

Antenna -> 10 meters of Coax -> Receiver.

example1

We are going to make some assumptions firstly we are considering 1090Mhz reception and the coax is RG174 (which is about 94db/100meters loss at 1090Mhz – don’t ever use RG174 for ADS-B !). The example radio will be an Airspy with a NF of 3.5db. For the purposes of the exercise the NF of coax can be assumed to be the same as the loss. Using Avago’s AppCad we can do a noise calc on the system:

2stage

So in this system we have a noise figure of 12.90db which is fairly large. So what happens if we stick a LNA in there near the antenna ? Let’s consider the following system :

Antenna -> 1 meter of Coax -> PSA5043+ -> CBP1090EC -> 9 meters coax -> Receiver.

example2
I’ve broken the Uputronics Ceramic ADSB 1090Mhz Preamp into its base components, the PSA5043+ amp and the CBP1090EC Ceramic filter. The PSA5043+ has about 15db of gain at 1090Mhz. 5stage

And look at that you’ve brought the NF down to 3.45db which is a large improvement over the system without significantly compromising the linearity (IIP3).

Conversely let’s consider what happens when you plug the preamp in next to your radio:

Antenna -> 9 meter of Coax -> PSA5043+ -> CBP1090EC -> 1 meters coax -> Receiver.

example3

 

 

5stage2

The linearity is very good at an IIP3 of over 22dBm, but… See the NF ? 9.49db nearly as bad as the system with no preamp in it. At this level, the receiver could be considered “deaf”. You get the gain and the linearity but the NF is much higher. As you can see, having the preamp close to the receiver won’t improve the sensitivity.

Some receivers have an LNA in the radio itself. So what happens if you plug a preamp into a radio that already has a LNA like the SDRPlay or the FunCube Dongle?

Antenna -> 1 meter of Coax -> PSA5043+ -> CBP1090EC -> 9 meters coax -> LNA Equipped Reciever.

example4

Taking the data from the SDRPlay datasheet here, at 1090Mhz with the internal noise figure NF is 5.19dB and the IP3 is -14.86dB. sdrplay

As you can see the noise figure (NF) is comparable to, but still higher than on a system with no preamp in the receiver. On the other hand, the linearity degraded dramatically to an IIP3 at -19dBm. This means even a moderate interferer can cause severe intermodulation, thus desensitizing the receiver.

In summary, a setup with a good antenna system connected to a receiver with a built in LNA:

  • May not benefit from having a preamp at the antenna.
  • The presence of a built in LNA is detrimental to the linearity and may degrade the signals.

So in conclusion:

  • Put the preamp as close to the antenna as possible.
  • Receivers with a built in LNA may not get the most out of an antenna system or preamp.
  • Proper gain distribution guarantees better performance than one-size-fits-all solutions, both in terms of sensitivity and strong signals handling.

Uputronics sell a variety of preamps suitable for use with SDR recievers for 403Mhz (Radiosonde), 434Mhz, 868Mhz/FLARM and ADS-B 1090Mhz.

 

ADS-B Reception RTL vs Airspy Round 2

In my previous article I compared an older Elonics E4000 based dongle with an Airspy for ADS-B reception. Unsurprisingly the Airspy beat the performance of the RTL dongle in all areas. However a number of commenters here http://www.rtl-sdr.com/rtl-sdr-vs-airspy-on-ads-b-reception/ noted the performance of the E4000 dongles wasn’t great for ADS-B.

So I went out and bought an R820T2 dongle from Cozycave.I got the expensive one (£7.85!)

The test setup was exactly as before, the Airspy and RTL connected via the Minicircuits splitter. The Airspy providing power to the 1090Mhz preamp. Airspy was using ADSB Spy V1.0.0.14 and the RTL 820T2 was using ADSB# V1.0.11.1 (Both are now packaged with SDRSharp). Again the Airspy wasn’t correcting using FEC/CRC and was suppressing duplicates, the ADSB# was correcting and using CRC and allowing duplicates through.

The test was run on a week day for 24 hours from around 20:00 to 20:00.

The range results were very similar to the initial tests with the Airspy for most part having slightly greater range than the RTL, again in one specific direction over 50km more. But generally it was limited by geography with both radios exceeding 400km over the North Sea (Outer green ring is 400km).

46voHoz

The results from Virtual Radar showed in the 24 hour period the Airspy received over 31 million messages of which 31 were unusable and 111 had bad parity. Of these 2.2million were Airborne Position/Velocity.

In the same period the RTL820T2 recorded 22.3million messages of which 3 million were unusable, 5523 had bad parity. Of these 1.2million were Airborne position/Velocity.

So yes the commenters were correct the RTL820T2 does exhibit much better performance for ADS-B reception than its E4000 based counterparts. Unsurprisingly the Airspy does still exceed the performance of the RTL dongles by a significant amount but you have to draw attention to what an absolute bargain the RTL dongles are.

I am going to perform one final test where I compare the Airspy to the R820T2 again but this time using dump1090 with –no-fix to prevent the correction of data (duplicates will still happen). This should give a true like for like comparison. We already know what the results are but its worth demonstrating what the additional cost of the Airspy translates to in outright ADS-B performance.

UPDATE :

Youssef Touil kindly supplied a version of ADSB# with duplicates suppressed, with the equivalent of dump1090’s –no-fix and with no phase “enhancement” that produce CRC valid noise. This would provide a direct comparison with the Airspy. This is available here should you wish to try it: http://airspy.com/downloads/ADSBSharp-no-fix.zip

Just to remind this isn’t to make the RTL look bad, this is preferred by sites such as such as FR24 and PlanePlotter’s sharing network as the CRC is weak and it can result in erroneous data being uploaded to their servers.

The results over a 46 hour period were as follows :

Total Messages Received:
Airspy 65,150,313
RTL 32,973,049

Airborne Position:
Airspy 4,615,972
RTL 2,270,810

Unusable:
Airspy 533
RTL 635,549

So as near as makes no difference the Airspy is doing twice the number of messages compared to the RTL. Range was again limited by radio horizon/geography both radios exceeding the 400km range.

For the money you simply can’t beat the RTL however if you’re serious about ADS-B the Airspy is most certainly the way to go.

ADS-B Reception RTL vs Airspy

I’ve recently been playing with ADS-B reception to test new revisions of my 1090Mhz ADS-B Preamp. With my location 300 meters ASL and between two international airports I’m ideally placed for reception. I wanted to see what difference there was between the nice and cheap RTL dongles and the Airspy SDR.

I had previously installed an A3 ADS-B antenna from Jetvision.de in my loft:

2015-04-18 09.49.13

You can see the preamp on the left. The indoor location is far from ideal but I currently don’t have space on the mast outside to fit it and as you can see by the results below its still performing well. At some point it will move outside. The antenna is connected using Belden RG6 with some nice quality SMA connectors from Barenco.

The preamp is a Uputronics ADS-B 1090Mhz preamp with SAW filter. Based around the Minicircuits PSA4-5043+ it provides approximately 14dB of gain at 1090Mhz and has a Golledge SAW filter to remove out of band inter-modulation.

To enable a side by side comparison of the two receivers the feed was connected into a Minicircuits ZAPD-2DC-S+ power splitter. The Airspy with its ability to provide power to the preamp via bias tee was connected to the DC pass through port. The RTL was connected to the other RF port:

2015-05-09 10.35.07

A quick word on the dongle, its an older Elonics E4000 based model the only modification is the Belling-Lee connect was removed and replaced with an SMA connector. Otherwise its stock.

SDRSharp’s ADSBSharp and ADSBSpy V1.0.0.11 (Link is latest V1.0.0.12) programs to drive the dongles these fed into Virtual Radar Server and ADSB Scope. To ensure no issues both dongles were on separate USB3 buses. After briefly adjusting the gain on both dongles to get the optimal reception I left them to run for about 28 hours on a week day.

At this point its worth noting, ADSBSpy suppresses duplicate frames and it doesn’t try to correct frames with bad CRC. This is preferred by sites such as such as FR24 and PlanePlotter’s sharing network as the CRC is weak and it can result in erroneous data being uploaded to their servers. ADSBSharp does correct frames with bad CRC and doesn’t do any duplicate detection so I would expect more frames and position reports from ADSBSharp.

So the results. Firstly range :

ezgif.com-gif-maker

As you can see the overall range is generally limited by geography from my location and in certain directions both radios are getting pretty close to the radio horizon.The outer ring is 400km of which both radios managed to exceed reception. However fairly consistently the Airspy exceeded the range of the RTL in some areas by over 50km.

In the 28 hour period the RTL returned the following stats :

TotalMessages Recieved : 2,910,780
AirbornePosition : 1,345,245
AirborneVelocity : 1,342,768

The Airspy :

TotalMessages Recieved : 10,307,631
AirbornePosition : 4,836,796
AirborneVelocity : 4,410,924

The numbers speak for themselves really, the other interesting number is the number of unusable frames with the RTL was 3.4million with the Airspy it was 305!

When you consider the results from the Airspy contained no duplication or corrected CRC the results are even more impressive. So in conclusion if you are serious about ADS-B reception the Airspy with a preamp is the way to go. I suspect it will give the hardware based ADS-B receivers a run for their money too whilst being significantly cheaper (If anyone wants to supply me one I’m happy to do a head to head!)

Getting Started with Ublox Part 4 – Basic NMEA Parser

Credits : Thanks to Dave Akerman who’s NMEA Parser code these examples are based on.

Ok so now we have the GPS talking to the Arduino and you have some method of debugging its time to read that NMEA from the GPS and turn it into something we can use within our code.

The basic principle of an NMEA parser is to locate the NMEA sentences we are interested in , usually GPGGA and GPRMC. These two sentences contain most of the information you need for navigation, GPGGA is the main one used. This example will show how to parse the information from GPGGA.

Side note on the Ublox 8 series GPGGA is replaced by GNGGA by default to indicate the navigation information is from multiple GNSS sources (I.e American GPS and Russian GLONASS normally). So for this example we will look for $$GNGGA sentences. GGA sentences contain essential fix data which provide a 3D location.

An example of this is :

$GNGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

Where :

     GGA          Global Positioning System Fix Data
     123519       Fix taken at 12:35:19 UTC
     4807.038,N   Latitude 48 deg 07.038' N
     01131.000,E  Longitude 11 deg 31.000' E
     1            Fix quality: 0 = invalid
                               1 = GPS fix (SPS)
                               2 = DGPS fix
                               3 = PPS fix
             4 = Real Time Kinematic
             5 = Float RTK
                               6 = estimated (dead reckoning) (2.3 feature)
             7 = Manual input mode
             8 = Simulation mode
     08           Number of satellites being tracked
     0.9          Horizontal dilution of position
     545.4,M      Altitude, Meters, above mean sea level
     46.9,M       Height of geoid (mean sea level) above WGS84
                      ellipsoid
     (empty field) time in seconds since last DGPS update
     (empty field) DGPS station ID number
     *47          the checksum data, always begins with *

So we need to read the incoming data from the GPS module, look for a $ to indicate the start of a sentence, when the full sentence is read in go see if it is a GNGGA line. Building on the previous code we add a new procedure to read data in and transmit to the debug when a sentence is detected (or not).


#include <SoftwareSerial.h>

#define GPSENABLE 2
SoftwareSerial mySerial(4, 3); // RX, TX
byte GPSBuffer[82];
byte GPSIndex=0;
void setup()
{
  pinMode(GPSENABLE, OUTPUT);
  digitalWrite(GPSENABLE, HIGH);
  Serial.begin(9600);
  mySerial.begin(9600);
  mySerial.println("Test Program");
}

void loop()
{
  CheckGPS();
}

void CheckGPS()
{
  int inByte;
  while (Serial.available() > 0)
  {
    inByte = Serial.read();

    if ((inByte =='$') || (GPSIndex >= 80))
    {
      GPSIndex = 0;
    }

    if (inByte != '\r')
    {
      GPSBuffer[GPSIndex++] = inByte;
    }

    if (inByte == '\n')
    {
      ProcessGPSLine();
      GPSIndex = 0;
    }
  }
}
void ProcessGPSLine()
{
  if ((GPSBuffer[1] == 'G') && (GPSBuffer[2] == 'N') && (GPSBuffer[3] == 'G') && (GPSBuffer[4] == 'G') && (GPSBuffer[5] == 'A'))
  {
    mySerial.println("GNGGA Detected!");
  }
  else
  {
    mySerial.println("It was something else!");
  }
}


Now from your software serial monitor you should see :

GNGGA Detected!
It was something else!
It was something else!
It was something else!
It was something else!
It was something else!
It was something else!
It was something else!
GNGGA Detected!

As you can see we are now detecting when we have a $GNGGA sentence and ignoring the others. So lets start extracting some data from that $GNGGA string.

We know the structure of the sentence, it starts with a $ all the fields are delimited by a comma. Firstly lets up the debug speed to 19200 as we are likely to be outputting data fairly quickly. Amend the connection speed in PuTTY to 19200 and note the change in the code below.Comment out line 31 to stop the NMEA from the GPS appearing.

#include <SoftwareSerial.h>

#define GPSENABLE 2
SoftwareSerial mySerial(4, 3); // RX, TX
byte GPSBuffer[82];
byte GPSIndex=0;
unsigned int GPS_Satellites=0;
unsigned int GPS_Altitude=0;

void setup()
{
  pinMode(GPSENABLE, OUTPUT);
  digitalWrite(GPSENABLE, HIGH);
  Serial.begin(9600);
  mySerial.begin(19200);
  mySerial.println("Test Program");
}

void loop()
{
  CheckGPS();
}

void CheckGPS()
{
  int inByte;
  while (Serial.available() > 0)
  {
    inByte = Serial.read();

    mySerial.write(inByte); // Output exactly what we read from the GPS to debug

    if ((inByte =='$') || (GPSIndex >= 80))
    {
      GPSIndex = 0;
    }

    if (inByte != '\r')
    {
      GPSBuffer[GPSIndex++] = inByte;
    }

    if (inByte == '\n')
    {
      ProcessGPSLine();
      GPSIndex = 0;
    }
  }
}
void ProcessGPSLine()
{
  if ((GPSBuffer[1] == 'G') && (GPSBuffer[2] == 'N') && (GPSBuffer[3] == 'G') && (GPSBuffer[4] == 'G') && (GPSBuffer[5] == 'A'))
  {
    mySerial.println("GNGGA Detected!");
    ProcessGNGGACommand();
    mySerial.print("Altitude :");
    mySerial.println(GPS_Altitude);
    mySerial.print("Satellites :");
    mySerial.println(GPS_Satellites);
  }
}
void ProcessGNGGACommand()
{
  int i, j, k, IntegerPart;
  unsigned int Altitude;

  // $GNGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
  //                                               =====  <-- altitude in field 8

  IntegerPart = 1;
  GPS_Satellites = 0;
  Altitude = 0;

  for (i=7, j=0, k=0; (i<GPSIndex) && (j<9); i++) // We start at 7 so we ignore the '$GNGGA,'
  {
    if (GPSBuffer[i] == ',')
    {
      j++;    // Segment index
      k=0;    // Index into target variable
      IntegerPart = 1;
    }
    else
    {
      if (j == 6)
      {
        // Satellite Count
        if ((GPSBuffer[i] >= '0') && (GPSBuffer[i] <= '9'))
        {
          GPS_Satellites = GPS_Satellites * 10;
          GPS_Satellites += (unsigned int)(GPSBuffer[i] - '0');
        }
      }
      else if (j == 8)
      {
        // Altitude
        if ((GPSBuffer[i] >= '0') && (GPSBuffer[i] <= '9') && IntegerPart)
        {
          Altitude = Altitude * 10;
          Altitude += (unsigned int)(GPSBuffer[i] - '0');
        }
        else
        {
          IntegerPart = 0;
        }
      }
    }
    GPS_Altitude = Altitude;
  }
}

Why not the rest ? Exercise left for reader 🙂

Getting Started with Ublox Part 3 – Setting Up Software Serial for Debugging

So one of the first stumbling blocks you’ll run into is how do you diagnose and debug code on the Arduino when you’re using the only serial port for the GPS ?

The ATMega328P based Arduinos like the Uno and the Duemilanove only have one hardware UART or serial port. This is a dedicated piece of hardware on the chip to do the nitty gritty of serial communications timing and the like. You can emulate this in software but it does use considerably more memory up also it can cause timing issues with other parts of your code as it uses interrupts.

It is advised you should use the hardware UART for the GPS on any tracker to avoid timing, communication issues etc. However there is nothing stopping you using Software Serial for GPS debugging purposes (just be aware it could mess with timing on stuff like radio transmission).

So you need some method of observing the serial data back on your PC, the easy way is to add a USB to Serial module such as the UM232R by FTDI or the Sparkfun/Adafruit ones such as this https://www.sparkfun.com/products/12731. I’ll refer to whatever you’re using as “UM232R”.

So wiring it up as follows (Wiring from previous example still in place) :

arduino-ft232r

 

Arduino GND to UM232R GND (Grey wire in image above)
Arduino 3 to UM232R DB1/RXD (Blue Wire)
Arduino 4 to UM232R DB0/TXD (Purple Wire)

Plug in the Arduino and note the serial port it appears as in your computer. Now plug in the UM232R and check in Device Manager what COM port its allocated (In my case COM21)

devicesNextly you’ll need some sort of terminal program so you can see the data on this COM port. I strongly suggest you grab a copy of the excellent PuTTY from here: http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe

Open it and check Serial, enter the COM port as ascertained above and click Open
putty

 

 

 

 

 

You’ll get a black screen doing nothing. This is expected.

Ok now load the following code up on your Arduino :


#include <SoftwareSerial.h>

SoftwareSerial mySerial(4, 3); // RX, TX

void setup()
{
 mySerial.begin(9600);
 mySerial.println("Hello, world?");
}

void loop()
{
}

Ok once done press reset on your Arduino and you should see :

helloIndicating everything is wired correctly and working.

Ok now amend the slightly as follows (assumes you’re still wired up as previous posts)


#include <SoftwareSerial.h>
#define GPSENABLE 2
SoftwareSerial mySerial(4, 3); // RX, TX

void setup()
{
pinMode(GPSENABLE, OUTPUT);
digitalWrite(GPSENABLE, HIGH);
Serial.begin(9600);
mySerial.begin(9600);
mySerial.println("Hello, world?");
}

void loop()
{
if (Serial.available())
mySerial.write(Serial.read());
}

Now you should see Hello, World? followed by the NMEA from the GPS module. Basically the code is reading from the hardware serial port and then echoing this back to your software serial port. From this point you can start to do your own code and output information to the software serial port to help you debug.

 

Getting started with Ublox Part 2 – Setting Airborne Dynamic Model

Ok firstly we need to switch the RX&TX connections over on the board as we were passing through to the in board Serial to USB chip. This is important, don’t do this and nothing will work

So amend the wiring as follows :

Arduino 5V to GPS Board 5V
Arduino GND to GPS Board GND
Arduino Pin 0 (RX) to GPS Board TX
Arduino Pin 1 (TX) to GPS Board RX
Arduino Pin 2 to GPS Board EN

Load the following code up on your Arduino (close down U-Center at this point as it will be hanging on to the serial port).  This code is derived from Jon Sowman and Joey flight computer CUSF https://github.com/cuspaceflight/joey-m/tree/master/firmware

This code opens the serial port, send the binary command to set the dynamic model, waits for confirmation this has been acknowledged by the GPS. Once done it just drops to the main loop where it just blinks the Status LED once a second to indicate success.

#include <util/delay.h>

#define GPSENABLE 2
#define STATUSLED 13

void setup() {
 pinMode(GPSENABLE, OUTPUT);
 pinMode(STATUSLED, OUTPUT);
 Serial.begin(9600);
 _delay_ms(500);
 digitalWrite(GPSENABLE, HIGH);
 _delay_ms(500);
 setGPS_DynamicModel6();
}
void loop() {
 digitalWrite(STATUSLED,!digitalRead(STATUSLED));
 _delay_ms(1000);
}
void setGPS_DynamicModel6()
{
 int gps_set_sucess=0;
 uint8_t setdm6[] = {
 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06,
 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00,
 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C,
 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC };
 while(!gps_set_sucess)
 {
 sendUBX(setdm6, sizeof(setdm6)/sizeof(uint8_t));
 gps_set_sucess=getUBX_ACK(setdm6);
 }
}
void sendUBX(uint8_t *MSG, uint8_t len) {
 Serial.flush();
 Serial.write(0xFF);
 _delay_ms(500);
 for(int i=0; i<len; i++) {
 Serial.write(MSG[i]);
 }
}
boolean getUBX_ACK(uint8_t *MSG) {
 uint8_t b;
 uint8_t ackByteID = 0;
 uint8_t ackPacket[10];
 unsigned long startTime = millis();

// Construct the expected ACK packet
 ackPacket[0] = 0xB5; // header
 ackPacket[1] = 0x62; // header
 ackPacket[2] = 0x05; // class
 ackPacket[3] = 0x01; // id
 ackPacket[4] = 0x02; // length
 ackPacket[5] = 0x00;
 ackPacket[6] = MSG[2]; // ACK class
 ackPacket[7] = MSG[3]; // ACK id
 ackPacket[8] = 0; // CK_A
 ackPacket[9] = 0; // CK_B

// Calculate the checksums
 for (uint8_t ubxi=2; ubxi<8; ubxi++) {
 ackPacket[8] = ackPacket[8] + ackPacket[ubxi];
 ackPacket[9] = ackPacket[9] + ackPacket[8];
 }

while (1) {

// Test for success
 if (ackByteID > 9) {
 // All packets in order!
 return true;
 }

// Timeout if no valid response in 3 seconds
 if (millis() - startTime > 3000) {
 return false;
 }

// Make sure data is available to read
 if (Serial.available()) {
 b = Serial.read();

// Check that bytes arrive in sequence as per expected ACK packet
 if (b == ackPacket[ackByteID]) {
 ackByteID++;
 }
 else {
 ackByteID = 0; // Reset and look again, invalid order
 }
 }
 }
}

So there you go that’s the module in Dynamic Model 6 – Airborne < 1g which is generally the one you want for High Altitude ballooning. If your application is rocketry there is mode 8 – Airborne < 4g. Its quite viable to drop back to mode 3 – Pedestrian when below 9km in altitude. The airborne modes have large positional deviation, whereas the pedestrian modes have small deviation. Airborne modes are still perfectly accurate enough to locate a payload.

Ok so what next ? You have a choice at this point you can write a parser to read NMEA GNGGA strings to obtain your location information, you can use a prebuilt library that does this such as TinyGPS or finally you can use the UBX protocol to poll the module for information. I’ll discuss using UBX in the next article.

Getting started with Ublox Part 1 – Basic Operation of the Breakout Board

Ublox GPS modules are used heavily in HAB due to their high performance, altitude limit and power usage. They are extremely well documented. By default they output NMEA strings at 9600 baud but with a max altitude limit of 12km . There are a number of ways to communicate with the module NMEA, PUBX or the binary UBX protocol.

For these examples we are going to use a HAB Supplies uBLOX MAX-M8Q Breakout With Quad-V Antenna for Arduino linking to an Arduino Duemilanove.

Basic Operation Test
arduino_exampleConnect as follows :

Arduino 5V to GPS Board 5V
Arduino GND to GPS Board GND
Arduino Pin 0 (RX) to GPS Board RX
Arduino Pin 1 (TX) to GPS Board TX
Arduino Pin 2 to GPS Board EN

Load the following sketch. All this does is turn the level convertor on the GPS Board so data from the GPS module is passed through to the Arduinos USB to Serial port.


#define GPSENABLE 2

void setup() {
 pinMode(GPSENABLE, OUTPUT);
 digitalWrite(GPSENABLE, HIGH);
}

void loop() {
}

Once loaded press the serial monitor button in Arduino and you should see NMEA strings being output :

arduino_example2If you stick the module in a window or outside you should start to see a clock and then actual location information. At this point if you’re a Windows user you can go download the Ublox U-Center. All the commands referenced in the following examples were obtained via U-Center. Close Arduino down, open U-Center and point it at the Arduino’s COM port :

ucenter

Note the GLONASS Satellite (Russian flag). Ok so how do we use this to ascertain the commands we want to send to the GPS module to put it in high altitude mode.

In Ucenter click View -> Messages.

Click the + next to NMEA to collapse it and then click the + next to UBX to expand it. Click + next to CFG to expand. UBX-CFG is where most of the configuration commands for the Ublox modules are located. All these commands are covered in extreme detail in the Ublox Receiver Description Including Protocol Specification.

However I’ll advise the setting to enable operation above 12km is down UBX-CFG-NAV5. Click NAV5. If you drop the dynamic model box down from the default 0 – Portable mode to 6 – Airborne < 1g you will notice the table at the bottom kindly gives the binary string you need to send to the module to enable this mode :


0000 B5 62 06 24 24 00 FF FF 06 03 µb$$ÿÿ
000A 00 00 00 00 10 27 00 00 05 00 '
0014 FA 00 FA 00 64 00 2C 01 00 3C úúd,<
001E 00 00 00 00 C8 00 00 00 00 00 È
0028 00 00 1A 28

So basically we need to send this to the GPS module and check it acknowledges it. This is discussed in Part 2 of this article.

 

Not quite 5 minute guide to making an NTP Server

THIS ARTICLE HAS BEEN DEPRECIATED AND INSTRUCTIONS CONTAINED BELOW NO LONGER WORK WITH LATEST RASPBIAN. HOWEVER GOOD NEWS – ITS MUCH EASIER NOW SEE HERE:

https://ava.upuaut.net/?p=951

This is an article on making a network attached Stratum 1 NTP Server using a Raspberry Pi+ Model 2 or 3 and the Uputronics Raspberry Pi+ GPS Expansion Board. If you need a standalone ready to go solution or need more performance please consider the LeoNTP Networked Time server unit which is available here.

As of May 2016 this was heavily reworked due to a new version of Raspbian which did all sorts of wonderful things like disabling the serial ports etc. This guide assumes Raspbian Jessie Lite June 2017 2017-06-21. No other version or distribution is supported.

I’ve also removed the off grid/standalone instructions as NTP isn’t designed to work off grid using just the NMEA derived time and PPS to discipline it.

HAB Supplies Raspberry Pi+ GPS Expansion Board

Uputronics Raspberry Pi+ GPS Expansion Board

Ideally rather than supplying a premade image I would have a set of concise instructions on making your own install from scratch so you could use the latest versions of the software. With assistance from David Taylor who did lots of background work on this here I present the following instructions on making a cheap PPS disciplined NTP Time server using one of the Raspberry Pi+ GPS boards sold on Uputronics.

The guide assumes you have a cursory knowledge of Linux, enough to install Raspbian and login should do.

You will need a Raspberry Pi 2 or 3 B+, the Uputronics Raspberry Pi+ GPS Expansion Board and a suitable GPS antenna.

This guide is assuming you’re using Raspbian Jessie Lite installed from the June 2017 image. Download and write this to an SD card (See http://www.raspberrypi.org/documentation/installation/installing-images/README.md). Other distributions may work but these instructions are known to work with Raspbian Jessie Lite.

Attach the Uputronics Raspberry Pi+ GPS Expansion Board to the Pi, insert the SD card, connect the antenna and network cable and boot the Pi up. Either connect locally or via SSH to the Pi. Follow the instructions carefully if you miss steps things won’t work.

Text in italics is what you type.
Text in red indicates editing inside a file.

Prerequisite Settings

sudo raspi-config
5 Interfacing Options
P2 SSH -> Would you like the SSH server to be enabled – YES (Recommended)
P6 Serial -> Login Shell (no) Hardware (yes)
Quit but no need to reboot at this point.

sudo nano /boot/config.txt
Add at the bottom :
# Allow the normal UART pins to work
dtoverlay=pi3-miniuart-bt
dtoverlay=pps-gpio,gpiopin=18
Save and Quit Nano.

sudo apt-get update
sudo apt-get dist-upgrade

sudo systemctl disable hciuart
sudo systemctl mask [email protected]

sudo apt-get install pps-tools
sudo apt-get install libcap-dev
sudo reboot

Verifying PPS Is Working

Ensure the GPS has a lock and the Green PPS LED on the Uputronics Pi+ GPS Expansion Board is blinking once a second.

dmesg | grep pps

Output should be similar to :

[ 2.443494] pps_core: LinuxPPS API ver. 1 registered
[ 2.446699] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti &lt;[email protected]&gt;
[ 2.471796] pps pps0: new PPS source pps.-1
[ 2.471886] pps pps0: Registered IRQ 498 as PPS source
[ 6.965166] pps_ldisc: PPS line discipline registered
[ 6.966569] pps pps1: new PPS source ttyAMA0
[ 6.966664] pps pps1: source "/dev/ttyAMA0" added

sudo ppstest /dev/pps0

Output should be similar to:

 trying PPS source "/dev/pps0"
 found PPS source "/dev/pps0"
 ok, found 1 source(s), now start fetching data...
 source 0 - assert 1418933982.998042450, sequence: 970 - clear  0.000000000, sequence: 0
 source 0 - assert 1418933983.998045441, sequence: 971 - clear  0.000000000, sequence: 0

(Press CTRL+C to quit). This indicates the PPS Module is loaded (top example) and is working (bottom).

GPS board mounted in Geaux Robot Dog Bone Case for Raspberry Pi B+ also available from HAB Supplies

GPS board mounted in Geaux Robot Dog Bone Case for Raspberry Pi B+ also available from Uputronics

Enabling PPS/ATOM Support in NTPD

The supplied version of NTPD on the Raspberry Pi doesn’t support PPS so we need to recompile it (Please note that some of these steps may take up to 30 minutes).

wget https://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-4.2.8p10.tar.gz
tar zxvf ntp-4.2.8p10.tar.gz
cd ntp-4.2.8p10
./configure  –enable-lcap
make -j4
sudo make install
sudo service ntp stop
sudo cp /usr/local/bin/ntp* /usr/bin/ && sudo cp /usr/local/sbin/ntp* /usr/sbin/
sudo nano /etc/ntp.conf

Add
server 127.127.22.0 minpoll 4 maxpoll 4
fudge 127.127.22.0  flag3 1  refid PPS

Amend

server 0.debian.pool.ntp.org iburst prefer

You may also want to add your local lan to so you can query the NTP Server by adding:
restrict 192.168.1.0 mask 255.255.255.0

Note You MUST add a preferred server or PPS doesn’t work. Its worth at this point seeing if you’re ISP has its own NTP server you can use and adding that but for the purposes of this exercise adding prefer to the Debian pool one will do.

Save and close nano.

sudo nano /etc/init.d/ntp
Find the line NTPD_OPTS=”$NTPD_OPTS -u $UGID”
Amend it to say NTPD_OPTS=”$NTPD_OPTS”

sudo systemctl daemon-reload

sudo service ntp restart

After a few minutes run

ntpq –p

if you get oPPS(0) this indicates source selected, Pulse Per Second (PPS) used and everything is working.

If you aren’t seeing the settings its possible the NTP server is picking up the NTP information via DHCP which is over riding your settings above. Do this :

rm /etc/dhcp/dhclient-exit-hooks.d/ntp
rm /var/lib/ntp/ntp.conf.dhcp

At this point you have a NTP server which will use an external time source and use your local PPS to discipline it.

Setting Stationary Mode

Grab this small program code here : https://pastebin.com/YTc9Nd3D
Compile + link:

gcc -o gpsControl gpsControl.c

sudo ./gpsControl -p -d /dev/ttyAMA0 = Portable Mode
sudo ./gpsControl -s -d /dev/ttyAMA0 = Stationary Mode

May take a few goes to set it.

pi@hypatia:~ $ sudo ./gpsControl -s -d /dev/ttyAMA0
Set GPS for stationary mode
Configuring device /dev/ttyAMA0
>>>>>>>>>>>>>>>>>>>>> SENDING >>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> SENDING >>>>>>>>>>>>>>>
GPS mode set OK

Static IP + Hostname

If you want to fix your LAN IP you do it by amending /etc/dhcpcd.conf adding the following lines:

interface eth0
static ip_address=192.168.1.7/24
static routers=192.168.1.254
static domain_name_servers=8.8.8.8 8.8.4.4

Amend your hostname by editing /etc/hostname and then adding this to /etc/hosts as well. I.e if you call your machine ‘eleanor’ add this after localhost in /etc/hosts:

127.0.0.1 localhost eleanor

Further Reading

David Taylor’s website here http://satsignal.eu/ntp/Raspberry-Pi-NTP.html goes into much further detail about the process above and covers graphing, remote access monitoring etc and I highly recommend you read it.

References from this draft document by Eric S. Raymond https://www.ntpsec.org/white-papers/stratum-1-microserver-howto/

Hope this helps, let me know how you get on with these instructions and I’ll try keep them up to date.

Thanks to:

David Taylor
Dave Akerman
Chris Stenton for the new kernel fix.
Tris Mabbs for the DHCP issue heads up.
Michiel Kanis for testing DHCP fix.
Phil Heron for the GPSD Autostart fix.

Updated : 27/06/17 Fixed for new June 2017 Raspbian. Updated links to ntp-4.2.8p10.
Updated : 25/05/16 Fixed for Pi3/May Raspbian. Removed Standalone mode (NTP isn’t designed for this)
Updated : 22/03/16 Added Pi3/Standalone etc
Updated : 24/02/16 Added Code to set stationary mode.
Checked : 29/09/15 Works with Raspian Jessie – Thx Ciaran!
Updated : 03/07/15 NTP version and location amended – Thx Greg!
Checked : 13/06/15 Works with 2015-05-05-raspbian-wheezy.img
Updated : 13/04/15 ntp-4.2.8p2.tar.gz links updated.
Updated : 23/02/15 Verified these instructions are good with 2015-02-16-raspbian-wheezy.img as a base
Updated : 20/02/15 ntp-4.2.8p1.tar.gz links updated.
Updated : 28/01/15 DHCP Client can pick up NTP from DHCP server and override all your good work. See below.
Updated : 27/01/15 New kernel breaks previous instructions. Updated.
Updated : 26/12/14 Updated NTP to 4.2.8 and tested with Raspbian 2014-12-14