Simple test

Ensure your device works with this simple test.

examples/gps_simpletest.py
  1# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
  2# SPDX-License-Identifier: MIT
  3
  4# Simple GPS module demonstration.
  5# Will wait for a fix and print a message every second with the current location
  6# and other details.
  7import time
  8import board
  9import busio
 10
 11import adafruit_gps
 12
 13# Create a serial connection for the GPS connection using default speed and
 14# a slightly higher timeout (GPS modules typically update once a second).
 15# These are the defaults you should use for the GPS FeatherWing.
 16# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
 17uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
 18
 19# for a computer, use the pyserial library for uart access
 20# import serial
 21# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
 22
 23# If using I2C, we'll create an I2C interface to talk to using default pins
 24# i2c = board.I2C()  # uses board.SCL and board.SDA
 25# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
 26
 27# Create a GPS module instance.
 28gps = adafruit_gps.GPS(uart, debug=False)  # Use UART/pyserial
 29# gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False)  # Use I2C interface
 30
 31# Initialize the GPS module by changing what data it sends and at what rate.
 32# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
 33# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
 34# the GPS module behavior:
 35#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf
 36
 37# Turn on the basic GGA and RMC info (what you typically want)
 38gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
 39# Turn on just minimum info (RMC only, location):
 40# gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
 41# Turn off everything:
 42# gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
 43# Turn on everything (not all of it is parsed!)
 44# gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0')
 45
 46# Set update rate to once a second (1hz) which is what you typically want.
 47gps.send_command(b"PMTK220,1000")
 48# Or decrease to once every two seconds by doubling the millisecond value.
 49# Be sure to also increase your UART timeout above!
 50# gps.send_command(b'PMTK220,2000')
 51# You can also speed up the rate, but don't go too fast or else you can lose
 52# data during parsing.  This would be twice a second (2hz, 500ms delay):
 53# gps.send_command(b'PMTK220,500')
 54
 55# Main loop runs forever printing the location, etc. every second.
 56last_print = time.monotonic()
 57while True:
 58    # Make sure to call gps.update() every loop iteration and at least twice
 59    # as fast as data comes from the GPS unit (usually every second).
 60    # This returns a bool that's true if it parsed new data (you can ignore it
 61    # though if you don't care and instead look at the has_fix property).
 62    gps.update()
 63    # Every second print out current location details if there's a fix.
 64    current = time.monotonic()
 65    if current - last_print >= 1.0:
 66        last_print = current
 67        if not gps.has_fix:
 68            # Try again if we don't have a fix yet.
 69            print("Waiting for fix...")
 70            continue
 71        # We have a fix! (gps.has_fix is true)
 72        # Print out details about the fix like location, date, etc.
 73        print("=" * 40)  # Print a separator line.
 74        print(
 75            "Fix timestamp: {}/{}/{} {:02}:{:02}:{:02}".format(
 76                gps.timestamp_utc.tm_mon,  # Grab parts of the time from the
 77                gps.timestamp_utc.tm_mday,  # struct_time object that holds
 78                gps.timestamp_utc.tm_year,  # the fix time.  Note you might
 79                gps.timestamp_utc.tm_hour,  # not get all data like year, day,
 80                gps.timestamp_utc.tm_min,  # month!
 81                gps.timestamp_utc.tm_sec,
 82            )
 83        )
 84        print("Latitude: {0:.6f} degrees".format(gps.latitude))
 85        print("Longitude: {0:.6f} degrees".format(gps.longitude))
 86        print(
 87            "Precise Latitude: {} degs, {:2.4f} mins".format(
 88                gps.latitude_degrees, gps.latitude_minutes
 89            )
 90        )
 91        print(
 92            "Precise Longitude: {} degs, {:2.4f} mins".format(
 93                gps.longitude_degrees, gps.longitude_minutes
 94            )
 95        )
 96        print("Fix quality: {}".format(gps.fix_quality))
 97        # Some attributes beyond latitude, longitude and timestamp are optional
 98        # and might not be present.  Check if they're None before trying to use!
 99        if gps.satellites is not None:
