Setting the RPi System Clock via GPS

I am still learning and experimenting with the Adafruit Ultimate GPS HAT and the Raspberry Pi 2 Model B.  While I have the GPS tied into the system now, it doesn’t appear that the Raspbian NTP service is handling the GPS, at least without an active internet connection (in which case, NTP is using the NTP servers, not the GPS).  With the internet disconnected, every time I start up the RPi, the GPS is functioning, but cgps shows an ever increasing difference between the GPS time and the system time, because the system time is not updating.

I’ve tried several approaches to get NTP working with just the GPS, but so far, no joy.  I clearly have more learning to do.  (And that’s not even trying to get things synchronized to the 1PPS signal, which is another issue entirely).

That said, the system “date -u” (UTC set) command can be used to set the system clock, after fetching the UTC time from the gps and converting it into the required string format.

Here is a small Python program called gpsutcset.py that can be executed from the command line that will read the time from the GPS, build a string that is properly formatted, and invoke the OS date -u command to set the UTC time.

import os
import sys
import time
from gps import *

print 'Set System Clock to GPS UTC time'

try:
  gpsd = gps(mode=WATCH_ENABLE)
except:
  print 'ERROR: No GPS Present, time not set!!'
  sys.exit()

while True:
  #wait until the next GPSD time tick
  gpsd.next()
  if gpsd.utc != None and gpsd.utc != '':
    #gpsd.utc is formatted like"2015-04-01T17:32:04.000Z"
    #convert it to a form the date -u command will accept: "20140401 17:32:04"
    #use python slice notation [start:end] (where end desired end char + 1)
    #   gpsd.utc[0:4] is "2015"
    #   gpsd.utc[5:7] is "04"
    #   gpsd.utc[8:10] is "01"
    gpsutc = gpsd.utc[0:4] + gpsd.utc[5:7] + gpsd.utc[8:10] + ' ' + gpsd.utc[11:19]
    os.system('sudo date -u --set="%s"' % gpsutc)
    sys.exit()

Assuming that python code is stores in the /home/pi directory, then simply typing “python /home/pi/gpsutcset.py” will do the trick.  Or that gpsutcset function can be added to the /etc/rc.local file after the gpsd daemon start up like this:

sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock
python /home/pi/gpsutcset.py
This entry was posted in Raspberry Pi, Satellite, Tracker. Bookmark the permalink.

10 Responses to Setting the RPi System Clock via GPS

  1. Dan says:

    Thanks for posting about this script. I’m flying a high altitude balloon project with my students this weekend and needed to set the system clock using our gps unit (no internet at 90,000 ft!). This worked great!

    • robert says:

      Hi Dan,

      How fantastic! I certainly hope your balloon experiment goes well for you and your students. I’d love to know how it turns out and what data you are gathering? (Simply logging GPS location data, or adding some other items). A friend of mine is considering doing a balloon experiment at his STEM middle school.

      We never did cool things like that when I was in school

      73, Bob, WB4SON

  2. Matt says:

    How would I have to modify this to have my time set to UTC -4 (Eastern US time)?

    • robert says:

      Usually the OS on a RPi is configured to be UTC. That said, the GUI is often configured to be your actual time zone, so both times exist.

      I was interested in UTC time because that is required for all the satellite tracking software, and is independent of things like Daylight Saving Time. Makes life much easier.

      Given how this plugs into the NTP services, I would think you would keep it as UTC and simply let the OS deal with EDT/EST as necessary (that’s the purpose of all the LINUX Localization settings).

      • Matt says:

        Robert,

        That makes perfect sense- having said that, and I am still a bit of a script fetus here, I had your python script working beautifully, worked everytime, I even had it run @boot in /etc/rc.local. So I decided to re-create what I had done on a different SD card. Now I get this error every time- I’ve researched and tried debugging but I am at a loss, and hoping you have seen it before and know the fix. If not, no worries.

        Here is the feedback.

        Set System Clock to GPS UTC time
        Traceback (most recent call last):
        File “/home/pi/setutc.py”, line 16, in
        gpsd.next()
        File “/usr/lib/python2.7/dist-packages/gps/gps.py”, line 326, in next
        if self.read() == -1:
        File “/usr/lib/python2.7/dist-packages/gps/gps.py”, line 316, in read
        self.unpack(self.response)
        File “/usr/lib/python2.7/dist-packages/gps/client.py”, line 145, in unpack
        raise json_error(buf, e.args[0])
        gps.client.json_error

        Thank you in advanced.

  3. Bill says:

    To test my Garmin GPS I attached it via its USB to the pi, booted then found the Garmin at ttyUSB0. (Zero) But when I ‘sudo cat /dev/ttyUSB0 ‘ the command line curser moves to the next line and hangs there. Garmin GPS runs at 4800 baud, how do I check and change the baud rate in the Pi ?

    Should I instead use a GPS serial output on the Pi Console Port ?

    • robert says:

      Hi Bill,

      I certainly am not an expert on Garmin GPS units. I presume you are hoping that sudo cat /dev/ttyUSB0 will open that connection and display any output on the console. I expect that you are correct, that there is a baud rate mismatch, as the default baud rate for the RPi is 11520, if I recall correctly. The other issue is that some models of the RPi (you didn’t specify) use the only “real” serial port for the console, and simulate another port for hardware connection. I would suggest that you check out some of the excellent online resources concerning the RPi serial ports. As to your final question, you could use the Console Port, but you would have to disable all the services that default to using that port — for example all the boot time messages (and there are hundreds of them as the OS loads). You would be far better off using the USB connection and figuring out what you need to change.

      Good luck & 73, Bob, WB4SON

  4. Isaac Newton says:

    Hi Robert,
    Thanks for your simple and fast solution! I’ve implemented it within a few minutes with my RPi 3B+ with Uputronics GPS expansion board. The RPi runs ntpd and allows machines in an isolated network segment to set their clocks accordingly.
    It still shows stratum values of 16 only with 1 or 2 possible but the accuracy of about +/-1 second is better than the minutes differences we do currently have. For all better accuracy we’ll have to use the 1PPS signal properly.

  5. G Utz says:

    Bob,
    Thanks for the GPS / System Clock Python code and /etc/rc.local start script.
    I generally work CW as a Parks on the Air activator but it appears that some POTA field activators are now using FT8.
    I’m planning to experiment with my PI4 and FT8 in the field so an offline, accurate system clock is essential.
    Best regards Gary KE2YK

    • Bob Beatty says:

      Hi Gary,

      Good luck with FT8 in the field. I’ve found that setting my clock at home, then not rebooting the laptop while traveling to a local park tends to keep things pretty tight on, but no doubt it will drift over time. I’ve only worked a few POTA folks on FT8. Right now, not that many on at all. I know I’m waiting for cooler fall days to get back to the parks here in RI, and want to do another 10 before year end.

      Thank you for the activations & 73
      Bob

Leave a Reply

Your email address will not be published. Required fields are marked *