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()
25
26# Create a GPS module instance.
27gps = adafruit_gps.GPS(uart, debug=False)  # Use UART/pyserial
28# gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False)  # Use I2C interface
29
30# Initialize the GPS module by changing what data it sends and at what rate.
31# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
32# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
33# the GPS module behavior:
34#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf
35
36# Turn on the basic GGA and RMC info (what you typically want)
37gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
38# Turn on just minimum info (RMC only, location):
39# gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
40# Turn off everything:
41# gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
42# Turn on everything (not all of it is parsed!)
43# gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0')
44
45# Set update rate to once a second (1hz) which is what you typically want.
46gps.send_command(b"PMTK220,1000")
47# Or decrease to once every two seconds by doubling the millisecond value.
48# Be sure to also increase your UART timeout above!
49# gps.send_command(b'PMTK220,2000')
50# You can also speed up the rate, but don't go too fast or else you can lose
51# data during parsing.  This would be twice a second (2hz, 500ms delay):
52# gps.send_command(b'PMTK220,500')
53
54# Main loop runs forever printing the location, etc. every second.
55last_print = time.monotonic()
56while True:
57    # Make sure to call gps.update() every loop iteration and at least twice
58    # as fast as data comes from the GPS unit (usually every second).
59    # This returns a bool that's true if it parsed new data (you can ignore it
60    # though if you don't care and instead look at the has_fix property).
61    gps.update()
62    # Every second print out current location details if there's a fix.
63    current = time.monotonic()
64    if current - last_print >= 1.0:
65        last_print = current
66        if not gps.has_fix:
67            # Try again if we don't have a fix yet.
68            print("Waiting for fix...")
69            continue
70        # We have a fix! (gps.has_fix is true)
71        # Print out details about the fix like location, date, etc.
72        print("=" * 40)  # Print a separator line.
73        print(
74            "Fix timestamp: {}/{}/{} {:02}:{:02}:{:02}".format(
75                gps.timestamp_utc.tm_mon,  # Grab parts of the time from the
76                gps.timestamp_utc.tm_mday,  # struct_time object that holds
77                gps.timestamp_utc.tm_year,  # the fix time.  Note you might
78                gps.timestamp_utc.tm_hour,  # not get all data like year, day,
79                gps.timestamp_utc.tm_min,  # month!
80                gps.timestamp_utc.tm_sec,
81            )
82        )
83        print("Latitude: {0:.6f} degrees".format(gps.latitude))
84        print("Longitude: {0:.6f} degrees".format(gps.longitude))
85        print("Fix quality: {}".format(gps.fix_quality))
86        # Some attributes beyond latitude, longitude and timestamp are optional
87        # and might not be present.  Check if they're None before trying to use!
88        if gps.satellites is not None:
89            print("# satellites: {}".format(gps.satellites))
90        if gps.altitude_m is not None:
91            print("Altitude: {} meters".format(gps.altitude_m))
92        if gps.speed_knots is not None:
93            print("Speed: {} knots".format(gps.speed_knots))
94        if gps.track_angle_deg is not None:
95            print("Track angle: {} degrees".format(gps.track_angle_deg))
96        if gps.horizontal_dilution is not None:
97            print("Horizontal dilution: {}".format(gps.horizontal_dilution))
98        if gps.height_geoid is not None:
99            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()
25
26# Create a GPS module instance.
27gps = adafruit_gps.GPS(uart)  # Use UART/pyserial
28# gps = adafruit_gps.GPS_GtopI2C(i2c)  # Use I2C interface
29
30# Initialize the GPS module by changing what data it sends and at what rate.
31# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
32# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
33# the GPS module behavior:
34#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf
35
36# Turn on the basic GGA and RMC info (what you typically want)
37gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
38# Turn on just minimum info (RMC only, location):
39# gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
40# Turn off everything:
41# gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
42# Tuen on everything (not all of it is parsed!)
43# gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0')
44
45# Set update rate to once a second (1hz) which is what you typically want.
46gps.send_command(b"PMTK220,1000")
47# Or decrease to once every two seconds by doubling the millisecond value.
48# Be sure to also increase your UART timeout above!
49# gps.send_command(b'PMTK220,2000')
50# You can also speed up the rate, but don't go too fast or else you can lose
51# data during parsing.  This would be twice a second (2hz, 500ms delay):
52# gps.send_command(b'PMTK220,500')
53
54# Main loop runs forever printing data as it comes in
55timestamp = time.monotonic()
56while True:
57    data = gps.read(32)  # read up to 32 bytes
58    # print(data)  # this is a bytearray type
59
60    if data is not None:
61        # convert bytearray to string
62        data_string = "".join([chr(b) for b in data])
63        print(data_string, end="")
64
65    if time.monotonic() - timestamp > 5:
66        # every 5 seconds...
67        gps.send_command(b"PMTK605")  # request firmware version
68        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
42    gps.update()
43    # Every second print out current time from GPS, RTC and time.localtime()
44    current = time.monotonic()
45    if current - last_print >= 1.0:
46        last_print = current
47        if not gps.timestamp_utc:
48            print("No time data from GPS yet")
49            continue
50        # Time & date from GPS informations
51        print("Fix timestamp: {}".format(_format_datetime(gps.timestamp_utc)))
52
53        # Time & date from internal RTC
54        print("RTC timestamp: {}".format(_format_datetime(the_rtc.datetime)))
55
56        # Time & date from time.localtime() function
57        local_time = time.localtime()
58
59        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 board
14import busio
15import adafruit_gps
16
17# Path to the file to log GPS data.  By default this will be appended to
18# which means new lines are added at the end and all old data is kept.
19# Change this path to point at internal storage (like '/gps.txt') or SD
20# card mounted storage ('/sd/gps.txt') as desired.
21LOG_FILE = "gps.txt"  # Example for writing to internal path gps.txt
22
23# File more for opening the log file.  Mode 'ab' means append or add new lines
24# to the end of the file rather than erasing it and starting over.  If you'd
25# like to erase the file and start clean each time use the value 'wb' instead.
26LOG_MODE = "ab"
27
28# If writing to SD card on a microcontroller customize and uncomment these
29# lines to import the necessary library and initialize the SD card:
30# NOT for use with a single board computer like Raspberry Pi!
31"""
32import adafruit_sdcard
33import digitalio
34import storage
35
36SD_CS_PIN = board.D10  # CS for SD card using Adalogger Featherwing
37spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
38sd_cs = digitalio.DigitalInOut(SD_CS_PIN)
39sdcard = adafruit_sdcard.SDCard(spi, sd_cs)
40vfs = storage.VfsFat(sdcard)
41storage.mount(vfs, '/sd')    # Mount SD card under '/sd' path in filesystem.
42LOG_FILE = '/sd/gps.txt'     # Example for writing to SD card path /sd/gps.txt
43"""
44
45# Create a serial connection for the GPS connection using default speed and
46# a slightly higher timeout (GPS modules typically update once a second).
47# These are the defaults you should use for the GPS FeatherWing.
48# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
49uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
50
51# If using a USB/Serial converter, use pyserial and update the serial
52# port name to match the serial connection for the GPS!
53# import serial
54# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
55
56# If using I2C, we'll create an I2C interface to talk to using default pins
57# i2c = board.I2C()
58
59# Create a GPS module instance.
60gps = adafruit_gps.GPS(uart)  # Use UART/pyserial
61# gps = adafruit_gps.GPS_GtopI2C(i2c)  # Use I2C interface
62
63# Main loop just reads data from the GPS module and writes it back out to
64# the output file while also printing to serial output.
65with open(LOG_FILE, LOG_MODE) as outfile:
66    while True:
67        sentence = gps.readline()
68        if not sentence:
69            continue
70        print(str(sentence, "ascii").strip())
71        outfile.write(sentence)
72        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# uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)
 19
 20# for a computer, use the pyserial library for uart access
 21# import serial
 22# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)
 23
 24# If using I2C, we'll create an I2C interface to talk to using default pins
 25i2c = board.I2C()
 26
 27# Create a GPS module instance.
 28# gps = adafruit_gps.GPS(uart, debug=False)  # Use UART/pyserial
 29gps = 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 everything (not all of it is parsed!)
 38gps.send_command(b"PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0")
 39
 40# Set update rate to once a second (1hz) which is what you typically want.
 41gps.send_command(b"PMTK220,1000")
 42# Or decrease to once every two seconds by doubling the millisecond value.
 43# Be sure to also increase your UART timeout above!
 44# gps.send_command(b'PMTK220,2000')
 45# You can also speed up the rate, but don't go too fast or else you can lose
 46# data during parsing.  This would be twice a second (2hz, 500ms delay):
 47# gps.send_command(b'PMTK220,500')
 48
 49
 50def format_dop(dop):
 51    # https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)
 52    if dop > 20:
 53        msg = "Poor"
 54    elif dop > 10:
 55        msg = "Fair"
 56    elif dop > 5:
 57        msg = "Moderate"
 58    elif dop > 2:
 59        msg = "Good"
 60    elif dop > 1:
 61        msg = "Excellent"
 62    else:
 63        msg = "Ideal"
 64    return f"{dop} - {msg}"
 65
 66
 67talkers = {
 68    "GA": "Galileo",
 69    "GB": "BeiDou",
 70    "GI": "NavIC",
 71    "GL": "GLONASS",
 72    "GP": "GPS",
 73    "GQ": "QZSS",
 74    "GN": "GNSS",
 75}
 76
 77# Main loop runs forever printing the location, etc. every second.
 78last_print = time.monotonic()
 79while True:
 80    # Make sure to call gps.update() every loop iteration and at least twice
 81    # as fast as data comes from the GPS unit (usually every second).
 82    # This returns a bool that's true if it parsed new data (you can ignore it
 83    # though if you don't care and instead look at the has_fix property).
 84    if not gps.update() or not gps.has_fix:
 85        time.sleep(0.1)
 86        continue
 87
 88    if gps.nmea_sentence[3:6] == "GSA":
 89        print(f"{gps.latitude:.6f}, {gps.longitude:.6f} {gps.altitude_m}m")
 90        print(f"2D Fix: {gps.has_fix}  3D Fix: {gps.has_3d_fix}")
 91        print(f"  PDOP (Position Dilution of Precision): {format_dop(gps.pdop)}")
 92        print(f"  HDOP (Horizontal Dilution of Precision): {format_dop(gps.hdop)}")
 93        print(f"  VDOP (Vertical Dilution of Precision): {format_dop(gps.vdop)}")
 94        print("Satellites used for fix:")
 95        for s in gps.sat_prns:
 96            talker = talkers[s[0:2]]
 97            number = s[2:]
 98            print(f"  {talker}-{number} ", end="")
 99            if gps.sats is None:
100                print("- no info")
101            else:
102                try:
103                    sat = gps.sats[s]
104                    if sat is None:
105                        print("- no info")
106                    else:
107                        print(f"Elevation:{sat[1]}* Azimuth:{sat[2]}* SNR:{sat[3]}dB")
108                except KeyError:
109                    print("- no info")
110        print()