100            print("# satellites: {}".format(gps.satellites))
101        if gps.altitude_m is not None:
102            print("Altitude: {} meters".format(gps.altitude_m))
103        if gps.speed_knots is not None:
104            print("Speed: {} knots".format(gps.speed_knots))
105        if gps.track_angle_deg is not None:
106            print("Track angle: {} degrees".format(gps.track_angle_deg))
107        if gps.horizontal_dilution is not None:
108            print("Horizontal dilution: {}".format(gps.horizontal_dilution))
109        if gps.height_geoid is not None:
110            print("Height geoid: {} meters".format(gps.height_geoid))

Echo test

Simple GPS module demonstration. This will print NMEA sentences received from the GPS, great for testing connection. This uses the GPS to send some commands, then reads directly from the GPS.

examples/gps_echotest.py
 1# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
 2# SPDX-License-Identifier: MIT
 3
 4# Simple GPS module demonstration.
 5# Will print NMEA sentences received from the GPS, great for testing connection
 6# Uses the GPS to send some commands, then reads directly from the GPS
 7import time
 8import board
 9import busio
10
11import adafruit_gps
12
13# Create a serial connection for the GPS connection using default speed and
14# a slightly higher timeout (GPS modules typically update once a second).
15# These are the defaults you should use for the GPS FeatherWing.
16# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
17uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
18
19# for a computer, use the pyserial library for uart access
20# import serial
21# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
22
23# If using I2C, we'll create an I2C interface to talk to using default pins
24# i2c = board.I2C()  # uses board.SCL and board.SDA
25# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
26
27# Create a GPS module instance.
28gps = adafruit_gps.GPS(uart)  # Use UART/pyserial
29# gps = adafruit_gps.GPS_GtopI2C(i2c)  # Use I2C interface
30
31# Initialize the GPS module by changing what data it sends and at what rate.
32# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
33# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
34# the GPS module behavior:
35#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf
36
37# Turn on the basic GGA and RMC info (what you typically want)
38gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
39# Turn on just minimum info (RMC only, location):
40# gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
41# Turn off everything:
42# gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
43# Tuen on everything (not all of it is parsed!)
44# gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0')
45
46# Set update rate to once a second (1hz) which is what you typically want.
47gps.send_command(b"PMTK220,1000")
48# Or decrease to once every two seconds by doubling the millisecond value.
49# Be sure to also increase your UART timeout above!
50# gps.send_command(b'PMTK220,2000')
51# You can also speed up the rate, but don't go too fast or else you can lose
52# data during parsing.  This would be twice a second (2hz, 500ms delay):
53# gps.send_command(b'PMTK220,500')
54
55# Main loop runs forever printing data as it comes in
56timestamp = time.monotonic()
57while True:
58    data = gps.read(32)  # read up to 32 bytes
59    # print(data)  # this is a bytearray type
60
61    if data is not None:
62        # convert bytearray to string
63        data_string = "".join([chr(b) for b in data])
64        print(data_string, end="")
65
66    if time.monotonic() - timestamp > 5:
67        # every 5 seconds...
68        gps.send_command(b"PMTK605")  # request firmware version
69        timestamp = time.monotonic()

Time source

Simple script using GPS timestamps as RTC time source. The GPS timestamps are available without a full location fix if a single satellite can be seen. The GPS unit will keep the track of time while there is power source (i.e. a coin cell battery.)

examples/gps_time_source.py
 1# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
 2# SPDX-License-Identifier: MIT
 3
 4# Simple script using GPS timestamps as RTC time source
 5# The GPS timestamps are available without a fix and keep the track of
 6# time while there is powersource (ie coin cell battery)
 7
 8import time
 9import board
10import busio
11import rtc
12import adafruit_gps
13
14uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
15# i2c = busio.I2C(board.SCL, board.SDA)
16
17gps = adafruit_gps.GPS(uart, debug=False)
18# gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False)  # Use I2C interface
19
20gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
21gps.send_command(b"PMTK220,1000")
22
23print("Set GPS as time source")
24rtc.set_time_source(gps)
25the_rtc = rtc.RTC()
26
27
28def _format_datetime(datetime):
29    return "{:02}/{:02}/{} {:02}:{:02}:{:02}".format(
30        datetime.tm_mon,
31        datetime.tm_mday,
32        datetime.tm_year,
33        datetime.tm_hour,
34        datetime.tm_min,
35        datetime.tm_sec,
36    )
37
38
39last_print = time.monotonic()
40while True:
41    gps.update()
42    # Every second print out current time from GPS, RTC and time.localtime()
43    current = time.monotonic()
44    if current - last_print >= 1.0:
45        last_print = current
46        if not gps.timestamp_utc:
47            print("No time data from GPS yet")
48            continue
49        # Time & date from GPS informations
50        print("Fix timestamp: {}".format(_format_datetime(gps.timestamp_utc)))
51
52        # Time & date from internal RTC
53        print("RTC timestamp: {}".format(_format_datetime(the_rtc.datetime)))
54
55        # Time & date from time.localtime() function
56        local_time = time.localtime()
57
58        print("Local time: {}".format(_format_datetime(local_time)))

