Saturday, June 21, 2014

GPS Location Sensing with the Arduino Mega

This project shows how to get location in latitude and longitude coordinates using an electronic circuit built with the Arduino Mega 2560 and the ITEAD GPS Shield v1.1 . If you want to see how to do GPS location sensing with the Arduino Uno and an LCD display check out my other blog.

The GPS shield has a GPS antenna connected. This is very important as you can't get a location fix if you don't have an antenna.

Using this circuit I got a location fix indoors on the ground floor of a 2 story house in 1 to 2 minutes. Outdoors it got a fix in about 30s or less. Accuracy was very good, to within 10-20ft initially, and improving the longer you leave it (it gets a new reading every second.

The wiring of this diagram is straightforward. First you should set the voltage switch on your GPS shield to 5v before you power it on and connect it up. There is also a 3.3v setting, but for our circuit we are using the Arduino Mega 2560 so the voltage setting I used is 5v. Next you need to set the jumpers for Rx (receive) and Tx (transmit) on the GPS shield. I set my GPS Rx to pin 6 and GPS Tx to pin 5. I wanted to receive the output of this circuit on my computer so I needed the default hardware serial interface for that. To communicate with the GPS shield I used the mega hardware serial interface 1. So I wired GPS Rx pin 6 to Mega Serial1 Tx1 pin 18, and GPS Tx pin 5 to Mega Serial 1 Rx1 pin 19. Using this circuit I was able to get a location fix even inside a house on the ground floor of a 2 story house. If used outside with a clear view of the sky it will get a GPS fix even faster.

You will need TinyGPS to run the sketch I used. Specifically you will need the TinyGPS.cpp and TinyGPS.h files to run this. I just dropped them in the same folder as the Arduino sketch and then when I loaded the sketch the Arduino IDE automatically found these two files and compiled and uploaded them with my sketch to the Mega for testing.

Below is a screenshot of the Arduino IDE serial console showing output from this sketch running. The GPS latitude / longitude coordinates each have a precision of 6 decimal places.

Below is the Arduino sketch I used for testing:

#include "TinyGPS.h"

TinyGPS gps;

#define GPS_TX_DIGITAL_OUT_PIN 5
#define GPS_RX_DIGITAL_OUT_PIN 6

long startMillis;
long secondsToFirstLocation = 0;

#define DEBUG

float latitude = 0.0;
float longitude = 0.0;

void setup()
{
  #ifdef DEBUG
  Serial.begin(19200);
  #endif
  
  // Serial1 is GPS
  Serial1.begin(9600);
  
  // prevent controller pins 5 and 6 from interfering with the comms from GPS
  pinMode(GPS_TX_DIGITAL_OUT_PIN, INPUT);
  pinMode(GPS_RX_DIGITAL_OUT_PIN, INPUT);
  
  startMillis = millis();
  Serial.println("Starting");
}

void loop()
{
  readLocation();
}

//--------------------------------------------------------------------------------------------
void readLocation(){
  bool newData = false;
  unsigned long chars = 0;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (Serial1.available())
    {
      int c = Serial1.read();
//      Serial.print((char)c); // if you uncomment this you will see the raw data from the GPS
      ++chars;
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }
  
  if (newData)
  {
    // we have a location fix so output the lat / long and time to acquire
    if(secondsToFirstLocation == 0){
      secondsToFirstLocation = (millis() - startMillis) / 1000;
      Serial.print("Acquired in:");
      Serial.print(secondsToFirstLocation);
      Serial.println("s");
    }
    
    unsigned long age;
    gps.f_get_position(&latitude, &longitude, &age);
    
    latitude == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : latitude;
    longitude == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : longitude;
    
    Serial.print("Location: ");
    Serial.print(latitude, 6);
    Serial.print(" , ");
    Serial.print(longitude, 6);
    Serial.println("");
  }
  
  if (chars == 0){
    // if you haven't got any chars then likely a wiring issue
    Serial.println("Check wiring");
  }
  else if(secondsToFirstLocation == 0){
    // still working
  }
}


If you are interested in how location sensing can be integrated into a broader solution that includes notification of location and geo-fence alerts on a users Android phone see Geo-Fencing

Hope you found this useful. Let me know if you create any cool enhancements to it. Have fun!

If you need any of the parts for this projects you can find them below:

31 comments:

  1. Hello David.

    I folow exactly this steps but mu serial monitor show only
    "Starting
    Check wiring
    Check wiring (infinite Check wiring)"

    Do you help-me?

    ReplyDelete
    Replies
    1. Hi, when "Check wiring" shows it usually means one or more of your connections is different from what the sketch is expecting. Can you confirm your jumper settings on the GPS shield are Tx on pin 5 and Rx on pin 6, and that you have connected these to the Serial 1 pins as shown in the photo I provided? Once you double check these, try uncomment the Serial.print((char)c); and see if there is any data from the GPS.

      Delete
  2. Hi David,

    I followed your example and I only get "Starting".
    This means I don't have GPS fixed right? How do you solve this?
    I have the antenna attached. I even stretch the line all the way out.
    TinyGPS example shows ********.

    -Frank

    ReplyDelete
    Replies
    1. Hi Frank. Are you inside? I have tested in a 2 story house on the bottom level and it worked, but acquisition time was longer. Outside it gets a fix sooner. You might also try uncommenting the line in the sketch above "Serial.print((char)c); " which will print out the raw data from the GPS. You should see lots of raw GPS data, FYI more about this at http://www.gpsinformation.org/dale/nmea.htm . If you don't see lots of raw data with this line uncommented then check your wiring to ensure you got the jumpers and wiring correct. Let us know how it goes.

      Delete
    2. Hi Davide,

      I tried it outside and it doesn't work...
      I checked the wiring again and again and it is the same as yours.
      Do you know whats wrong?

      Thanks!

      Delete
    3. Did you uncomment the line to see the raw GPS input? Are you seeing raw input or nothing?

      Delete
    4. Hello,

      If I uncomment the line I get things like these:
      "Starting
      !%¡¥!¡• RŒœ
      ¡¡%±†ŒŒ¬ í‡%¥¥µ%††
      Z±!%5±5±5±¥1¡ iΡ5¡!!%$€¥!¡!5Ô !%¡¥!¡• RŒœ
      ¡¡%±†Œ¬¬ í‡%¥¥µ%††
      Z±!%5±5±5±¥1¡ iΡ5¡!!%$€¥!¡!5ã !†RŒ!¥"

      Delete
    5. Ah, it seems like it is working now, I just had to change the baud rate of Serial1 to 38400. Thank you for your help!

      Delete
    6. Thanks for the update. Makes sense. Garbled output usually means the baud rate is off. Glad you were able to get it working.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Your blog is really helps for my search and amazingly it was on my searching criteria.. Thanks a lot.

    gps antenna manufacturers & cell phone booster antenna

    ReplyDelete
  5. Hi David! I'm from Brazil.

    I made these same steps, but the serial monitor is showing only "îÖOþ"
    I changed the Serial1 9600 to 38400, but still showing the same thing.

    The TinyGPS library is in the root folder of the Arduino with the other libraries.
    I'm not using an external source, only the Arduino USB connected PC.

    What might be going wrong?

    ReplyDelete
    Replies
    1. Hi Roger, I believe the way it is trying to load the TinyGPS.h in the sketch it will look for it in the same folder as the Arduino sketch, along with TinyGPS.cpp. That is where I have it. Once you copy these two files I recommend restart Arduino IDE and reload your sketch. You should see the TinyGPS files load alongside in different tabs. I recommend leave the serial rates as they are in the sketch above, and check the serial rate of your Arduino console which should be 19200. Make sure you have your GPS antenna connected. Also, make sure you have your jumpers set correctly on the GPS shield and serial connections to the Mega. Have fun.

      Delete
    2. Now the GPS is working.
      My Serial1 is with 38400 and console IDE is 19200.
      With that I can see the data readable with Serial.print((char) c)... But gps.encode () is always returning false. I left working for a long time with failure.

      Delete
    3. Example response:

      Starting
      $GPRMC,143830.00,V,,,,,,,230315,,,N*76
      $GPVTG,,,,,,,,,N*30
      $GPGGA,143830.00,,,,,0,00,99.99,,,,,,*6B
      $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
      $GPGSV,1,1,01,21,,,33*7B
      $GPGLL,,,,,143830.00,V,N*47

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. HI

    Could you please help in this.
    I just copy paste this code and ran and got this error
    'Serial1' was not declared in this scope--Error message.
    I am new to this as could u pls help. I can figure it out like i have not added some thing in serial lib so pls guide me..Thanks

    ReplyDelete
    Replies
    1. You are probably getting this error because you do not have the right board selected in the Arduino IDE. To change the board selection, go to the top menu in the IDE and select Tools->Board, and then select Adruino Mega 2560

      Delete
  8. thanks for this post.it helped me a lot.

    ReplyDelete
  9. Hii!! my console baud rate is 9600 and that of gps is 4800(as it is specified in product sheet). I m getting Sarting and then some characters for Serial.print((char)c). but the encode function is returning false forever. What should I do?

    ReplyDelete
  10. Hi, my name is William and I am from Brazil.
    The code is running perfectly, but I need to get these data in a high frequency.
    Anybody knows how could I do that? Is this something that I could modify in the library?

    ReplyDelete
  11. I got the code to work but is there a way to have the code print out the other stuff like date , time, speed, altitude, angle , fix, satellite .. etc. the other thing is , how would the code be if we want to write it on the SD card exactly like what the serial monitor would show which is a readable sentences not the nmea sentences.
    thanks a lot

    ReplyDelete
    Replies
    1. Hey Mostafa, where you able to find a code to write on SD card of this shield?

      Delete
  12. Spying on someone do not need to be that hard. You can just download a simple app like that and get all the information you need.

    ReplyDelete
  13. thank you so much!!
    I would like to know, is it possible to send the location to a mobile phone?

    ReplyDelete
  14. Everything is working great! But do you have an idea how to store the data to the SD card because there is an sd slot available
    Thanks

    ReplyDelete
  15. Hello, thank you so much for your example!!! I'm runing it well, but I'm receiving grong data values Year: 2000, Month: 0, Day: 0. I'm running it over the Arduino Due board.
    Thanks for your atention.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete