Connecting u-blox NEO-6M GPS to Raspberry Pi

Previously, I connected a u-blox GPS to an arduino and got it functioning. Today I connected it to my Raspberry Pi, got the GPS daemon running, figured out how to get GPS information from the command line, and finally made the GPS an NTP clock source for the RPI.

Connecting the Hardware

I am working with a u-blox NEO-6M GPS like this:

which I purchased from for a mere $28.

I chose to connect the GPS to the RPI (Raspberry Pi) using a USB port. It is possible to connect it to the RPI’s serial port, but this is more complicated and has some risk associated with it. If you want to use the serial port, instructions are easy to come by. If I were going to permanently connect the GPS to this RPI, then I might consider using the serial port.

To use a USB port, you need an FTDI cable like this one:

The pinout for the FTDI cable is:

Interconnecting the FTDI cable to the GPS is easy:

FTDI Color        GPS Pin
Black(GND)        GND
Yellow(RX)        TX
Orange(TX)        RX
Red(VCC)          VCC

Before I connected the USB cable to the RPI, I typed the two following commands to find the current USB devices connected to the RPI:

ls /dev/ttyUSB*

I then connected the USB cable to the RPI which caused it to reboot (don’t know if that is normal, but it has happened both times I have done so). Once the cable was connected to the RPI had rebooted, I typed the status commands again to verify that the GPS was now showing up:

# lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
# ls /dev/ttyUSB*
crw-rw---T 1 root dialout 188, 0 Dec 31  1969 /dev/ttyUSB0

The lines in bold font are new after connecting the GPS. The GPS is connected to device /dev/ttyUSB0.

Further you can see the output of the GPS by doing the following:

#sudo cat /dev/ttyUSB0

You have now verified the connection to the GPS has been established.

Installing the GPS Daemon

The GPS daemon, gpsd, reads the output from the GPS and makes it available to the rest of the system.

I found good information on the gpsd daemon here:

To install the daemon and client utilities do the following:

sudo apt-get update
sudo apt-get install gpsd gpsd-clients

After reading through many different docs on installing gpsd (and having some issues) I have found that you will also want to do the following, especially if you want to use the GPS with NTP, so that the GPS always starts when the system reboots:

type the following command:

sudo dpkg-reconfigure gpsd

For each prompt, answer as:

start gpsd automatically: yes
Should gpsd handle attached USB receivers automatically: yes
Device the GPS receiver is attached to: <leave blank>
Options to gpsd: -n /dev/ttyUSB0
gpsd control socket path: <use default>

By placying the device name in the options field, you will get the GPS to start properly at bootup.

Type the following to verify the options were sent to gpsd correctly:

# ps aux | grep gpsd
nobody     357  9.3  0.4  13168  1904 ?        S<sl 16:38   3:45 gpsd -n /dev/ttyUSB0 -F /var/run/gpsd.sock

If you aren’t going to use NTP and just want to experiment, then you can start gpsd like this:

gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock

To verify gpsd is working properly you can type:

cgps -s
|    Time:-------2015-01-18T01:25:41.000Z---||PRN:   Elev:  Azim:  SNR:  Used: |
|    Latitude:    00.0000   N               ||   2    06    312    00      Y   |
|    Longitude:  000.0000   W               ||   3    24    182    28      Y   |
|    Altitude:   582.0 m                    ||   6    07    271    00      Y   |
|    Speed:      0.1 kph                    ||   7    39    254    26      Y   |
|    Heading:    0.0 deg (true)             ||   8    33    059    35      Y   |
|    Climb:      n/a                        ||   9    65    302    29      Y   |
|    Status:     3D FIX (7 secs)            ||  10    35    301    37      Y   |
|    Longitude Err:   +/- 1 m               ||  16    56    082    43      Y   |
|    Latitude Err:    +/- 2 m               ||  20    46    223    34      Y   |
|    Altitude Err:    +/- 5 m               ||  23    80    110    40      Y   |
|    Course Err:      n/a                   ||  27    10    116    22      Y   |
|    Speed Err:       +/- 18 kph            ||                                 |
|    Time offset:     0.597                 ||                                 |
|    Grid Square:     DN17hq                ||                                 |

You can also see a nicer version of cgps if you are running X windows on RPI by running xgps:


Accessing GPS Provided Data

Information for accessing the gpsd daemon via C can be found here:

I am really just interested in extracting locational information at the shell, at least for the moment.

