gpsd notes


I’ve tried reconnecting an old GPS module to the UART pins on my raspberry pi, but it seems it’s not able to get a satellite fix.

I’ve had troubles trying to get gpsd started, but I’m able to test the connection with gpsmon. It seems capable of parsing data from the serial connection, but not a single satellite is ever seen.

Then I tried looking at the raw data using the commands

To set it to 9600 baud: stty -F /dev/serial0 9600

To print out the data: cat /dev/serial0

What I got back doesn’t look quite right to me. Here’s an excerpt:

[0x01][0x1B][0x0F][0x1F][0x0C] ÿÿÿÿ$GPGSA,A,1,,,,,,,,,,,,,,,*1E



[0x01][0x1B][0x0F][0x1F][0x0C] ÿÿÿÿ$GPRMC,054305.099,V,,,,,0.00,0.00,220519,,,N*47

A^X^O^_^L ÿÿÿÿ$GPGGA,054305.099,,,,,0,00,,,M,,M,,*7F



A^X^O^_^L ÿÿÿÿ$GPGGA,054305.099,,,,,0,00,,,M,,M,,*7F



A^X^O^_^L ÿÿÿÿ$GPGGA,054305.099,,,,,0,00,,,M,,M,,*7F


I’ve replaced control characters with their hex codes in [] brackets.

Is this normal, have I used incorrect settings, or does it mean the GPS module is faulty?


This is the module in question: https://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi/

Using an external antenna (placed ~1m away from the pi).


Nearly 48 hours later, I have checked on things, having been left as they were when the question was first posed. I hadn’t received any fix within 3 hours which prompted me to make the post.

Sometime since, the GPS module appears to have started working as expected. The odd ascii/control characters are no longer present in the serial output. The GPS now has a fix, and is seeing 6 – 9 satellites.

I don’t have an explanation for how it has recovered.

Perhaps it was RF noise as suggested by Dougie , but for that to be true, it would mean that the TV I was using for display output (3m away) would have been causing the interference as nothing else is nearby that has changed (powered/unpowered) over the duration. The PI’s wifi has been enabled throughout. I have tried testing whether power cycling the TV has any effect on the GPS reception by monitoring the serial output and it does not look like there is any effect.

It could have been ESD suggested by Dmitry Grigoryev, although if that were true then I guess leaving the antenna charged would have caused it, which dissipated over time, leaving no lasting damage? Is this possible?

It was stored in a dry place (heated indoors), but I can’t rule out moisture damage as I live in a very humid area. Could keeping it powered up, have warmed it up, leading to to evapouration, removing electrical interference?

My other conclusion is that giving it a restricted view (still a good chunk of sky – around 1/3rd), caused it to miss a lot of updates, making a cold start take much, much longer than expected? This wouldn’t explain the corruption seen in the serial output though, would it?

  • 1
    Does the GPS unit have a clear sky view? – joan May 22 at 8:38
  • The NMEA sentences you’re getting appear valid. There’s just a lot of noise in with your signal. How is your GPS connected to your RPi, how long is the cable? – Dougie May 22 at 9:50
  • The following youtube might give you some tips -Troubleshooting the Adafruit Ultimate GPS When Not Getting a Fix 11,156 views youtube.com/watch?v=LtqVrwwVfGY – tlfong01 May 22 at 13:41   
  • @joan It’s located directly (in contact) with a window. It has a visibility of an estimated 33% of the sky. I’ve used the location before with success when the GPS module was new. – Rob May 24 at 7:36
  • @Dougie The cable is about 10cm-15cm long, using a raspberry pi breadboard breakout.– Rob May 24 at 7:41

2 Answers


Those UART GPS modules often have quite poor reception, so you will only get a fix with a clear sky view. Not inside your house, not just out of the window, not on a lawn right next to your house, not under the trees. Additionally, such modules rely on the GPS signal to get the GPS constellation data, which is very slow and can take several minutes. The worst of such modules won’t store the constellation data anywhere, so every time you power down the module, getting a fix will again require several minutes.

Additionally, even if the module talks to your UART correctly, it doesn’t mean it’s not damaged. For example, you could have killed the amplifier with ESD by touching the antenna. If the module doesn’t get a fix under a clear sky in ten minutes or so, I would bin it and get a new one.



  1. Tried reconnecting GPS module to Rpi UART, not able to get a fix, …
  2. Trouble trying to get gpsd started, able to test the connection with gpsmon, …
  3. Raw data normal, GPS module fried?

