|
| 1 | +Communicating with the GPS |
| 2 | +========================== |
| 3 | + |
| 4 | +The code communicates with the GPS by sending and receiving specially formatted |
| 5 | +sentences. The format used is the NMEA 0183 protocol specified by the National |
| 6 | +Marine Electronics Association. This was designed for boat navigation and |
| 7 | +control systems and is widely used by GPSs. |
| 8 | + |
| 9 | +In general, you configure the device to send the sentences that you want at the |
| 10 | +frequency you need and then receive a flow of GPS update messages. |
| 11 | + |
| 12 | +Sentences received from the GPS module use the same format, irrespective of the |
| 13 | +manufacturer. Sentences sent to the GPS module to control it, and answers to |
| 14 | +these commands, are proprietary to the manufacturer. |
| 15 | + |
| 16 | +**NOTE:** All of the example commands used in this documentation, and |
| 17 | +the examples folder, are for the MediaTek 333X GPS chips used in Adafruit |
| 18 | +products. Make sure to check the datasheet for your GPS chip if it is different. |
| 19 | + |
| 20 | +Sentence format |
| 21 | +--------------- |
| 22 | + |
| 23 | +$TAG[,DATA[,DATA...]]*hh<CR><LF> |
| 24 | + |
| 25 | +* '$' is the opening delimiter |
| 26 | +* TAG is the tag describing the type of message. |
| 27 | + |
| 28 | + * The tag for a proprietary (chipset specific) message is composed of |
| 29 | + |
| 30 | + * 'P' for proprietary. |
| 31 | + * 'ABC', a 3 letter code for the manufacturer, eg. 'MTK' for MediaTek. |
| 32 | + * 'CODE', a manufacturer specified code for the command or answer. |
| 33 | + *Note: This can be made up of letters and numbers and there is no |
| 34 | + required length.* |
| 35 | + |
| 36 | + 'PMTK220' is the Mediatek command for setting the update rate. |
| 37 | + |
| 38 | + *Note: not all commands have an answer counterpart* |
| 39 | + |
| 40 | + * The tag for a received data sentence is of the form TTDDD, where: |
| 41 | + |
| 42 | + * TT is the talker sending the data. The list of talkers is large but we |
| 43 | + are only interested in ones starting with a 'G': |
| 44 | + |
| 45 | + * GA - Galileo (Europe) |
| 46 | + * GB - BeiDou (China) |
| 47 | + * GI - NavIC (India) |
| 48 | + * GL - GLONASS (Russia) |
| 49 | + * GP - GPS (US) |
| 50 | + * GQ - QZSS (Japan) |
| 51 | + * GN - GNSS, a combination of the above |
| 52 | + |
| 53 | + * DDD is the data type of the sentence, this determines how to decode it. |
| 54 | + Again, the list of data types is long but we are only interested in a |
| 55 | + few: |
| 56 | + |
| 57 | + * RMC - Recommended Minimum Navigation Information |
| 58 | + * GLL - Geographic Position - Latitude/Longitude |
| 59 | + * GGA - Global Positioning System Fix Data |
| 60 | + * VTG - Track made good and Ground speed *(not currently parsed)* |
| 61 | + * ZDA - Time & Date - UTC, day, month, year and local time zone *(not |
| 62 | + currently parsed)* |
| 63 | + * GSA - GPS `DOP |
| 64 | + <https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)>`_ |
| 65 | + and active satellites |
| 66 | + * GSV - Satellites in view |
| 67 | + * GRS - GPS Range Residuals *(not currently parsed)* |
| 68 | + * GST - GPS Pseudorange Noise Statistics *(not currently parsed)* |
| 69 | + |
| 70 | +* DATA is separated from the TAG by a comma and is a comma separated list of |
| 71 | + data. Proprietary commands, and answers, will specify on their datasheet what |
| 72 | + the list of data is. The normal sentences generated by GPS modules are |
| 73 | + specified by NMEA. An unofficial list is `here |
| 74 | + <https://gpsd.gitlab.io/gpsd/NMEA.html>`_. |
| 75 | +* '*' is the end of data delimiter. |
| 76 | +* hh is the 1-byte checksum of all characters between '$' and '*' in |
| 77 | + hexadecimal. |
| 78 | +* <CR><LF> is the mandatory sentence terminator |
| 79 | + |
| 80 | +Checksums |
| 81 | +--------- |
| 82 | + |
| 83 | +When sending commands with the `send_command()` method it will add the |
| 84 | +necessary delimiters and calculate the checksum for you, eg. |
| 85 | + |
| 86 | +.. code-block:: python |
| 87 | +
|
| 88 | + gps.send_command(b'PMTK220,1000') |
| 89 | +
|
| 90 | +When receiving answers or data from the GPS module, if you use the `update()` |
| 91 | +method to poll the device it will reject any sentences with an invalid |
| 92 | +checksum and then try to parse the data. However, you can choose to manually |
| 93 | +pull data with the :py:meth:`~adafruit_gps.GPS.read` or |
| 94 | +:py:meth:`~adafruit_gps.GPS.readline` which will do no parsing or checksum |
| 95 | +validation. |
| 96 | + |
| 97 | + |
| 98 | +Initial Configuration |
| 99 | +--------------------- |
| 100 | + |
| 101 | +.. code-block:: python |
| 102 | +
|
| 103 | + import board |
| 104 | + import busio |
| 105 | + import adafruit_gps |
| 106 | +
|
| 107 | + USE_UART = True # Change this to False to connect via I2C |
| 108 | +
|
| 109 | + if USE_UART: |
| 110 | + # Create a serial connection for the GPS connection. |
| 111 | + uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10) |
| 112 | +
|
| 113 | + # for a computer, use the pyserial library for uart access |
| 114 | + # import serial |
| 115 | + # uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10) |
| 116 | +
|
| 117 | + # Create a GPS module instance. |
| 118 | + gps = adafruit_gps.GPS(uart, debug=False) # Use UART/pyserial |
| 119 | + else: |
| 120 | + # If using I2C, we'll create an I2C interface to talk to using default pins |
| 121 | + i2c = board.I2C() |
| 122 | +
|
| 123 | + # Create a GPS module instance. |
| 124 | + gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False) # Use I2C interface |
| 125 | +
|
| 126 | +Configuring the GPS |
| 127 | +------------------- |
| 128 | + |
| 129 | +.. code-block:: python |
| 130 | +
|
| 131 | + # Set update rate to 1000 milliseconds (1Hz) |
| 132 | + gps.send_command(b"PMTK220,1000") |
| 133 | +
|
| 134 | + # Ask for specific data to be sent. |
| 135 | + # A B C D E F G H I |
| 136 | + gps.send_command(b'PMTK314,1,1,5,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0') |
| 137 | +
|
| 138 | + # A - send GLL sentences |
| 139 | + # B - send RMC sentences |
| 140 | + # C - send VTG sentences |
| 141 | + # D - send GGA sentences |
| 142 | + # E - send GSA sentences |
| 143 | + # F - send GSV sentences |
| 144 | + # G - send GRS sentences |
| 145 | + # H - send GST sentences |
| 146 | + # I - send ZDA sentences |
| 147 | +
|
| 148 | + # The number is how often to send the sentence compared to the update frequency. |
| 149 | + # If the update frequency is 500ms and the number is 5, it will send that message |
| 150 | + # every 2.5 seconds. |
| 151 | +
|
| 152 | +**Note:** Be aware that some data types send multiple sentences per update. So |
| 153 | +if you ask for 5 different types of data at 1Hz, you need to be able to handle |
| 154 | +at least 10 sentences per second. If the data is not read fast enough, the |
| 155 | +internal buffer and backlog behaviour is not specified. |
| 156 | + |
| 157 | +Poll for data |
| 158 | +------------- |
| 159 | + |
| 160 | +.. code-block:: python |
| 161 | +
|
| 162 | + while True: |
| 163 | + if gps.update(): |
| 164 | + # A valid sentence was received - do something |
| 165 | + if gps.has_fix: |
| 166 | + print(f"{gps.latitude:.6f},{gps.longitude:.6f}") |
| 167 | + else: |
| 168 | + print("Waiting for a fix...") |
| 169 | + else: |
| 170 | + # No valid sentence was received, wait a moment. |
| 171 | + time.sleep(100) |
| 172 | +
|
| 173 | +The `update()` call takes care of reading data from the device and parsing it |
| 174 | +into usable data. This can then be accessed using the property accessors, eg. |
| 175 | +`has_fix`, `datetime`, latitude, longitude etc. |
| 176 | + |
| 177 | +Selected Data Types |
| 178 | +=================== |
| 179 | + |
| 180 | +RMC - Recommended Minimum Navigation Information |
| 181 | +------------------------------------------------ |
| 182 | +:: |
| 183 | + |
| 184 | + 1 2 3 4 5 6 7 8 9 10 11 12 |
| 185 | + | | | | | | | | | | | | |
| 186 | + $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh |
| 187 | + $GNRMC,001031.00,A,4404.13993,N,12118.86023,W,0.146,,100117,,,A*7B |
| 188 | + |
| 189 | +1. Time (UTC) |
| 190 | +2. Status, A = Valid, V = Warning |
| 191 | +3. Latitude |
| 192 | +4. N or S |
| 193 | +5. Longitude |
| 194 | +6. E or W |
| 195 | +7. Speed over ground, knots |
| 196 | +8. Track made good, degrees true |
| 197 | +9. Date, ddmmyy |
| 198 | +10. Magnetic Variation, degrees |
| 199 | +11. E or W |
| 200 | +12. FAA mode indicator (NMEA 2.3 and later) |
| 201 | +13. Checksum |
| 202 | + |
| 203 | +GGA - Global Positioning System Fix Data |
| 204 | +---------------------------------------- |
| 205 | +:: |
| 206 | + |
| 207 | + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
| 208 | + | | | | | | | | | | | | | | | |
| 209 | + $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh |
| 210 | + $GNGGA,001043.00,4404.14036,N,12118.85961,W,1,12,0.98,1113.0,M,-21.3,M,,*47 |
| 211 | + |
| 212 | +1. Time (UTC) |
| 213 | +2. Latitude |
| 214 | +3. N or S (North or South) |
| 215 | +4. Longitude |
| 216 | +5. E or W (East or West) |
| 217 | +6. GPS Quality Indicator: |
| 218 | + |
| 219 | + 0. Fix not available |
| 220 | + 1. GPS fix |
| 221 | + 2. Differential GPS fix |
| 222 | + 3. PPS fix (values above 2 are NMEA 0183 v2.3 features) |
| 223 | + 4. Real Time Kinematic |
| 224 | + 5. Float RTK |
| 225 | + 6. Estimated (dead reckoning) |
| 226 | + 7. Manual input mode |
| 227 | + 8. Simulation mode |
| 228 | + |
| 229 | +7. Number of satellites in view, 00 - 12 |
| 230 | +8. Horizontal dilution of precision |
| 231 | +9. Antenna altitude above/below mean-sea-level (geoid) |
| 232 | +10. Units of antenna altitude, meters |
| 233 | +11. Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid |
| 234 | +12. Units of geoidal separation, meters |
| 235 | +13. Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, empty field when DGPS is not used |
| 236 | +14. Differential reference station ID, 0000-1023 |
| 237 | +15. Checksum |
| 238 | + |
| 239 | +Info about NMEA taken from `here (2001) |
| 240 | +<https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf>`_. |
| 241 | +and `here (2021) |
| 242 | +<https://gpsd.gitlab.io/gpsd/NMEA.html>`_ |
0 commit comments