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

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