Lab 04a: Where are they now

The questions below are due on Thursday March 01, 2018; 09:55:00 PM.


Partners: You have not yet been assigned a partner for this lab.
You are not logged in.

If you are a current student, please Log In for full access to the web site.
Note that this link will take you to an external site (https://oidc.mit.edu) to authenticate, and then you will be redirected back to this page.

Music of My Youth

 

Goals:

In this lab, you will learn how to use the GPS module to acquire location data, and you'll write code to parse that data and figure out where you are.

1) Today's to-do

First, we'll hook up the GPS module. Then we'll learn how to decode the standard statements that are sent by GPS modules, and check to see if our reported location is accurate. Finally, we'll create a GPS parser to extract out the relevant data from a GPS statement and display it on our screen.

2) Getting Started

The code for today's Lab can be found here.

2.1) Adding the GPS module

We'll be using the ATGM336H-5N GNSS module for GPS signal acquisition in this class. GNSS stands for Global Navigation Satellite System, of which GPS (Global Positioning System) is a type. Other types of GNSS's include Galileo (Europe), and Beidou (Chinese/Southeast Asia). Awesomely, this chipset works with all of these.

The ATGM336H-5N Board. The thing dangling off the top is an Active Antenna.

The GNSS board communicates with the ESP32 using the UART protocol (Universal Asynchronous Receive Transmit), which is a two-wire protocol. We can create a serial object that we'll call gps to interface with it in code using the following syntax.

HardwareSerial gps(2);

In the setup function we'll then specify the pins we want to use with it using the following call:

gps.begin(9600,SERIAL_8N1,32,33);

Schematically, we'll need to integrate the GPS unit into our system in the way shown in the schematic below. Note the communication lines (TX and RX pins on the GPS) link to the IO32 and IO33 pins we specify in our serial object specification above. The GPS will also need a ground connection whereever is convenient, and we will power it using the third linear regulator (LDO3 that we used for the bright white LED in Lab 03B. We'll do this so that we can turn on or off the GPS as needed.

Our GNSS board requires four connections, two for power (a ground and a voltage source, and two for communications.

Place the module in this general area of your board since it'll allow easy mounting of the antenna to the top (using the adhesive layer on the antenna).

How we recommend placing your GPS/GNSS module. The antenna has an adhesive layer that can be peeled/exposed to allow us to reliably mount it at the top of our board like shown! Note that power for this device is coming from a separate linear regulator (LDO3).

3) Look at the raw data

With the GPS hooked up, open up gps_starter.ino from this week's code distribution, compile, and upload it to the ESP32. It is an extremely simple script, but let's take a look at the main part of it below. An empty String is created and while data is available from the GPS serial, it is appended onto this String. When there is no more available data, it will print only if the length of data is nonzero.

void parseGPS(){
  String data = "";
  if (gps.available()) {     // If anything comes in Serial1 (pins 0 & 1)
    data = gps.readStringUntil('\n'); // read it and send it out Serial (USB)
  }
  if (data.length()>0){
    Serial.println(data);
  }
}

The code reads from the UART port and stores the characters in a data variable. After it reads as much as is available from the gps, it prints data to the Serial monitor.

Compile and upload the code. Open the Serial Monitor. You should see something like this:

$GNGGA,,,,,,0,00,25.5,,,,,,*64
$GNGLL,,,,,,V,M*79
$GPGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5*02
$BDGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5*13
$GPGSV,1,1,01,07,,,34*78
$BDGSV,1,1,00*68
$GNRMC,,V,,,,,,,,,,M*4E
$GNVTG,,,,,,,,,M*2D
$GNZDA,,,,,,*56
$GPTXT,01,01,01,ANTENNA OK*35

After maybe one minute (or significantly less), the device will lock onto a satellite signal and will start to update these outputs with more data:

$GNGGA,005132.000,4221.6666,N,07105.5423,W,1,08,1.3,2.4,M,0.0,M,,*6F
$GNGLL,4221.6666,N,07105.5423,W,005132.000,A,A*56
$GPGSA,A,3,01,17,11,07,08,28,30,13,,,,,2.3,1.3,1.9*3A
$BDGSA,A,3,,,,,,,,,,,,,2.3,1.3,1.9*28
$GPGSV,3,1,10,01,63,136,23,07,44,194,26,08,36,058,27,11,77,100,23*71
$GPGSV,3,2,10,13,11,299,17,17,23,253,23,22,11,124,,28,55,313,23*70
$GPGSV,3,3,10,30,58,231,23,34,,,24*46
$BDGSV,1,1,00*68
$GNRMC,005536.000,A,4236.1732,N,07109.0595,W,0.00,0.00,230218,,,A*68
$GNVTG,0.00,T,,M,0.00,N,0.00,K,A*23
$GNZDA,005132.000,23,02,2018,00,00*45
$GPTXT,01,01,01,ANTENNA OK*35

These statements will be repeated over-and-over, as a new set of data is sent from the GPS module to the ESP32 every second.

The different lines mean different things, but in general are encoding a variety of GNSS information. A number of these lines give out GPS information in a variety of formats, while others work for other systems. For example, the readout below is clearly empty, but that line corresponds to the Beidou system which is only valid over South East Asia.

$BDGSA,A,3,,,,,,,,,,,,,1.4,0.8,1.1*2E