Data logging

Simple GPS datalogging demonstration. This example uses the GPS library and to read raw NMEA sentences over I2C or UART from the GPS unit and dumps them to a file on an SD card (recommended), microcontroller internal storage (be careful as only a few kilobytes are available), or to a filesystem.

If you are using a microcontroller, before writing to internal storage you MUST carefully follow the steps in this guide to enable writes to the internal filesystem: Writing to the filesystem

examples/gps_datalogging.py
 1# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
 2# SPDX-License-Identifier: MIT
 3
 4# Simple GPS datalogging demonstration.
 5# This example uses the GPS library and to read raw NMEA sentences
 6# over I2C or UART from the GPS unit and dumps them to a file on an SD card
 7# (recommended), microcontroller internal storage (be careful as only a few
 8# kilobytes are available), or to a filesystem.
 9# If you are using a microcontroller, before writing to internal storage you
10#  MUST carefully follow the steps in this guide to enable writes to the
11# internal filesystem:
12#  https://learn.adafruit.com/adafruit-ultimate-gps-featherwing/circuitpython-library
13import sys
14
15import board
16import busio
17import adafruit_gps
18
19# Path to the file to log GPS data.  By default this will be appended to
20# which means new lines are added at the end and all old data is kept.
21# Change this path to point at internal storage (like '/gps.txt') or SD
22# card mounted storage ('/sd/gps.txt') as desired.
23LOG_FILE = "gps.txt"  # Example for writing to internal path gps.txt
24
25# File more for opening the log file.  Mode 'ab' means append or add new lines
26# to the end of the file rather than erasing it and starting over.  If you'd
27# like to erase the file and start clean each time use the value 'wb' instead.
28LOG_MODE = "ab"
29
30# sdcardio and adafruit_sdcard are NOT supported on blinka. If you are using a
31# Raspberry Pi or other single-board linux computer, the code will save the
32# output to the path defined in LOG_FILE above.
33if sys.platform != "linux":
34    import storage
35
36    SD_CS_PIN = board.D10  # CS for SD card using Adalogger Featherwing
37    try:
38        import sdcardio
39
40        sdcard = sdcardio.SDCard(board.SPI, SD_CS_PIN)
41    except ImportError:
42        import adafruit_sdcard
43        import digitalio
44
45        sdcard = adafruit_sdcard.SDCard(
46            board.SPI(),
47            digitalio.DigitalInOut(SD_CS_PIN),
48        )
49
50    vfs = storage.VfsFat(sdcard)
51    storage.mount(vfs, "/sd")  # Mount SD card under '/sd' path in filesystem.
52    LOG_FILE = "/sd/gps.txt"  # Example for writing to SD card path /sd/gps.txt
53
54# Create a serial connection for the GPS connection using default speed and
55# a slightly higher timeout (GPS modules typically update once a second).
56# These are the defaults you should use for the GPS FeatherWing.
57# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
58uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
59
60# If using a USB/Serial converter, use pyserial and update the serial
61# port name to match the serial connection for the GPS!
62# import serial
63# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
64
65# If using I2C, we'll create an I2C interface to talk to using default pins
66# i2c = board.I2C()  # uses board.SCL and board.SDA
67# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
68
69# Create a GPS module instance.
70gps = adafruit_gps.GPS(uart)  # Use UART/pyserial
71# gps = adafruit_gps.GPS_GtopI2C(i2c)  # Use I2C interface
72
73# Main loop just reads data from the GPS module and writes it back out to
74# the output file while also printing to serial output.
75with open(LOG_FILE, LOG_MODE) as outfile:
76    while True:
77        sentence = gps.readline()
78        if not sentence:
79            continue
80        print(str(sentence, "ascii").strip())
81        outfile.write(sentence)
82        outfile.flush()

Satellite fix

This example uses GSA and GSV sentences from the GPS device to report on the quality of the received data from the satellites.

  • GSA - DOP(Dilution of Precision) and active satellites

  • GSV - Satellites in view