One of the utilities in the gpsd-clients package is gpspipe. This allows you to capture GPS information that is being transmitted by the GPS. More detailed information on this utility can be found here:

Using gpspipe, you can capture the next locational data packet transmitted by the GPS:

gpspipe -w -n 30 | grep -m 1 lat

This is a bit messy, but could be cleaned up with something like SED to return, say, just the latitude and longitude.

I decided to follow a different tack and install jq, a program for manipulating the json data being output by gpspipe. To install jq on RPI (I could find no package to install, so you have to manually compile):

curl -O
tar xfvz jq-1.3.tar.gz
cd jq-1.3
make install

After make install, I swear I saw jq copied to /usr/bin, but it wasn’t there so I also had to

sudo cp jq /usr/bin

Now using jq to see the full packet:

gpspipe -w -n 30 | grep -m 1 lat | jq '.'
  "eps": 3.96,
  "climb": 0,
  "speed": 0.031,
  "track": 0,
  "epv": 5.989,
  "epy": 1.981,
  "epx": 1.726,
  "alt": 584,
  "class": "TPV",
  "tag": "GLL",
  "device": "/dev/ttyUSB0",
  "mode": 3,
  "time": "2015-01-17T21:08:56.000Z",
  "ept": 0.005,
  "lat": 00.000000,
  "lon": 00.000000000

To see just latitude:

# gpspipe -w -n 30 | grep -m 1 lat | jq '.lat'

and latitude and longitude:

# gpspipe -w -n 30 | grep -m 1 lat | jq '. | {lat,lon}'
  "lon": 000.000000
  "lat": 00.0000000


gpspipe -w -n 30 | grep -m 1 lat | jq '.lon,.lat'

to get both items on the same line:

echo $(gpspipe -w -n 30 | grep -m 1 lat | jq '.lat') $(gpspipe -w -n 30 | grep -m 1 lat | jq '.lon')
00.000000 000.0000000

and, lastly, to create a URL to google maps:

echo ''$(gpspipe -w -n 30 | grep -m 1 lat | jq '.lat')','$(gpspipe -w -n 30 | grep -m 1 lat | jq '.lon'),000.00000

Using the GPS as an NTP Clock Source

I spent more time learning the ins and outs of NTP for this project that I would have expected, though just scratched the surface. It turns out using a navigation GPS such as this u-blox NEO-6M isn’t considered very accurate. In general, NTP will prefer using an internet based clock over the GPS unless you account for the GPS latency (my word).

To use a GPS as a really accurate clock, you need one that provides a PPS (pulse per second) signal. This is a highly accurate clock pulse coming off a pin on the GPS that NTP can use. If you have such a GPS the resource below is a must read.

Perhaps using a nav GPS on an RPI won’t result in a super accurate clock, but that’s OK for my purposes. If I’m putting a GPS on an RPI, it is because I don’t have an internet connection to begin with so as long as the clock is right within a few seconds, I’m OK with that. And in my testing, I seem to have no trouble achieving that.

In learning about using GPS as a clock source, I also stumbled across DCF77 . This is the radio based the signal that many clocks now use to keep set accurately. They have the advantage of being able to work w/o needing clear view to the sky. I may have to play with one of those some day.

Here is a good source on setting up NTP to use a GPS:

GPSD Time Service HOWTO

In this procedure, I’m going to first get the GPS running as the only clock source for the RPI. Then I’ll use internet based clock sources to adjust its accuracy to be pretty good.🙂

Configuring the GPS as the Only Clock Source

First, to get NTP to see your GPS, make sure you use dpkg-reconfigure gps as outlined earlier.

This is the minimum /etc/ntp.conf file you need:

driftfile /var/lib/ntp/ntp.drift

#pool iburst

# GPS Serial data reference
fudge refid GPS

# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict ::1

I would suggest renaming your current ntp.conf file to something like ntp.conf.old, and then creating the file above. Once you have the GPS providing time properly, then make the necessary changes to the original file and put it back into position.

Note that the pool command is commented out. There should be no pools nor servers except for server for the time being.

Type service ntp restart to restart ntpd and load in the new ntp.conf file.

At this point, ntpd and gpsd should both be running and gpsd must be running with the -n /dev/ttyUSB0 option as outlined above.

Use ntpq -p to see the clock source and the date command to verify the current date/time:

root@rpi:/etc# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
*SHM(0)          .GPS.            0 l    4   64  177    0.000   -0.890   1.381
root@rpi:/etc# date
Sun Jan 18 11:13:23 PST 2015

