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
702 Responses → “TinyGPS”

  1. Nagesh

    14 years ago

    Is this library compliant with NMEA 2000 ? I think, I looked at the obvious places but couldn’t conclude the compliance or non-compliance with NMEA 2000. Also, would you know of GPS modules NMEA 2000 compliant ?


  2. jesús

    14 years ago


  3. Mikal

    14 years ago

    @Nagesh,

    Gee, I don’t know. Where’s the NMEA 2000 spec documented?


  4. Mikal

    14 years ago

    @jesús,

    excellent, thanks for sharing!


  5. Syafruddin

    14 years ago

    Gmana ya cara memprogram ulang Tiny GPS 10,GPS q lg problem,muncul kotak2 hitam.


  6. Austin

    14 years ago

    Mikal,

    I’m using a Copernicus II Dip module (http://www.sparkfun.com/products/11067) with an Arduino UNO board. I’m trying to run the simple_test which comes with the TinyGPS library that you have on your page. When I run it, everything compiles nice, but I don’t get any data coming in.

    This is what I get…

    Simple TinyGPS library v. 12
    by Mikal Hart

    CHARS=0 SENTENCES=0 CSUM ERR=0
    CHARS=0 SENTENCES=0 CSUM ERR=0…(repeating endlessly).

    I understand the code and see that newData is never set to true.

    Why would this be? Problem with the chip? Problem with the Antenna?
    I am using an antenna through a BNC converter…it’s not in great shape.

    Also, I have Rx-B going to pin D0-RX and the Tx-B going to D1-RX and I’m using 4800 baud.

    Please let me know if you have any suggestions or if you would like any more info!!

    Thanks!!


  7. Mikal

    14 years ago

    Austin,

    When debugging a GPS application, the first thing you need to do is determine whether you’re getting any data at all from the module. The “CHARS=0” suggests not, but the quickest way to say for sure is to simply Serial.write() the values coming from the GPS. My best guess is that you have the wiring reversed. Remember that if a pin is labeled RX on the GPS, that means RX *from the GPS point of view*. You connect it to the *TX* pin on the Arduino.

    It’s not the antenna, because even when my GPS modules aren’t getting any fix they still transmit some data to the Arduino.


  8. Derrick

    14 years ago

    Hey Mikal,
    I’m getting chars through, but it seems to think the sentences are invalid? It’s failing the check some, but when i check serial spew with a pc comm port it looks like im getting clean sentences? I’m using a
    A1035-H Module with a MAX3244 level shifter connected to my arduino. http://datasheets.maxim-ic.com/en/ds/MAX3224E-MAX3245E.pdf

    Any suggestions on possible debug steps?
    Thanks in advance, this is a nice library.
    -Derrick


  9. Mikal

    14 years ago

    @Derrick,

    If you have proven to your satisfaction that valid-looking NMEA sentences are indeed coming through, it is most likely that you are experiencing overflow. Could you check the value of nss.overflow()? (I assume you’re using a software serial to communicate with the GPS?)

    Overflow is caused when you are processing incoming characters slower than they are transmitted. Some modules when send out a ton of characters at once, and this overflows the 64-byte NSS buffer.

    What do the TinyGPS sample applications report?

    M


  10. Derrick

    14 years ago

    Got it! Guess I dont need that xcvr! Works great.


  11. Austin

    14 years ago

    Mikal!

    Thank you so much for the advice. I ended up having the RX and the TX pins switched going to the Arduino. After i fixed this, the Copernicus II ran fine. I got the coordinates for my house and thought I was golden. However, I’ve run into a new problem, the Copernicus won’t update it’s position. I’ve tried it at two other locations (~ 100 miles from my house) and it still gives me the coordinates of my house. I’m not sure if this is a programming problem or a hardware issue.

    When I try to upload a new code to the Arduino, it compiles, uploads, and gives me…

    avrdude: stk500_getsync(): not in sync: resp=0x00

    Then it runs the previous program again pumping out the same coordinates.

    I have the XRST pin connected to 3.3v…I assume this resets the device.

    Again, if you have any suggestions I would really appreciate to hear them and also let me know if you need anymore info.

    Thanks!!


  12. Austin

    14 years ago

    Forgot to say that I also have a 10k ohm resistor on the XRST pin.


  13. Steve Berl

    14 years ago

    I was curious if my GPS was using DGPS/SBAS/WAAS or not, so I added a variable and a method to track and retrieve the Fix Quality term of the GPGGA sentence.

    Are you interested in the diffs?

    -steve


  14. Chris Spurgeon

    14 years ago

    Is there a way to have the tinyGPS code dump out the raw $GPGGA line all at once (as opposed to the character-by-character method that you would get by just echoing out the serial data from the GPS)? I want to log the lines to a SD card, but I also want to write additional information to the card between $GPGGA lines. There doesn’t seem to be a function to do that.

    Thanks!


  15. D

    14 years ago

    Hi Mikal,
    I was looking through the TinyGPS.h header to find where you discard any partial sentences? I want to disable that feature so I can process RMC data even if no satalites are in view. Is this possible?
    Thanks,
    -d


  16. Mikal

    14 years ago

    @Steve Berl,

    Yep! Actually, I’m working on an idea that would allow you to extract any field. Send away…!


  17. Mikal

    14 years ago

    @Chris Spurgeon,

    Part of the design methodology for TinyGPS is I expressly don’t want to ever store the entire sentence. It doesn’t seem too hard to do what you envision though. Just write the characters to the SD yourself, and then whenever encode() returns true also write the parsed data from TinyGPS. Note that writing to an SD card will probably cause you to lose some data, because those writes are pretty slow.


  18. Mikal

    14 years ago

    @D,

    I’m a little confused by your comment. First of all, if there are no satellites, I don’t think you’ll have any reasonable RMC data, will you? Secondly, TinyGPS only discards a sentence if its checksum fails, indicating corrupted or missing data. Even when it doesn’t see any satellites, a GPS module is supposed to generate valid NMEA sentences. They may not contain any useful data, but they are valid and aren’t discarded.


  19. ASiefert

    14 years ago

    Hello, Mikal. Thanks for such a handy library.

    Unfortunately, my device seems to have suddenly stopped recognizing GPMRC sentences, as I get only invalid values for speed and course. I checked the output of my GPS and it seems to be in order:

    $GPRMC,062132.000,A,3404.5087,N,11742.5844,W,0.10,225.72,070512,,,A*7D
    $GPGGA,062133.000,3404.5088,N,11742.5848,W,1,08,1.0,317.2,M,-33.0,M,,0000*6E
    $GPGSA,A,3,12,04,25,09,10,05,02,27,,,,,2.1,1.0,1.9*32
    $GPRMC,062133.000,A,3404.5088,N,11742.5848,W,0.29,250.08,070512,,,A*7A

    I used to get course and speed just fine, but now I can’t. Any ideas?


  20. Amaynard

    14 years ago

    Hi keep getting alot of defind errors delcared void can any input?
    its for a fio cat tracker thanks for all your hard work


  21. Mikal

    14 years ago

    A Siefert,
    Are you using [New]SoftSerial to communicate with the GPS? If so, check nss.overflow() to see if you are losing characters. I bet that’s the case. I bet you are not processing the data as fast as it’s arriving.


  22. Mikal

    14 years ago

    Amaynard,

    Love the Fio cat tracker idea. We want to build one of those too. Make sure you get the latest versions of Arduino and all the libraries and they should work together ok.


  23. ADRIANA

    14 years ago

    hola disculpa TinyGPS ES COMPATIBLE CON ARDUINO NG Atmega8 estoy haciendo un dataloger y esto utilizando el GPS FV-M8 y me gustaria saber si es compatible o hay una libreria para la version 0022 de arduino esque no me corre el ejemplo de la libreria llamado static_test me dice que es el sketch es demaciado grande gracias


  24. Mikal

    14 years ago

    Does anyone know if TinyGPS is small enough to work with Atmega8? I imagine it should work fin.


  25. D

    14 years ago

    Mikal,
    Sorry if my question was unclear. I’m trying to get date and time regardless of satellites in view. GPRMC sentences have good time data available via real time clock on the module. This is the sentence that the datetime crack seems to not like. “$GPRMC,184104.706,V,,,,,,,020512,,,N*40”
    As soon as I move within view of a satellite the datetime crack works as expected.
    Any thoughts?

    Thanks,
    D


  26. Germano Freitas

    14 years ago

    hello. It is not clear for me if HDOP is returning an absulte value or a value multiplied by a constant such as 10^1 or 10^2, in the same way angles are returned as integers. I have read HDOP values in the order of 80-100 which I found high. Could anyone help? Thanks, Germano


  27. D

    14 years ago

    FYI for anyone else who is looking to do the same thing as me..
    In TinyGPS.cpp included in the download change
    _gps_data_good(false) to _gps_data_good(true) everywhere its called.
    -d


  28. Eight

    14 years ago

    When I run…

    gps.get_datetime(&date, &time, &fix_age);

    … is the date and time returned the last data received from the GPS, or has it been adjusted to the current time? If it has not been adjusted, I assume I should be able to add the fix_age to the returned time to get the current time. It would just be sweeter if it IS adjusted.


  29. Mikal

    14 years ago

    @Germano,

    You are right. The HDOP value returned is multiplied by 100 before it is returned, just like the angles are. Sorry about the unclear documentation!


  30. Mikal

    14 years ago

    @Eight,

    The value returned by get_datetime is the very latest value that was seen in the NMEA stream. If you’re getting a healthy fix, this should always be accurate close to within 1 second, because every device I’ve seen updates the value at least once a second. If you want to be even closer to true time, you might add the “fix_age” value in, but even then you’d be a bit behind because there will be some lag between the time TinyGPS samples the data and the time you actually obtain it.


  31. Jan

    14 years ago

    Mikal,
    do you have a version available which only supports
    latitude and longitude
    distance_to()
    course_to()
    – so to say a “tinybasicGPS”
    Thanks Jan


  32. AndyDandy

    14 years ago

    Hello,

    can you pleae help me out how to find the right Rx and Tx pins for an antrax gps module communicating via SPI (4-wire) interface? http://www.antrax.de/site/Onlineshop/Home/Arduino-Komponenten:::370_386_378.html

    Thanks a lot!


  33. Mikal

    14 years ago

    Sorry, no, Jan. Are you having space problems with TinyGPS? That’s a little unusual.


  34. Jochen

    14 years ago

    Hello,

    with the GPS emulator, my code works nearly faultless inclusive Course, speed, course_to.

    But when I test the code with the “real” GPS Module if problems with Course, Speed, course to. In the other way with the emulator the number of sattelites are not correct.

    If I compare the two nmea strings i see that there are values missing on the “real GPS” string.

    MTK3339 Globaltop PA6C
    $GPRMC,194849.000,A,xxxx.xxxx,N,0xxxx.xxxx,E,0.31,247.57,070612,,,A*6A
    $GPGGA,194849.500,xxxx.xxxx,N,0xxxx.xxxx,E,1,7,1.19,361.3,M,47.6,M,,*52

    Emulator
    $GPRMC,195101.609,A,xxxx.xxxx,N,0xxxx.xxxx,E,0.0,0,060712,003.1,E*76
    $GPGGA,195101.609,xxxx.xxxx,N,0xxxx.xxxx,E,1,08,0,9,300,M,0,M,,*6C

    Anyone an idea??


  35. berm

    14 years ago

    Mikal,
    Thank you very much for good lessons and examples.I’ve just study in arduino for 2 weeks.I will try my best to finish my project.

    just want to say Thanks.


  36. Ari

    14 years ago

    Hi Mikal,
    I implemented your test_with_gps_device code. It compiles, and prints out the headers – long, lat,& etc. But the data is all *****
    The 3.3v pin from Arduino UNO board goes to 3.3v pin on the GPS.
    UNO ground to GPS ground.
    UNO 3 pin to GPS tx.
    It seems that the GPS receiver is not locking on to the GPS Satellites.

    What should I do?


  37. Ari

    14 years ago

    Hello Mikal,

    When I run your code, the column headers (longitude, latitude, and etc.) are printed out. However, the entries are all *****

    I used the connections based on
    http://www.doctormonk.com/2012/05/sparkfun-venus-gps-and-arduino.html

    which says to:

    Make the following connections

    The red lead goes from 3.3V Arduino to 3.3V GPS Module
    The blue lead, GND to GND
    The yellow lead Arduino Pin 10 to TX0 on the GPS Module

    However, since it says in your code that RX should be on Pin 3,
    I connected the wire from GPS pin TX0 to Arduino UNO Pin 3.

    What should I do? I am using the “newest” version of Arduino obtained via Ubuntu 12.04.


  38. dan z

    14 years ago

    Hi,

    Im having a problem trying to run this code. gps.encode(c) never validates or returns a true value even when it get 2D or 3D fix . I could use some help.

    Thank you!


  39. dan z

    14 years ago

    And i forgot to say, I’m using a haicom HI-204III gps receiver.


  40. andrew m

    14 years ago

    Do we have docs as to the parameters , variables that TinyGPS can give us ?
    or do I have to understand the code ?

    Sorry, but not a native C++ programmer, trying to be, but not having docs on place is a pain.


  41. Mikal

    14 years ago

    berm,

    :)


  42. Mikal

    14 years ago

    @Ari,

    The first thing you should do when debugging issues like this is print out the raw NMEA data from the device. Will the 3.3V device even work with the 5V Uno?


  43. Mikal

    14 years ago

    @Ari, does Dr. Monk’s sample code work?

7 Trackbacks For This Post
  1. Anonymous

    […] […]

  2. Jacket Positioning System: JPS « Titles are Strange Things

    […] it’s pretty simple. It only does those functions, but with the help of the truly fantastic TinyGPS library, I have a destination function in the […]

  3. Testing MTK3329 10Hz GPS module and making an Arduino GPS logger | Develop with Arduino

    […] TinyGPS for Arduino […]

  4. Arduino + GPS Shield + LCD 16x2 | We Are The Electric Brothers

    […] tinygps […]

  5. TinyGPS Libraryを使ってGPSデータを取得

    […] ちなみに、データ処理部分は、TinyGPS Libraryなる便利なものがあったので、それを使ってみた。 […]

  6. GPS приемник на базе модуля Quectel L30 | Arduino Market

    […] Библиотека для работы с GPS/NMEA для Arduino (TinyGPS) […]

  7. Using SKYLAB SKM53 GPS with Arduino

    […] Download TinyGPS her […]

Leave a Reply