Short Answer

  1. Well, to get a fix, you don’t need the GPS module connected to Rpi UART. If you test with the Rpi UART disconnected from the GPS module, your chance of getting a fix will be at least 0.1% higher.
  2. Once you have gotten a fix, the little status blue LED should start blinking slowly, around once per second. If blue LED not blinking, that mean no fix yet.
  3. If there is no fix, you can still talk to the GPS module through UART, but a not fixed GPS module will only give you yesterday data, which is still useful any way, but of course not realtime GPS data.
  4. There are 101 reasons that you can not get a fix. Let me list one by one. The list of reasons is very long, so I will put it in the long answer below.

/ to continue, …

Long Answer

/ to continue, …

Research Notes

/ to continue, …


AliEXpress GPS + Beidou Dual mode positioning module ATK1218-BD ATK-S1216 -US$24

TaoBao dual GPS (GPS + BaiDu) Positioning Module ATK1218-BD ATK-S1216 – ¥98

Troubleshooting the Adafruit Ultimate GPS When Not Getting a Fix – Paul McWhorter 2015jun23, 11,180 views

gpsd — a GPS service daemon

How to read NMEA 1083 data over USB on Pi? – Rpi StackExchange 2017apr

Getting NMEA string from GPS module to your Raspberry PI B+ [duplicate] – Rpi StackExchange 2017jan

More serial ports [for GPS module]

The 6 Best Arduino GPS Modules 2018

SainSmart NEO-6M

Hobbypower Ublox NEO-7M


Gowoops Ublox NEO-6M

Readytosky Ublox NEO-M8N

Adafruit Ultimate Breakout

GPSD compatible modules

NMEA sentences

GPSD not getting a good fix- stackOverflow 2015apr

Using python with a GPS receiver on a Raspberry Pi – Mark Williams 2109jan

Adafruit Ultimate GPS HAT for Raspberry Pi A+/B+/Pi 2/Pi 3 – Mini Kit – US$45

AdaFruit Ultimate GPS Module Tutorial

AdaFruit GPS HAT Tutorial PDF File

AdaFruit GPS Tutorial, Schematic etc

GlobalTop Command Set

GlobalTop GPS chip datasheet

/ to continue, …


Appendix A – My GPS module blinking – YouTube

GPS Module Blinking

Appendix B – My GPS module setup

GPS module setup

Appendix C – My GPS Antenna setup

GPS Antenna setup

Fix times 2019may23hkt2100 – first fix = 8 minutes, followed by 14 sec, 24 sec, 25 sec, 1.24 min, 1.13 min, then 17 min no fix, end of fixing test.

Appendix D – GPS Antenna Location – 4 stories down the “well”

GPS location

Appendix D – GPS Fix Time Measurement at Rooftop Garden

I am going to test if GPS fixing is possible with huge motor generated EMI around.

GPS Fixed Time Measurement at Rooftop Garden with huge EMI motor nearby

Appendix E – GPS Fix Time Measurement with Antenna 1 metre out of window

I surprising found that even with the antenna just 1 meter out of the window, the fix time is regularly less than 1 minute. My quick and dirty conclusion is that it not necessary at all to try any fix at the rooftop garden, … 🙂

window 1 meter GPS fix test

Appendix F – 200VAC in 12V AC out switching PSU performance

I read that the power supply for GPS module should be very stable. So I used LiPo 11.2V power bank with heavy duty 2.5A 5V voltage regulator for testing. This morning I used a weak 200VAC in 12V 1A PSU and light LM2596 regulator to test again. I found fixing times very good: 1m43s, 35s, 20s, 9s, 14s.

My quick and dirty conclusion is that the PSU quality doen’t mater much. So from now on I will forget using LiPo battery bank and just use 200VAC in 12V out switching PSU.

using switching psu

Appendix F – Downloading gpsd

gpsd download

Appendix G – Fix time measurements by the window L corner, 0 cm from window

Now I am measuring fix time with antenna by the window very near to a L shape corner. I find average fix time around 5 minutes. So far so good. I am using 200VAC in, 12V DC out, regulated by LM2596 regulator and found no problem. So I will not be using any LiPo power bank in the coming tests.

