diff --git a/README.rst b/README.rst index 5a7d095..817b6a1 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,3 @@ - Introduction ============ @@ -14,8 +13,8 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_GPS/actions/ :alt: Build Status -GPS parsing module. Can parse simple NMEA data sentences from serial GPS -modules to read latitude, longitude, and more. +GPS parsing module. Can send commands to, and parse simple NMEA data sentences +from serial and I2C GPS modules to read latitude, longitude, and more. Dependencies @@ -115,72 +114,10 @@ These two lines are the lines that actually solve the issue: print('Longitude: {0:.6f} degrees'.format(gps.longitude)) -Note: Sending multiple PMTK314 packets with gps.send_command() will not work unless there is a substantial amount of time in-between each time gps.send_command() is called. A time.sleep() of 1 second or more should fix this. - -About NMEA Data -=============== -This GPS module uses the NMEA 0183 protocol. - -This data is formatted by the GPS in one of two ways. - -The first of these is GGA. GGA has more or less everything you need. - -Here's an explanation of GGA: -:: - - 11 - 1 2 3 4 5 6 7 8 9 10 | 12 13 14 15 - | | | | | | | | | | | | | | | - $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh - - -1. Time (UTC) -2. Latitude -3. N or S (North or South) -4. Longitude -5. E or W (East or West) -6. GPS Quality Indicator, - - * 0 - fix not available, - * 1 - GPS fix, - * 2 - Differential GPS fix - -7. Number of satellites in view, 00 - 12 -8. Horizontal Dilution of precision -9. Antenna Altitude above/below mean-sea-level (geoid) -10. Units of antenna altitude, meters -11. Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid -12. Units of geoidal separation, meters -13. Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used -14. Differential reference station ID, 0000-1023 -15. Checksum - -The second of these is RMC. RMC is Recommended Minimum Navigation Information. - -Here's an explanation of RMC: -:: - - 12 - 1 2 3 4 5 6 7 8 9 10 11| - | | | | | | | | | | | | - $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh - -1. Time (UTC) -2. Status, V = Navigation receiver warning -3. Latitude -4. N or S -5. Longitude -6. E or W -7. Speed over ground, knots -8. Track made good, degrees true -9. Date, ddmmyy -10. Magnetic Variation, degrees -11. E or W -12. Checksum - - -`Info about NMEA taken from here -`_. +Note: Sending multiple PMTK314 packets with ``gps.send_command()`` will not +work unless there is a substantial amount of time in-between each time +``gps.send_command()`` is called. A ``time.sleep()`` of 1 second or more +should fix this. Contributing ============ diff --git a/adafruit_gps.py b/adafruit_gps.py index 2aca02a..450eeb7 100644 --- a/adafruit_gps.py +++ b/adafruit_gps.py @@ -9,7 +9,7 @@ GPS parsing module. Can parse simple NMEA data sentences from serial GPS modules to read latitude, longitude, and more. -* Author(s): Tony DiCola +* Author(s): Tony DiCola, James Carr Implementation Notes -------------------- diff --git a/docs/conf.py b/docs/conf.py index 48fa06c..22cd1e0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,8 +35,8 @@ # General information about the project. project = "Adafruit GPS Library" -copyright = "2017 Tony DiCola" -author = "Tony DiCola" +copyright = "2017 Tony DiCola, 2021 James Carr" +author = "Tony DiCola, James Carr" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/details.rst b/docs/details.rst new file mode 100644 index 0000000..3845719 --- /dev/null +++ b/docs/details.rst @@ -0,0 +1,242 @@ +Communicating with the GPS +========================== + +The code communicates with the GPS by sending and receiving specially formatted +sentences. The format used is the NMEA 0183 protocol specified by the National +Marine Electronics Association. This was designed for boat navigation and +control systems and is widely used by GPSs. + +In general, you configure the device to send the sentences that you want at the +frequency you need and then receive a flow of GPS update messages. + +Sentences received from the GPS module use the same format, irrespective of the +manufacturer. Sentences sent to the GPS module to control it, and answers to +these commands, are proprietary to the manufacturer. + +**NOTE:** All of the example commands used in this documentation, and +the examples folder, are for the MediaTek 333X GPS chips used in Adafruit +products. Make sure to check the datasheet for your GPS chip if it is different. + +Sentence format +--------------- + +$TAG[,DATA[,DATA...]]*hh + +* '$' is the opening delimiter +* TAG is the tag describing the type of message. + + * The tag for a proprietary (chipset specific) message is composed of + + * 'P' for proprietary. + * 'ABC', a 3 letter code for the manufacturer, eg. 'MTK' for MediaTek. + * 'CODE', a manufacturer specified code for the command or answer. + *Note: This can be made up of letters and numbers and there is no + required length.* + + 'PMTK220' is the Mediatek command for setting the update rate. + + *Note: not all commands have an answer counterpart* + + * The tag for a received data sentence is of the form TTDDD, where: + + * TT is the talker sending the data. The list of talkers is large but we + are only interested in ones starting with a 'G': + + * GA - Galileo (Europe) + * GB - BeiDou (China) + * GI - NavIC (India) + * GL - GLONASS (Russia) + * GP - GPS (US) + * GQ - QZSS (Japan) + * GN - GNSS, a combination of the above + + * DDD is the data type of the sentence, this determines how to decode it. + Again, the list of data types is long but we are only interested in a + few: + + * RMC - Recommended Minimum Navigation Information + * GLL - Geographic Position - Latitude/Longitude + * GGA - Global Positioning System Fix Data + * VTG - Track made good and Ground speed *(not currently parsed)* + * ZDA - Time & Date - UTC, day, month, year and local time zone *(not + currently parsed)* + * GSA - GPS `DOP + `_ + and active satellites + * GSV - Satellites in view + * GRS - GPS Range Residuals *(not currently parsed)* + * GST - GPS Pseudorange Noise Statistics *(not currently parsed)* + +* DATA is separated from the TAG by a comma and is a comma separated list of + data. Proprietary commands, and answers, will specify on their datasheet what + the list of data is. The normal sentences generated by GPS modules are + specified by NMEA. An unofficial list is `here + `_. +* '*' is the end of data delimiter. +* hh is the 1-byte checksum of all characters between '$' and '*' in + hexadecimal. +* is the mandatory sentence terminator + +Checksums +--------- + +When sending commands with the `send_command()` method it will add the +necessary delimiters and calculate the checksum for you, eg. + +.. code-block:: python + + gps.send_command(b'PMTK220,1000') + +When receiving answers or data from the GPS module, if you use the `update()` +method to poll the device it will reject any sentences with an invalid +checksum and then try to parse the data. However, you can choose to manually +pull data with the :py:meth:`~adafruit_gps.GPS.read` or +:py:meth:`~adafruit_gps.GPS.readline` which will do no parsing or checksum +validation. + + +Initial Configuration +--------------------- + +.. code-block:: python + + import board + import busio + import adafruit_gps + + USE_UART = True # Change this to False to connect via I2C + + if USE_UART: + # Create a serial connection for the GPS connection. + uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10) + + # for a computer, use the pyserial library for uart access + # import serial + # uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10) + + # Create a GPS module instance. + gps = adafruit_gps.GPS(uart, debug=False) # Use UART/pyserial + else: + # If using I2C, we'll create an I2C interface to talk to using default pins + i2c = board.I2C() + + # Create a GPS module instance. + gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False) # Use I2C interface + +Configuring the GPS +------------------- + +.. code-block:: python + + # Set update rate to 1000 milliseconds (1Hz) + gps.send_command(b"PMTK220,1000") + + # Ask for specific data to be sent. + # A B C D E F G H I + gps.send_command(b'PMTK314,1,1,5,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0') + + # A - send GLL sentences + # B - send RMC sentences + # C - send VTG sentences + # D - send GGA sentences + # E - send GSA sentences + # F - send GSV sentences + # G - send GRS sentences + # H - send GST sentences + # I - send ZDA sentences + + # The number is how often to send the sentence compared to the update frequency. + # If the update frequency is 500ms and the number is 5, it will send that message + # every 2.5 seconds. + +**Note:** Be aware that some data types send multiple sentences per update. So +if you ask for 5 different types of data at 1Hz, you need to be able to handle +at least 10 sentences per second. If the data is not read fast enough, the +internal buffer and backlog behaviour is not specified. + +Poll for data +------------- + +.. code-block:: python + + while True: + if gps.update(): + # A valid sentence was received - do something + if gps.has_fix: + print(f"{gps.latitude:.6f},{gps.longitude:.6f}") + else: + print("Waiting for a fix...") + else: + # No valid sentence was received, wait a moment. + time.sleep(100) + +The `update()` call takes care of reading data from the device and parsing it +into usable data. This can then be accessed using the property accessors, eg. +`has_fix`, `datetime`, latitude, longitude etc. + +Selected Data Types +=================== + +RMC - Recommended Minimum Navigation Information +------------------------------------------------ +:: + + 1 2 3 4 5 6 7 8 9 10 11 12 + | | | | | | | | | | | | + $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh + $GNRMC,001031.00,A,4404.13993,N,12118.86023,W,0.146,,100117,,,A*7B + +1. Time (UTC) +2. Status, A = Valid, V = Warning +3. Latitude +4. N or S +5. Longitude +6. E or W +7. Speed over ground, knots +8. Track made good, degrees true +9. Date, ddmmyy +10. Magnetic Variation, degrees +11. E or W +12. FAA mode indicator (NMEA 2.3 and later) +13. Checksum + +GGA - Global Positioning System Fix Data +---------------------------------------- +:: + + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + | | | | | | | | | | | | | | | + $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh + $GNGGA,001043.00,4404.14036,N,12118.85961,W,1,12,0.98,1113.0,M,-21.3,M,,*47 + +1. Time (UTC) +2. Latitude +3. N or S (North or South) +4. Longitude +5. E or W (East or West) +6. GPS Quality Indicator: + + 0. Fix not available + 1. GPS fix + 2. Differential GPS fix + 3. PPS fix (values above 2 are NMEA 0183 v2.3 features) + 4. Real Time Kinematic + 5. Float RTK + 6. Estimated (dead reckoning) + 7. Manual input mode + 8. Simulation mode + +7. Number of satellites in view, 00 - 12 +8. Horizontal dilution of precision +9. Antenna altitude above/below mean-sea-level (geoid) +10. Units of antenna altitude, meters +11. Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid +12. Units of geoidal separation, meters +13. Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, empty field when DGPS is not used +14. Differential reference station ID, 0000-1023 +15. Checksum + +Info about NMEA taken from `here (2001) +`_. +and `here (2021) +`_ diff --git a/docs/details.rst.license b/docs/details.rst.license new file mode 100644 index 0000000..5d181bd --- /dev/null +++ b/docs/details.rst.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2021 lesamouraipourpre +# +# SPDX-License-Identifier: MIT diff --git a/docs/examples.rst b/docs/examples.rst index 29a3826..2a9148f 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,3 +6,57 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/gps_simpletest.py :caption: examples/gps_simpletest.py :linenos: + +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. + +.. literalinclude:: ../examples/gps_echotest.py + :caption: examples/gps_echotest.py + :linenos: + +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.) + +.. literalinclude:: ../examples/gps_time_source.py + :caption: examples/gps_time_source.py + :linenos: + +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 +`_ + +.. literalinclude:: ../examples/gps_datalogging.py + :caption: examples/gps_datalogging.py + :linenos: + +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 + +.. literalinclude:: ../examples/gps_satellitefix.py + :caption: examples/gps_satellitefix.py + :linenos: diff --git a/docs/index.rst b/docs/index.rst index a39b9dd..adb092b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,7 @@ Table of Contents :hidden: self + details .. toctree:: :caption: Examples @@ -23,11 +24,17 @@ Table of Contents .. toctree:: :caption: Tutorials + Adafruit Ultimate GPS + Adafruit Ultimate GPS featherwing + Adafruit Mini GPS module + GPS Tour Guide + .. toctree:: :caption: Related Products Adafruit Ultimate GPS Breakout Adafruit Ultimate GPS FeatherWing + Adafruit Mini GPS module .. toctree:: :caption: Other Links diff --git a/examples/gps_satellitefix.py b/examples/gps_satellitefix.py index 17ef3c0..37de93b 100644 --- a/examples/gps_satellitefix.py +++ b/examples/gps_satellitefix.py @@ -1,6 +1,11 @@ # SPDX-FileCopyrightText: 2021 lesamouraipourpre # SPDX-License-Identifier: MIT +# 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 + import time import board