Like we said above, we have different types of GPS statements, like GNRMC, and GPGSV, etc. These are all industry-standard statements that virtually all GPS modules report. A nice explanation of all these statements, which are known as NMEA statements, can be found here. The GNGGA statement gives information as to the quality of the fix, while the GNVTG focuses on ground-speed information, etc. (Note that the statements listed in the link above all start with GP, while some of ours start with GN. This appears to be because we are using a GPS unit with support for more than just the GPS system. However, messages with the same last three letters (eg. GPGGA and GNGGA) report the same information, and are formatted the same way.)

In GPS-speak, we use the term "fix" to denote when the GPS unit has obtained enough information to discern, or fix, our location.

The line of interest here is the one that starts $GNRMC. Each following piece of data is delimited by a comma.

  • Time (Greenwich Mean Time) in hhmmss.milliseconds (usually milliseconds round to 0) for this module.
  • V meaning data is Void (invalid) or A meaning data is Active (valid)
  • 4 pieces of geolocation data (which will be empty before your GPS gets a fix)
  • Ground speed (in knots), estimated by the difference in subsequent locations
  • Tracking angle (in degrees), similarly estimated
  • Date in ddmmyy format
  • The rest is a checksum

The first time you power up your unit it may take a little bit of time to get a new fix, though in the 6.08 lab, it won't be too bad since we actually have a GPS repeater installed in the room1

The LED under the GPS board will be a steady red when there is no fix (it is hunting) and it will flash at approximately 1Hz when it has a fix and is reporting data.

So, it will start out looking something like this:

$GNRMC,,V,,,,,,,,,,M*4E

After some time, you should start seeing something more akin to:

$GNRMC,005536.000,A,4236.1732,N,07109.0595,W,0.00,0.00,230218,,,A*68

Now you notice that there is an A after the second comma, the time and date are correct (in UTC), and there is location information:

4236.1732,N,07109.0595,W

This means that we are at 42 degrees, 36.1732 minutes North, and 71 degrees, 09.0595 minutes West. You should also notice the the LED on the underside of the module is now blinking.

3.1) GPS Location Representations

An important aspect of GPS location data is that it is routinely presented in three slightly different ways. You need to be aware of the differences, lest you think you're in the wrong place!

  • Degrees, minutes and seconds (DMS). This will often look like 42^{\circ} 36' 10.4''N   71^{\circ} 9' 3.6''W.
  • Degrees and decimal minutes (DDM). In this representation, the whole minutes are listed and the seconds are converted into fractions of a minute, i.e., 21 seconds = 21/60 = 0.35 minutes. This would look like 42 36.1732 N, 71 9.0595 W. This is what we'll use today, and what our GPS gives us.
  • Decimal degrees (DD). Here the minutes range from 0 to 1. It takes the decimal minutes from above and divides that by 60 to range from 0 to 1, i.e., decimal degrees = degrees + decimal minutes/60. The location above would look like 42.0602887 N, 71.150992 W.

3.2) Check Our First Fix

Let's check if our received location is correct. In your browser, open Google Maps. We can't enter the numbers into Google Maps directly, we have to separate out the degrees and decimal minutes, and we have to use a + for N or E, and a - for S or W. For the location information from above, this translates to:

+42 36.1732, -71 09.0595

Type your location into the location box in Google Maps. Where are you?

Checkoff 1:
Show your Google Maps screen and Serial Monitor data to a staff member.

4) Parse the NMEA String

We want to be able to write our location to the OLED display, and as such we'll want to write a string parser that will pull out the time, date, latitude, and longitude and send that to the display. You should write a function called parseGPS that when called should populate a set of global variables with the parsed GPS data. These variables include:

  • String lat_from_gps: The latitude
  • String lon_from_gps: The longitude
  • String time_from_gps: The time (GMT is fine for this lab)
  • String date_from_gps: The date

The tricky thing about this parser, which is new for us, is that the string is continually being read in from the serial port. So we want to monitor the string until we see that it has a complete statement, and then take action. If we decode the string too early, it will be incomplete. If we wait too long, the string will be unnecessarily long. We've taken care of most of this by using the readStringUntil function, which guarantees we'll only be analyzing full lines of readout2

Your task is to complete the missing parts of gps_starter.ino:

  • Wait until data contains a complete GNRMC statement, and then extract the relevant information from that statement.

  • When parsing the information, look for common features that are guaranteed to exist in the String and use those as anchor points. We strongly recommend you try to find the commas inside the String. We also recommend utilizing member functions of the Arduino String Library

  • Update your OLED every time you receive a complete GNRMC statement.

  • Your code should not miss many updates, i.e., your algorithm shouldn't throw away more than an occasional valid $GNRMC statement.

  • If you need the degree symbol it can be placed by typing "\xB0" in your String.

Take care if you have a function that returns String objects! You must make sure you actually return one under all conditions. Failing to return anything can cause system crashes!

An example of how one could display their data.

Checkoff 2:
Show your working code to a staff member and explain your approach.

 
Footnotes

1 An antenna on the roof of 38 is channeled down to a small box above the water cooler and then it re-broadcasts the GPS signal for us. You can tell it doesn't have a fix not only because most entries are blank, and not only because the GNRMC statement has a "V" in it, but also because the LED on the bottom of the board will be red and not blink. When it gets a signal, it will start to blink: (click to return to text)

2 This is an extremely versatile function and you may findt his useful in lots of future work. (click to return to text)