You should see an asterisk (*) next to the SHM which indicates ntpd has selected it as the clock source. If it isn’t, wait a while. I normally see it get selected within a couple of minutes of restarting ntpd.

If when stays at ‘-‘, then ntpd is NOT talking to the GPS. The most likely culprit would be wrong options. Go back to the top of this procedure where I have you do a ps aux and make sure that process is working correctly.

On your PC, resync its clock to be sure it is accurate (mine updates only once every few days and in that time ends up being several seconds out of whack). Now compare the RPI date command to the PC’s clock. You should be within a second. In my testing,  at this point I’m usually 1 sec slower than the PC.

At this point, your RPI is using the GPS clock and is at most 1 second off. As I said before, I would usually be happy enough with this result; however, if you want to spend some ‘time’ calibrating the GPS clock, you can make it more accurate. The rest of this procedure outlines how I did that.

Increasing Accuracy of GPS Clock

If you really, really want an accurate clock, well, buy a GPS with a PPS pin. If you want to do the best possible without a PPS pin, wade thru the GPSD Time Service HOWTO document – he will show you how to use statistics to get the clock really accurate.

I short-circuited his work into a pretty quick and easy process. Not as accurate, but way more accurate than the default configuration.

In this procedure, I will bring up 4 internet clock sources and make the GPS  a stratum 10 device. This will force ntpd to pick one of the internet clock sources. We’ll then use the reported offset for the GPS to correct its latency.

Assuming you are using the ntp.conf file outlined above, uncomment the pool command,  and add stratum 10 to the GPS fudge command:

pool iburst
 fudge stratum 10 refid GPS

By the way, if you aren’t in the US, drop the us. part of the pool DNS so it just reads

Here is the ntp.config that I am using:

driftfile /var/lib/ntp/ntp.drift
 pool iburst
 # GPS Serial data reference
 fudge stratum 10 refid GPS
 # By default, exchange time with everybody, but don't allow configuration.
 restrict -4 default kod notrap nomodify nopeer noquery
 restrict -6 default kod notrap nomodify nopeer noquery
 # Local users may interrogate the ntp server more closely.
 restrict ::1

Now use service ntp restart to restart the ntp daemon:

root@rpi:/etc# service ntp restart
[....] Stopping NTP server: ntpd.
[....] Starting NTP server: ntpd.

Give ntpd a few seconds, then:

root@rpi:/etc# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
 clock.xmission. .STEP.          16 u   15   64    0    0.000    0.000   0.001
 leeloo.scurvyne .STEP.          16 u  803   64    0    0.000    0.000   0.001
 bindcat.fhsu.ed    2 u    -   64    1   84.484  154.288   0.001     2 u    -   64    1   40.873  161.477   0.001
 SHM(0)          .GPS.           10 l    -   64    0    0.000    0.000   0.001

You should have 4 internet clock sources as well as your GPS and the stratum column (st) should have a 10 for the GPS.

Pretty quick ntpd should select a clock source other than the gps:

root@rpi:/etc# ntpq -p
      remote           refid      st t when poll reach   delay   offset  jitter
 *clock.xmission. .GPS.            1 u    5   64    1   55.014  161.233   1.838
  leeloo.scurvyne .STEP.          16 u  822   64    0    0.000    0.000   0.000
 +bindcat.fhsu.ed    2 u    9   64    1   94.084  159.134   3.526
 +     2 u    9   64    1   45.071  163.592   3.034
  SHM(0)          .GPS.           10 l   19   64    0    0.000    0.000   0.001

and eventually (roughly 10 minutes) the GPS will get a large negative offset like this:

 root@rpi:/etc# ntpq -p
      remote           refid      st t when poll reach   delay   offset  jitter
 +leeloo.scurvyne    2 u   33   64  377   89.977  -130.58  51.517
 *bindcat.fhsu.ed   2 u   45   64  377   88.215  -123.77  48.948  2 u   33   64  377   81.806  -118.99  52.617    3 u   31   64  377   91.499  -128.05  53.169
 -SHM(0)          .GPS.           10 l   25   64  377    0.000  -275.17  46.395

Now you just need to wait for a few hours for ntpd to get everything caught up. I waited about 4 hours at which point I had:

root@rpi:/etc# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
+leeloo.scurvyne    2 u  379 1024  377   90.041   -7.182   3.263
*bindcat.fhsu.ed    2 u  904 1024  377   86.614   -3.981   0.765  2 u  872 1024  377   80.314    3.298   4.451    3 u  361 1024  377   86.176   -2.557   3.516
xSHM(0)          .GPS.           10 l    7   64  377    0.000  -150.36   1.312

Note that the offsets to the internet clocks are now fairly small. Only the GPS offset is high. This offset is how slow the GPS clock signal is millisecs. Once the GPS offset stabilizes you can use that in the fudge command to adjust the GPS:

fudge time1 0.150 refid GPS

In the fudge command, I have removed stratum 10 (allowing it to return to 0) and sped the clock up 150ms. This should be accurate enough that ntpd will select the GPS as the primary clock.

Restart the ntpd service, and give ntpd time to settle:

Upon checking immediately after the restart, ntpd had not select the GPS:

root@rpi:/etc# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
+mirror       2 u   31   64    1   67.428    0.907   1.677
+ccadmin.cycores  2 u   30   64    1   91.994   -0.196   1.352
-tarkin.widezero       2 u   29   64    1   64.706   -3.979   0.743
*oxygen.neersigh    2 u   28   64    1   33.742    0.024   1.063
-SHM(0)          .GPS.            0 l   37   64    1    0.000   -1.474   0.001

But after about 5 minutes it had:

     remote           refid      st t when poll reach   delay   offset  jitter
-mirror       2 u   45   64  177   69.304    0.610   1.715
+ccadmin.cycores  2 u   44   64  177   91.994   -0.196   2.336
-tarkin.widezero       2 u   47   64  177   64.699   -4.549   2.596
+oxygen.neersigh    2 u   40   64  177   33.742    0.024   0.908
*SHM(0)          .GPS.            0 l    -   64  377    0.000   -1.023   2.205

Comparing RPI’s Time to a Timer Server

To determine how accurate your clock is, you can use ntpdate. RPI does not have this installed by default, so you will need to install it:

sudo apt-get install ntpdate

Now just use ntpdate against a real time server. I use

root@rpi:/etc# ntpdate -d
19 Jan 10:08:18 ntpdate[3909]: ntpdate 4.2.6p5@1.2349-o Sat Dec 20 21:34:03 UTC
2014 (1)
server, port 123
stratum 1, precision -29, leap 00, trust 000
refid [ACTS], delay 0.08333, dispersion 0.00107
transmitted 4, in filter 4
reference time:    d867c68f.0e3b967b  Mon, Jan 19 2015 10:08:15.055
originate timestamp: d867c698.3f15ba89  Mon, Jan 19 2015 10:08:24.246
transmit timestamp:  d867c698.3630df01  Mon, Jan 19 2015 10:08:24.211
filter delay:  0.08577  0.08333  0.08643  0.08533
         0.00000  0.00000  0.00000  0.00000
filter offset: 0.004816 0.003681 0.005342 0.004880
         0.000000 0.000000 0.000000 0.000000
delay 0.08333, dispersion 0.00107
offset 0.003681

19 Jan 10:08:24 ntpdate[3909]: adjust time server offset 0.003681 sec

On the last line, the offset indicates the difference in time between the RPI’s clock and the time server. In this example, it is 3.681ms. Pretty darn close!

Reconciling the NTP Configurations

At this point you have the GPS configured properly for NTP. You can copy the server commands:

# GPS Serial data reference
fudge time1 0.150 refid GPS

to your old ntp.conf file and reinstall it. If you don’t intend to use internet based clocks you can remove the pool command or any other server commands you might have.



This entry was posted in c-rpi and tagged , . Bookmark the permalink.

8 Responses to Connecting u-blox NEO-6M GPS to Raspberry Pi

  1. Pingback: GPS GY-NEO6MV2 en la Raspberry Pi | Carlini's Blog

  2. Amol P says:

    Cool project. I want to use this GPS module too. Have you made any new project with it?

  3. Alexis says:

    Thanks for this valuable info.
    The line “sudo dpkg-reconfigure gps”
    Worked like this for me: “sudo dpkg-reconfigure gpsd” (an extra ‘d’ at the end)

  4. Ernesto says:

    thanks by share! your information has been realy helpfull!

  5. BOZ says:

    Have you tried using pin 3 of the ublox chip? It has PPS apparently.
    I am looking for a way to keep the time without having GPS on all the time.
    Do you think it would be posible to use the PPS time to set a Real Time Clock which is connected to the raspberry pi’s I2C?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s