examples/gps_satellitefix.py
  1# SPDX-FileCopyrightText: 2021 lesamouraipourpre
  2# SPDX-License-Identifier: MIT
  3
  4# This example uses GSA and GSV sentences from the GPS device to report on the
  5# quality of the received data from the satellites.
  6# * GSA - DOP(Dilution of Precision) and active satellites
  7# * GSV - Satellites in view
  8
  9import time
 10import board
 11
 12import adafruit_gps
 13
 14# Create a serial connection for the GPS connection using default speed and
 15# a slightly higher timeout (GPS modules typically update once a second).
 16# These are the defaults you should use for the GPS FeatherWing.
 17# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
 18# import busio
 19# uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
 20
 21# for a computer, use the pyserial library for uart access
 22# import serial
 23# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
 24
 25# If using I2C, we'll create an I2C interface to talk to using default pins
 26i2c = board.I2C()  # uses board.SCL and board.SDA
 27# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
 28
 29# Create a GPS module instance.
 30# gps = adafruit_gps.GPS(uart, debug=False)  # Use UART/pyserial
 31gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False)  # Use I2C interface
 32
 33# Initialize the GPS module by changing what data it sends and at what rate.
 34# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
 35# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
 36# the GPS module behavior:
 37#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf
 38
 39# Turn on everything (not all of it is parsed!)
 40gps.send_command(b"PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0")
 41
 42# Set update rate to once a second (1hz) which is what you typically want.
 43gps.send_command(b"PMTK220,1000")
 44# Or decrease to once every two seconds by doubling the millisecond value.
 45# Be sure to also increase your UART timeout above!
 46# gps.send_command(b'PMTK220,2000')
 47# You can also speed up the rate, but don't go too fast or else you can lose
 48# data during parsing.  This would be twice a second (2hz, 500ms delay):
 49# gps.send_command(b'PMTK220,500')
 50
 51
 52def format_dop(dop):
 53    # https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)
 54    if dop > 20:
 55        msg = "Poor"
 56    elif dop > 10:
 57        msg = "Fair"
 58    elif dop > 5:
 59        msg = "Moderate"
 60    elif dop > 2:
 61        msg = "Good"
 62    elif dop > 1:
 63        msg = "Excellent"
 64    else:
 65        msg = "Ideal"
 66    return f"{dop} - {msg}"
 67
 68
 69talkers = {
 70    "GA": "Galileo",
 71    "GB": "BeiDou",
 72    "GI": "NavIC",
 73    "GL": "GLONASS",
 74    "GP": "GPS",
 75    "GQ": "QZSS",
 76    "GN": "GNSS",
 77}
 78
 79# Main loop runs forever printing the location, etc. every second.
 80last_print = time.monotonic()
 81while True:
 82    # Make sure to call gps.update() every loop iteration and at least twice
 83    # as fast as data comes from the GPS unit (usually every second).
 84    # This returns a bool that's true if it parsed new data (you can ignore it
 85    # though if you don't care and instead look at the has_fix property).
 86    if not gps.update() or not gps.has_fix:
 87        time.sleep(0.1)
 88        continue
 89
 90    if gps.nmea_sentence[3:6] == "GSA":
 91        print(f"{gps.latitude:.6f}, {gps.longitude:.6f} {gps.altitude_m}m")
 92        print(f"2D Fix: {gps.has_fix}  3D Fix: {gps.has_3d_fix}")
 93        print(f"  PDOP (Position Dilution of Precision): {format_dop(gps.pdop)}")
 94        print(f"  HDOP (Horizontal Dilution of Precision): {format_dop(gps.hdop)}")
 95        print(f"  VDOP (Vertical Dilution of Precision): {format_dop(gps.vdop)}")
 96        print("Satellites used for fix:")
 97        for s in gps.sat_prns:
 98            talker = talkers[s[0:2]]
 99            number = s[2:]
100            print(f"  {talker}-{number} ", end="")
101            if gps.sats is None:
102                print("- no info")
103            else:
104                try:
105                    sat = gps.sats[s]
106                    if sat is None:
107                        print("- no info")
108                    else:
109                        print(f"Elevation:{sat[1]}* Azimuth:{sat[2]}* SNR:{sat[3]}dB")
110                except KeyError:
111                    print("- no info")
112        print()