fix time l corner

Appendix H – Fix time measurement – inside L corner 50cm from window

For antenna about 50 cm from window, first fix time decreases to 3 minutes (based on only one sample!)

Appendix I – Hot fix time 12 metres down a concrete walled well = avg 15 seconds

I again checked the hot fix times at the U position, 12 metres down the concrete walled well. I very surprisingly found that the hot fix times (powering off and then on) was about 15 seconds (only 4 or 5 samples)

U position fix time measurements

Appendix J – ATK1218-BD GPS Module Specification

TaoBao Risym ATK1218-BD (ATK-S1216) GPS/BD dual mode GPS module – ¥98 https://detail.tmall.com/item.htm?


  1. Chip = SkyTra S1216
  2. Module = ATK1218-BD (former ATK-S1216)
  3. Antenna = 3m active
  4. Speed = 4.8 kBaud ~ 230.4 kBaud
  5. Protocol = NMEA-0183
  6. Resolution = 2.5 mCEP
  7. Refresh rate = 1/2/4/5/6/10/20 Hz (Neo-6M = 5 Hz)
  8. Cold fix time = up to 29 seconds
  9. Sensitivity = -165 dBm
  10. Temperature = -40 deg C to + 85 deg C
  11. Dimension = 25mm * 27mm
  12. Antenna = IPX to SMA adapter
  13. Power off hot fix (in 30 minutes) = 1 few seconds (Neo-6M = 1 ~ 5 min)
  14. PPS status LED
  15. Backup battery
  16. DuPont 2.54mm male pin x 5 (STM32 Board compatible)

Appendix K – AdaFruit Rpi GPS HAT Schematic

Adafruit Rpi GPS HAT Schematic

Appendix L – Testing Rpi built in UART serial loopback and repeat send char

The repeat send char 0x55 TxD waveform

rpi serial repeat send char 0x55

# Rpi3B+ serial port loop back test v2.0 tlfong01 2019may27hkt2137 ***

# Rpi3B+ Raspbian stretch 9 (full version 2019april), IDLE python 3.5.3

# Program name = serial_loopback_2019may2702.py

# Description

# This program tests serial port loop back of
#   (1) Rpi built in UART/Serial Port, or
#   (2) USB/TTL Serial Adapter

# Rpi built in UART/Serial Port:
#   Devcie name = '/dev/serial0'
#   TxD = Rpi UART/serial port output pin = BCM GPIO pin #15  ( = Rpi 40 pin connector pin position #  8)
#   RxD = Rpi UART/serial port  input pin = BCM GPIO pin #16  ( = Rpi 40 pin connector pin position # 10)

# UART/TTL Serial Adapter/Cable ($ ls /dev/ttyUSB* to list USB/TTYserial port names)
#   Device name = '/dev/ttyUSB0'
#   Pins = Gnd, Tx, Rx, 3V3, 5V0 (3V3, 5V0 are power pins, for powering external devices) 

# Loopback hardwareware setup
#   Use a connecting wire / jumper wire / female to female DuPont connector to connect TxD pin to RxD pin

# Program execution example
# 1. Desktop GUI python 3 IDLE
#    Copy program to any directory under Rpi home directory, eg /home/python_programs  
#    File menu > save as > serial_loopback_2019may26x1.py (or Ctrl+S, or Ctrl+Shift+S)
#    Run  menu > run > run module (or F5)
# 2, Terminal mode
#    To add later

# Sample output
 RESTART: /home/pi/Python Programs/Python_Programs/test1200/serial_loopback_2019may2702.py 
        Begin serialPortLoopBack() [Remember to connect Tx to Rx!] , ...
        bytes written =  b'AT\r\n'
        bytes read    =  b'AT\r\n'
        End   serialPortLoopBack(), ...

from   time import sleep
import serial

# *** Setup serial port and set baud rate functions ***

def setSerialPortBaudRate(serialPort, baudRate):
    serialPort.baudrate = baudRate

# *** Serial port write and read bytes functions ***

def serialPortWriteBytes(serialPort, writeBytes):

def serialPortReadBytes(serialPort, maxBytesLength):
    readBytes = serialPort.read(maxBytesLength)
    return readBytes

def serialPortWriteWaitReadBytes(serialPort, writeBytes, maxBytesLength, waitSeconds):
    readBytes = serialPortReadBytes(serialPort, maxBytesLength)
    print('        bytes written = ', writeBytes) 
    print('        bytes read    = ', readBytes)
    return readBytes

# *** Test functions ***

def testSerailPortRepeatWriteBytes(serialPort, writeBytes, betweenBytePauseSeconds, repeatCount):
    print('       Begin repeatWriteOneByte(), ...')   
    for i in range(repeatCount):
        serialPortWriteBytes(serialPort, writeBytes)                
    print('       End   repeatWriteOneByte().')

def testSerialPortLoopBack(serialPort, writeBytes, maxBytesLength, waitSeconds): 
    print('        Begin serialPortLoopBack() [Remember to connect Tx to Rx!] , ...')
    serialPortWriteWaitReadBytes(serialPort, writeBytes, maxBytesLength, waitSeconds)     
    print('        End   serialPortLoopBack(), ...')

# *** Setup serial port and set baud rate ***

deviceName = '/dev/serial0' # For Rpi built UART/Serial (BCM GPIO pins 14, 15)
# deviceName = '/dev/ttyUSB0' # For USB/UART adapter/cable

serialPort0 = serial.Serial(port = deviceName,
        baudrate = 9600,
        parity = serial.PARITY_NONE,
        stopbits = serial.STOPBITS_ONE,
        bytesize = serial.EIGHTBITS,
        timeout= 1)

setSerialPortBaudRate(serialPort = serialPort0, baudRate = 9600)

# *** Main Tests ***

#Test serial port repeat write bytes ***
#testSerailPortRepeatWriteBytes(serialPort = serialPort0, writeBytes = b'0x55', \
#                               betweenBytePauseSeconds = 0.005, repeatCount = 200000000)

# Test serial loop back ***
testSerialPortLoopBack(serialPort = serialPort0, writeBytes = b'AT\r\n', maxBytesLength = 32, waitSeconds = 0.01)

# End

Appendix M – cgps and xgps results

cgps xgps results

Appendix N – Antenna in a a “well” of concrete walls

antenna in well

Appendix O – gpsd notes

GPSD Client Howto / How works – ctab

While GPSD project ships several library bindings that will hide the details of the wire protocol from you, you’ll understand the library APIs better by knowing what a wire-protocol session looks like. After reading this section, you can forget the details about commands and responses and attributes as long as you hold on to the basic logical flow of a session.

Your client library’s open function is going to connect a socket to port 2947 on the host your sensors are attached to, usually localhost. On connection, the gpsd daemon will ship a banner that looks something like this:

{“class”:”VERSION”,”release”:”2.93″,”rev”:”2010-03-30T12:18:17″, “proto_major”:3,”proto_minor”:2}

There’s nothing mysterious here. Your server daemon is identifying itself with information that may allow a client library to work around bugs or potential incompatibilities produced by upgrades.

To get data from the attached sensors, you need to explicitly tell the daemon you want it. (Remember that it’s trying to minimize the amount of time the devices are held open and in a fully powered state.) You do this by issuing a WATCH command:


This tells the daemon to watch all devices and to issue reports in JSON. It can ship some other protocols as well (notably, NMEA 0183) but JSON is the most capable and usually what you want.

A side effect of the WATCH command is that the daemon will ship you back some information on available devices.

{“class”:”DEVICES”,”devices”:[{“class”:”DEVICE”,”path”:”/dev/ttyUSB0″, “activated”:1269959537.20,”native”:0,”bps”:4800,”parity”:”N”, “stopbits”:1,”cycle”:1.00}]}

{“class”:”WATCH”,”enable”:true,”json”:true,”nmea”:false,”raw”:0, “scaled”:false,”timing”:false,”pps”:false}

The DEVICES response tells you what devices are available to the daemon; this list is maintained in a way you as the application designer don’t have to care about. The WATCH response will immediately follow and tells you what all your watch request settings are.

Up to this point, nothing has been dependent on the state of the sensors. At this time, it may well be that none of those devices is fully powered up yet. In fact, they won’t be, unless another GPSD-enabled application is already watching when you open your connection. If that’s the case, you will start seeing data immediately.

For now, though, let’s go back to the case where gpsd has to fire up the sensors. After issuing the WATCH response, the daemon opens all of them and watches for incoming packets that it can recognize. After a variable delay, it will ship a notification that looks something like this:

{“class”:”DEVICE”,”path”:”/dev/ttyUSB0″,”activated”:1269960793.97, “driver”:”SiRF binary”,”native”:1,”bps”:4800, “parity”:”N”,”stopbits”:1,”cycle”:1.00}

This is the daemon telling you that it has recognized a SiRF binary GPS on /dev/ttyUSB0 shipping report packets at 4800 bits per second. This notification is not delayed by the time it takes to achieve satellite lock; the GPS will cheerfully ship packets before that. But it will be delayed by the time required for the daemon to sync up with the GPS.

The GPSD daemon is designed so it doesn’t have to know anything about the sensor in advance – not which of a dozen reporting protocols it uses, and not even the baud rate of the serial device. The reason for this agnosticism is so the daemon can adapt properly to anything a hotplug event night throw at it. If you unplug your GPS while your application is running, and then plug one one of a different type, the daemon will cope. Your application won’t know the difference unless you have told it to notice device types.

You can even start your application, have it issue a WATCH, realize you forgot to plug in a GPS, and do that. The hotplug event will tell gpsd, which will add the new device to the watched-devices list of every client that has issued a ?WATCH.

In order to make this work, gpsd has a packet sniffer inside it that does autobauding and packet-protocol detection. Normally the packet sniffer will achieve sync in well under a second (my measured times range from 0.10 to 0.53 sec at 4800bps), but it can take longer if your serial traffic is degraded by dodgy cables or electrical noise, or if the GPS is configured to run at an unusual speed/parity/stopbit configuration.

The real point here is that the delay is variable. The client library, and your application, can’t assume a neat lockstep of request and instant response.

Once you do get your device(s) synced, things become more predictable. The sensor will start shipping fix reports at a constant interval, usually every second, and the daemon will massage them into JSON and pass them up the client to your application.

However, until the sensor achieves satellite lock, those fixes will be “mode 1” – no valid data (mode 2 is a 2D fix, mode 3 is a 3D fix). Here’s what that looks like:

{“class”:”TPV”,”device”:”/dev/ttyUSB0″, “time”:”2010-04-30T11:47:43.28Z”,”ept”:0.005,”mode”:1}

Occasionally you’ll get another kind of sentence, SKY, that reports a satellite skyview. But TPV is the important one. Here’s what it looks like when the sensor has a fix to report:

{“class”:”TPV”,”time”:”2010-04-30T11:48:20.10Z”,”ept”:0.005, “lat”:46.498204497,”lon”:7.568061439,”alt”:1327.689, epx”:15.319,
“epy”:17.054,”epv”:124.484,”track”:10.3797, “speed”:0.091,”climb”:-0.085,”eps”:34.11,”mode”:3}

Note the “mode”:3 at the end. This is how you tell that the GPS is reporting a full 3D fix with altitude. …

When your application shuts down, it can cancel its watch:

?WATCH={“enable”:false} This will enable the daemon to close devices and conserve power. Supposing you don’t do this, the daemon will time out devices with no listeners, so canceling your watch is not strictly necessary. But it is good manners.

Another way to use the daemon is with the ?POLL command To do this, issue


This activates all devices without enabling streaming of reports. You can then say “?POLL;” to poll gpsd’s recorded data.


{“class”:”POLL”,”time”:”2012-04-05T15:00:01.501Z”,”active”:1, …

This interface is intended for use with applications like CGI scripts that cannot wait on output from the daemon but must poke it into responding.

If you’re a clever sort, you’re already wondering what the daemon does if the application at the other end of the client socket doesn’t read data out of it as fast as gpsd is shipping it upwards. And the answer is this: eventually the socket buffer fills up, a write from the daemon throws an error, and the daemon shuts down that client socket.

From the point of view of the application, it reads all the buffered data and then gets a read return indicating the socket shutdown. We’ll return to this in the discussion of client libraries, but the thing for you to know right now is that this edge case is actually quite difficult to fall afoul of. Total data volume on these sockets is not high. As long as your application checks for and reads socket data no less often than once a second, you won’t — and a second is a lot of time in which to come back around your main loop.

Interfacing from the client side

/ to continue, …

/ to continue, …

Categories: Uncategorized

Leave a Reply

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

WordPress.com Logo

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

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: