TinyGPS

A Compact Arduino GPS/NMEA Parser

TinyGPS is designed to provide most of the NMEA GPS functionality I imagine an Arduino user would want – position, date, time, altitude, speed and course – without the large size that seems to accompany similar bodies of code.  To keep resource consumption low, the library avoids any mandatory floating point dependency and ignores all but a few key GPS fields.

Usage

To use, simply create an instance of an object like this:

#include "TinyGPS.h"
TinyGPS gps;

Feed the object serial NMEA data one character at a time using the encode() method. (TinyGPS does not handle retrieving serial data from a GPS unit.) When encode() returns “true”, a valid sentence has just changed the TinyGPS object’s internal state. For example:

#define RXPIN 3
#define TXPIN 2
SoftwareSerial nss(RXPIN, TXPIN);
void loop()
{
  while (nss.available())
  {
    int c = nss.read();
    if (gps.encode(c))
    {
      // process new gps info here
    }
  }
}

You can then query the object to get various tidbits of data. To test whether the data returned is stale, examine the (optional) parameter “fix_age” which returns the number of milliseconds since the data was encoded.

long lat, lon;
unsigned long fix_age, time, date, speed, course;
unsigned long chars;
unsigned short sentences, failed_checksum;

// retrieves +/- lat/long in 100000ths of a degree
gps.get_position(&lat, &lon, &fix_age);

// time in hhmmsscc, date in ddmmyy
gps.get_datetime(&date, &time, &fix_age);

// returns speed in 100ths of a knot
speed = gps.speed();

// course in 100ths of a degree
course = gps.course();

Statistics

The stats method provides a clue whether you are getting good data or not. It provides statistics that help with troubleshooting.

// statistics
gps.stats(&chars, &sentences, &failed_checksum);
  • chars – the number of characters fed to the object
  • sentences – the number of valid $GPGGA and $GPRMC sentences processed
  • failed_checksum – the number of sentences that failed the checksum test

Integral values

Values returned by the core TinyGPS methods are integral. Angular latitude and longitude measurements, for example, are provided in units of millionths of a degree, so instead of 90°30’00”, get_position() returns a longitude value of 90,500,000, or 90.5 degrees. But…

Using Floating Point

…for applications which are not resource constrained, it may be more convenient to use floating-point numbers. For these, TinyGPS offers several inline functions that return more easily-managed data. Don’t use these unless you can afford to link the floating-point libraries. Doing so may add 2000 or more bytes to the size of your application.

float flat, flon;

// returns +/- latitude/longitude in degrees
gps.f_get_position(&flat, &flon, &fix_age);
float falt = gps.f_altitude(); // +/- altitude in meters
float fc = gps.f_course(); // course in degrees
float fk = gps.f_speed_knots(); // speed in knots
float fmph = gps.f_speed_mph(); // speed in miles/hr
float fmps = gps.f_speed_mps(); // speed in m/sec
float fkmph = gps.f_speed_kmph(); // speed in km/hr

Date/time cracking

For more convenient access to date/time use this:

int year;
byte month, day, hour, minutes, second, hundredths;
unsigned long fix_age;

gps.crack_datetime(&year, &month, &day,
  &hour, &minute, &second, &hundredths, &fix_age);

Establishing a fix

TinyGPS objects depend on an external source, i.e. its host program, to feed valid and up-to-date NMEA GPS data. This is the only way to make sure that TinyGPS’s notion of the “fix” is current. Three things must happen to get valid position and time/date:

  1. You must feed the object serial NMEA data.
  2. The NMEA sentences must pass the checksum test.
  3. The NMEA sentences must report valid data. If the $GPRMC sentence reports a validity of “V” (void) instead of “A” (active), or if the $GPGGA sentence reports fix type “0” (no fix) then those sentences are discarded.

To test whether the TinyGPS object contains valid fix data, pass the address of an unsigned long variable for the “fix_age” parameter in the methods that support it. If the returned value is TinyGPS::GPS_INVALID_AGE, then you know the object has never received a valid fix. If not, then fix_age is the number of milliseconds since the last valid fix. If you are “feeding” the object regularly, fix_age should probably never get much over 1000. If fix_age starts getting large, that may be a sign that you once had a fix, but have lost it.

float flat, flon;
unsigned long fix_age; // returns +- latitude/longitude in degrees
gps.f_get_position(&flat, &flon, &fix_age);
if (fix_age == TinyGPS::GPS_INVALID_AGE)
  Serial.println("No fix detected");
else if (fix_age > 5000)
  Serial.println("Warning: possible stale data!");
else
  Serial.println("Data is current.");

Interfacing with Serial GPS

To get valid and timely GPS fixes, you must provide a reliable NMEA sentence feed. If your NMEA data is coming from a serial GPS unit, connect it to Arduino’s hardware serial port, or, if using a “soft” serial port, make sure that you are using a reliable SoftSerial library. As of this writing (Arduino 0013), the SoftwareSerial library provided with the IDE is inadequate. It’s best to use my NewSoftSerial library, which builds upon the fine work ladyada did with the AFSoftSerial library.

Library Version

You can retrieve the version of the TinyGPS library by calling the static member library_version().

int ver = TinyGPS::library_version();

Resource Consumption

Linking the TinyGPS library to your application adds approximately 2500 bytes to its size, unless you are invoking any of the f_* methods. These require the floating point libraries, which might add another 600+ bytes.

Download

The latest version of TinyGPS is available here: TinyGPS13.zip

Change Log

  1. initial version
  2. << streaming, supports $GPGGA for altitude, floating point inline functions
  3. also extract lat/long/time from $GPGGA for compatibility with devices with no $GPRMC
  4. bug fixes
  5. API re-org, attach separate fix_age’s to date/time and position.
  6. Prefer encode() over operator<<. Encode() returns boolean indicating whether TinyGPS object has changed state.
  7. Changed examples to use NewSoftSerial in lieu of AFSoftSerial; rearranged the distribution package.
  8. Greater precision in latitude and longitude.  Angles measured in 10-5 degrees instead of 10-4 as previously.  Some constants redefined.
  9. Minor bug fix release: the fix_age parameter of get_datetime() was not being set correctly.
  10. Added Maarten Lamers’ distance_to() as a static function.
  11. Arduino 1.0 compatibility
  12. Added satellites(), hdop(), course_to(), and cardinal()
  13. Improved precision in latitude and longitude rendering. get_position() now returns angles in millionths of a degree.

Acknowledgements

Many thanks to Arduino forum users mem and Brad Burleson for outstanding help in alpha testing this code. Thanks also to Maarten Lamers, who wrote the wiring library that originally gave me the idea of how to organize TinyGPS.  Thanks also to Dan P. for suggesting that I increase the lat/long precision in version 8.  Thanks to many people who suggested new useful features for TinyGPS, especially Matt Monson, who wrote some nice sample code to do so.

All input is appreciated.

Mikal Hart

Page last updated on August 31, 2013 at 7:00 pm
701 Responses → “TinyGPS”

  1. Ankit

    10 years ago

    Can you please explain how and where does the TinyGPS library do all the required calculations to get the fix?


  2. Mats

    10 years ago

    I’m trying to make a power budget for a TinyGPS.

    And does anyone have experience what the time is from cold start to have a fixed position. I know that it can vary depending on factors like clouds, partly seen sky and so on.


  3. nick

    10 years ago

    I have an unusual behaviour when it comes to your library.

    i have arduino duemilanove and em408
    My code is this:

    #include <Arduino.h>
    #include <TinyGPS.h>
    
    #define GPS_RX_PIN 2
    #define GPS_TX_PIN 3
    
    TinyGPS gps;
    SoftwareSerial ss(GPS_RX_PIN, GPS_TX_PIN);
    
    void setup()
    {
      Serial.begin(9600);
      ss.begin(4800); 
      }
    
    void loop()
    {
      while (ss.available())
      {
        char c = byte(ss.read());
        // Here i tried Serial.write(c); and i succesully saw the NMEA data in my serial monitor
        if (gps.encode(c))
        {
          long lat, lon;
         unsigned long fix_age;
        gps.get_position(&amp;lat, &amp;lon, &amp;fix_age);
        if (fix_age == TinyGPS::GPS_INVALID_AGE )
          Serial.println("No fix ever detected!");
        else if (fix_age &gt; 2000)
          Serial.println("Data is getting STALE!");
        else
          Serial.println("Latitude and longitude valid!");
    
          Serial.print("Lat: "); 
          Serial.print(lat);
          Serial.print(" Lon: "); 
          Serial.println(lon);
    
        }
        else Serial.println("Not encoded data!");
      }
    }
    

    My output is this:

    No data!
    No data!
    No data!
    No data!

    No data!
    No data!
    No data!
    No data!
    No data!
    No data!
    No data!
    No data!
    No data!
    Latitude and longitude valid!
    Lat: 32758239
    Lon: 15637489
    No data!
    No data!
    No data!
    No data!
    No data!
    No data!
    No data!

    And then i continue getting No data! forever…

    So… 1. Why does gps.encode() only manage to return true only 1 time? I have gotten the raw data from the gps (the commented code on my code snippet) and it’s ok. Why it returns true only one time?

    2. Why the longitude/latidude data is like this? As far as i know, this isnt valid, correct?


  4. Allan

    10 years ago

    Hi again Mikal.

    Please disregard my previous email for help.
    I have your excellent library working beautifully. Many thanks for that.

    My problem was simple. I downloaded the library and renamed it to TinyGPS.
    Unfortunately the files within the folder were still named TinyGPS13 (the current version).
    The compiler reported the Library as installed, when in fact it was not! I had extracted the files…. but of course they still had the old name within the new folder. Stupid me!
    It now works 100%.

    Kind regards,
    Allan (in sunny Scotland) :-)


  5. Mikal

    10 years ago

    @Ankit,

    The TinyGPS library doesn’t really do any calculations. It simply parses the data provided by the GPS module and presents it in a more convenient form.


  6. Mikal

    10 years ago

    @Mats, I get times of up to about 6 minutes with an absolutely cold EM-406A in poor conditions.


  7. Mikal

    10 years ago

    @Nick–

    Your problem is probably buffer overflow caused by the fact that your sketch is mostly working on printing “No data!”. Remove that “else Serial.println(“No data!”)” line and see if that helps.

    The lat/long values are reported in millionths of a degree, so if you are off the Libyan coast they are correct. If not, I can’t explain them. :)


  8. Dizzwold

    10 years ago

    Hi Mikal. Great library. Do you know of any code to transmit TinyGPSPlus data over 2 nrf24l01’s? 1 TX 1RX.


  9. Ben

    10 years ago

    G’day
    Fantastic Library! Love It.

    Have you considered option to allow use of TinyGPS::distance_between with longs instead of floats?


  10. Ben

    10 years ago

    Mikal & Users

    So many thanks – this really is a most fantastic piece of work.

    Kevin Walton & Terry Baume have forked previous versions to include some great additions for ublox recievers.
    Enabling the use of request / response gps updates instead of being hit with NMEA sentences constantly.
    I understand that your library has been designed to be non device specific, and further that the TinyGPS plus library has support for custom sentences, so I see why you have not rolled these additions into your source.

    I have updated Kevin and Terrys work to include your V13 updates and its available here: https://github.com/HarperBen/TinyGPS

    Again Mikal – thanks – through developing and releasing this library you saved me several days swearing at a gps module – Champion.


  11. Jonas

    10 years ago

    i want to send a complete sentence gpgga for example to an seial port…is there a command for tiny GPS for a complete sentence ???


  12. GOHO

    10 years ago

    Mikal , i want to ask u that how to show the calculating of the latitude and longitude in the program? and then how to show the value like an example -7.281495 that the value of the latitude, but on my program only show in serial.print in -7.28 like that…, can u explain to me please, thanks before…


  13. Mikal

    10 years ago

    What units would they be in, Ben?


  14. Mikal

    10 years ago

    @Jonas,

    TinyGPS is a parser. You can’t use it to transmit data.


  15. Mikal

    10 years ago

    @GOHO,

    Arduino prints floats with 2 decimals precision by default, but you can override this:

    Serial.print(lat, 6);
    

  16. Syah

    10 years ago

    I am using a Groove GPS module that uses ublox. How do I configure it in such away that it uses A-GPS?


  17. bbb

    10 years ago

    How can I print only new data from GPS not the same with previous? for example with comparing if will be new data!=previous data then to print serial .


  18. bbb

    10 years ago

    How can I print only new data not the same with previous? print to serial only new data changing


  19. Mikal

    10 years ago

    @bbb,

    There really isn’t a facility for detecting when the data changes, though you could test this manually. TinyGPS++ does have the facility to test for when a value is updated (though it might still have be the same number).


  20. Stanley

    10 years ago

    Hi, any plans to support BeiDou or GLONASS GPS module in the near future ?


  21. Alexis

    10 years ago

    Hello does it works with on an attiny85?
    thx


  22. Jose Domingues

    10 years ago

    Is TinyGPS compatible with Ublox Max-M8Q?
    I’ve been trying to test it using the example “test_with_gps_device” code and I can’t seem to get anything printed. I only get the RX chars and the Checksum. Sometimes checksum is zero, sometimes it’s another number, can’t figure out why this varies. But even when checksum is zero I can’t get any readings.
    I have tested Max-M8Q with PUBX example code and I do get a lock and readings.


  23. Ahmed Maher

    10 years ago

    I have skylab SKM53 GPS , and i use it with arduino , and I wish to get the speed , when I use the test_with_gps_device Example , I do not get any thing .. Why?!
    Thanks


  24. Charlie Harrison

    10 years ago

    This looks like a really good library. My only recommendation is that it adds support for DGPS data by outputting altitude and also there exists some NMEA strings that output magnetic declination which would also be useful to get.


  25. Longjohn

    10 years ago

    How hard would it be to to extend this library to parse NMEA depth and temperature data from a depthfinder so I can long that info along with the GPS coordinates? There are basically 3 sentences
    $SDDBT – Depth below transducer
    $SDDPT – Depth after finder adds the offset to DBT
    $SDMTW – water temperature


  26. Mikal

    9 years ago

    @Alexis, I haven’t tried it on ATTiny85, but I’m pretty certain it will work.


  27. Mikal

    9 years ago

    @Jose and @Ahmed Maher, can you print out a 3-second sample from the serial stream coming from your GPS?


  28. Mikal

    9 years ago

    @Charlie Harrison, I have tried not to support too many features that are unlikely to be used often (like magnetic declination). However, have your seen TinyGPS++? It supports custom sentences.


  29. Mikal

    9 years ago

    @Longjohn,

    Have you seen TinyGPS++? I would think it would be pretty easy to get these to work in TinyGPS++.


  30. Kurt Guldbaek

    9 years ago

    Hello.
    I am new in c-programming and Arduino.
    I am using tinyGPS++ in a project with 2 GPS in a kind of DGPS. Both GPS is logging data to SD. One is in the same pos all the time and the other is on a wagon, where the pos and magnetic field i logged. Later the data is compared to get the “real” pos of the wagon.
    For that porpose I would like to store the sentense from the GPS on the SD.
    Is it possible for me to add this feature?

    Kind regards Kurt


  31. Mikal

    9 years ago

    Hi Kurt,

    Yes, you can write the raw sentences to the SD. This doesn’t involve TinyGPS. When you get the character from the gps device with c = ss.read(); write it immediately to the SD card before (or after) you send it to gps.encode(). Remember that you have full control over the NMEA stream coming from the gps device.


  32. Samuel

    9 years ago

    Hi Mikal

    First I would like to thank you for both the TinyGPS and TinyGPS++

    My question regards lat. and long., is it possible to use lat and long to calculate the distance traveled? For example, when I power the GPS, it records lat and long and then begins calculating distance based on those first starting points?

    Thanks in advance


  33. Mikal

    9 years ago

    @Samuel–

    Yes, if you’ll capture the lat and long at the start and end points, then use the distance_between() member function, you can calculate the distance between them.


  34. Sid

    9 years ago

    I am using Skylab GPS module….. and i am trying to run the example code TinyGPS library. But i always get invalid values here is my code…..

    Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum
    (deg) (deg) Age Age (m) — from GPS —- —- to London —- RX RX Fail
    ————————————————————————————————————————————-
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 29 0 1
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 105 0 11
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 181 0 22
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 257 0 33
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 333 0 44
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 409 0 55
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 485 0 66
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 561 0 77
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 637 0 87
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 713 0 97
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 789 0 107
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 940 0 128
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 1017 0 139
    **** **** ********* ********** **** ********** ******** **** ****** ****** ***** *** ******* ****** *** 1093 0 150


  35. Samuel

    9 years ago

    Hi Mikal, it’s me again

    I previously asked you about the possibility of obtaining distance traveled using lat and long, I am wondering if you would mind showing me how. I am new to this arduino but it’s a project due in a two weeks.

    Thanks

    Samuel


  36. Mike Dzado

    9 years ago

    Hi Mikal

    I have question regarding the SKM53.
    Page 3 of the SKM53 datasheet states that the UART is full duplex and page 4 specifies the $GPSxx strings that are available. It has a table that shows which GPS strings are available by default. This implies that we can configure the SKM53 via the comm port to enable and disable the GPS strings we would like to use.

    I would like to disable the $GPGSV and $GPGSA sentences. They are not needed for our application and are flooding the Comm port. We just need time and location.

    Can you write to the SKM53? If so, what are the commands to enable and disable GPS strings?

    Thanks
    Mike


  37. Mikal

    9 years ago

    @Sid, I don’t think that GPS operates at 4800 baud. Try 9600?


  38. Mikal

    9 years ago

    @Mike, TinyGPS is a parser. You can’t use it to write. If you want to write to the SKM53, just write to the serial port that you opened.


  39. Jakub Dražan

    9 years ago

    Hello,
    sometimes during an inicialization gps, the library return true on gps.encode(c), but date sets as 2000/00/00 and correct time. On next method calling (in next second) sets date correctly, but im premising, if gps.encode(c) return true, a have a correct datetime.

    Can i fixed this bug in library?

    With regard, Jakub


  40. Mikal

    9 years ago

    @Jakub,

    I’m aware of this condition, but I’m hesitant to call it a bug. By definition, encode() returns TRUE when a sentence has been properly processed. If the GPS chipset returns a properly-formed sentence with no valid date but potentially useful information, I don’t think it’s correct to make encode() return FALSE in that case. I think the best practice is just to check to ignore the date as long as it is invalid.


  41. TRK

    9 years ago

    How can I save and restore the almanach orbital data for sleeping gps module over 2 min?

9 Trackbacks For This Post
  1. Arduino Development Journal/May 2014 | Surfing Satellites

    […] one extra sentence that is discarded by TinyGPS (a very cool library – check it out at http://arduiniana.org/libraries/tinygps/).  I corrected that and believe the GPS delivers the optimum number of sentences at 19200 baud to […]

  2. Tutorial – Arduino and MediaTek 3329 GPS » Geko Geek

    […] fly, so thankfully there is an Arduino library to do this for us – TinyGPS. So head over to the library website, download and install the library before […]

  3. Tutorial – Arduino and MediaTek 3329 GPS

    […] fly, so thankfully there is an Arduino library to do this for us – TinyGPS. So head over to the library website, download and install the library before […]

  4. GPS und Arduino | wer bastelt mit?

    […] Eine recht praktische und kompakte Library zum Parsen von GPS/NMEA Daten: TinyGPS […]

  5. Interfacing a USB GPS with an Arduino | Bayesian Adventures

    […] Library to connect to the shield and I modified the code a little to stream incoming data into Mikal Hart’s GPS Parser Library, TinyGPS. Here is the crux of the […]

  6. Freematics Blog – Users Guide for Arduino Telematics Kits

    […] TinyGPS Library […]

  7. Freematics Blog – Freematics OBD-II Adapter Programming Guide

    […] TinyGPS Library […]

  8. Spark Core and TinyGPS Library | devlper

    […] comes a sample application using Spark Core and TinyGPS library. TinyGPS is a very powerful and fast NMEA GPS parser for Arduino and compatible. In this […]

  9. Arduino UNO with GPS module(GY-GPS/NEO6MV2) - TFP

    […] the Arduino IDE, I shall directly skip on the coding part then. Our arduino sketch will require Tiny GPS library, which you can download it from here. Import the downloaded library to your Arduino IDE. […]

Leave a Reply