Go Down

Topic: TinyGPS Library: Making GPS small and easy (Read 16453 times) previous topic - next topic

mikalhart

Steffen,

Thanks for the kind words about TinyGPS and NewSoftSerial.

It looks like the Arduino with the ATMega328 is resetting itself, probably in response to a badly-handled serial interrupt.  There is a known bug with certain Arduino builds that causes software like NewSoftSerial to fail.  Are you using NewSoftSerial v. 5 or later?  We put a workaround into v5 for this problem, but the fix is very specific to avr-gcc 4.3.0 and the 168 chip, and may not work for the 328.

I am going to order some 328s to test with, but in the meanwhile, could you temporarily disconnect the GPS and prove that the problem goes away?

Another useful test would be to temporarily replace NewSoftSerial with AFSoftSerial to prove that the defect also affects AFSoftSerial.

Thanks for your help and feedback.

Mikal


Steffen Elste

Mikal,

i used v. 5 - noticed that You made v. 6 available in the meantime - i'm going to give the new version a try; i'll do a round with AFSoftSerial as well.
The compiler version i got is 4.3.2 - this is actually a Debian package, not the one that comes with Ubuntu, because a couple of people reported some serious bugs with that one.

I'll keep You posted!

Steffen

Steffen Elste

Hi Mikal,

after switching to v. 6 the error's gone!
Haven't tried switching to AFSoftSerial yet to see if the same weird behaviour applies there too ... and i'm not sure i could be easily convinced to do so ;-)

Thanks,

Steffen

mikalhart

#33
Feb 22, 2009, 10:49 pm Last Edit: Feb 23, 2009, 02:49 am by mikalhart Reason: 1
Steffan, I think that ladyada's modifications to NSS 5 (resulting in v6) probably is a good workaround for the 328p.  At this point I don't think you could convince me to try AFSoftSerial either -- for testing I mean. I think it will almost certainly exhibit the same problem.

Thank you very much for your feedback.

Mikal

mikalhart

Today I released TinyGPS version 8, which increases the precision of latitude and longitude, as reported by the get_position() and f_get_position() methods.  Thanks to DanP for the suggestion.

Mikal

trialex

#35
Apr 14, 2009, 09:01 am Last Edit: Apr 14, 2009, 09:25 am by trialex Reason: 1
Mikal,

Thanks heaps for your TinyGPS library.

I'm trying to use the TinyGPS library together with ladyada's AF_SDlog library. Unfortunately at the moment it seems they are not playing nice.

At the moment I've got a simple logging to SD sketch working, but as soon as I add

Code: [Select]

#include <TinyGPS.h>
TinyGPS gps;


I can no longer access the fat16 filesystem on the SD card - the AF_SDlog library reports a "Can't open filesys" error.

I'm looking through the libraries trying to find out what's incompatible - but I'm not a strong coder - anything past the standard arduino commands and I'm starting to get out of my depth.

Do you have any ideas or hints on where specifically I could look? Could it be a case of the 1k RAM limit being reached on a '168? Seems like an unusual symptom of that though.

Thanks for your help,

trialex


mikalhart

#36
Apr 14, 2009, 02:35 pm Last Edit: Apr 14, 2009, 08:59 pm by mikalhart Reason: 1
Hmm... curious.  TinyGPS is, well, pretty tiny.  I don't think it consumes more than ~100 bytes of RAM, but I guess it is possible that those 100 bytes put the system over the top.

You can slightly lower the RAM cost of TinyGPS by defining

Code: [Select]
#define _GPS_NO_STATS

before #including the header file.  Perhaps that will help.  I don't think there's any physical interaction problem, because TinyGPS doesn't do anything with the physical pins on the board.

Would it be possible to try an Arduino with a 328 chip?  Those have more RAM.

EDIT: Correction, you have to put _GPS_NO_STATS inside the header and then rebuild the library binary.

Mikal


duganj

Another thanks for the TinyGPS and NewSoftSerial libraries.

I'm using them both with a 328 Boarduino, eTrex GPS receiver and Parallax LCD.

I have the eTrex and LCD on their own NewSoftSerial ports and am using the hardware serial to display the GPS parsing example code on my computer serial port.

Question: I'm getting about 5% checksum errors, are there some possibile explanations for this?

I have TX pin of eTrex to GND and GND pin of eTrex to SoftSerial RX.

Should I look into using a MAX232 chip to invert the RS232 to TTL?

Do I need to have the RX pin of the GPS connected?

mikalhart

Quote
I have TX pin of eTrex to GND and GND pin of eTrex to SoftSerial RX.


Wow, cool.  I'm surprised that works at all.  Is that to overcome the inverted signal?  I'm toying with adding a signal inversion feature in a future NewSoftSerial.

What's the baud rate?  NewSoftSerial (or indeed any software serial) is inherently susceptible to corruption from internal interrupts, etc., and this is particular true at high baud rates.  Also, if the GPS sends data in rapid bursts, this could be a problem.  A 5% checksum failure rate is not too bad in certain circumstances.

Mikal

duganj

Yeah, the pin swapping was a cheap workaround for the inverted signal. I had seen discussion of it on a couple of other forums.

Perhaps hooking up the pins 'correctly' and using software to invert the signal would be a better option?

I'll also try the MAX232 chip which I believe can do the inversion.

The baud rate is 4800, std NMEA output.

mikalhart

Before abandoning that funky wiring, it might be instructive to view the NMEA bytes to the serial monitor to see if it tells you anything about the corruption.

If I were in your position, I would modify the NewSoftSerial sources to invert the signal (or wait for me to do it :)).  It's pretty easy: just change all the digitalReads and digitalWrites.  Of course I'm speaking as a software guy.  It may be easier for you to do a hardware inversion.  

But I think that it must have something to do with that wiring, because 4800 baud is pretty stable with NewSoftSerial.  Are you running any other interrupt-generating things?

Mikal

duganj

Thanks again for the reply. I haven't looked much more into the checksum errors. I did include the code I'm running, hacked together mostly from your work.

Code: [Select]
#include <NewSoftSerial.h>
#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
  It requires the use of NewSoftSerial, and assumes that you have a
  4800-baud serial GPS device hooked up on pins 2(rx) and 3(tx).
*/

TinyGPS gps;
NewSoftSerial nss(2, 3);
NewSoftSerial lcd(8, 9);

float flat, flon;

void gpsdump(TinyGPS &gps);
bool feedgps();
void printFloat(float f);

void setup()
{
 Serial.begin(19200);
 nss.begin(4800);
 lcd.begin(9600);
 delay(50);
 lcd.print(22,BYTE);
 delay(50);
 lcd.print(17,BYTE);
 delay(50);
 lcd.print(128,BYTE);
 delay(5);
 //lcd.print("Lat ");
 //lcd.print(148,BYTE);
 //delay(5);
 //lcd.print("Lon ");
 Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
 Serial.println("by Mikal Hart");
 Serial.println();
 Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
 Serial.println();
}

void loop()
{
 bool newdata = false;
 unsigned long start = millis();

 // Every 5 seconds we print an update
 while (millis() - start < 5000)
 {
   if (feedgps())
     newdata = true;
 }
 
 if (newdata)
 {
   Serial.println("Acquired Data");
   Serial.println("-------------");
   gpsdump(gps);
   Serial.println("-------------");
   Serial.println();
 }
}

void printFloat(float f)
{
 if (f < 0)
 {
   Serial.print('-');
   f = -f;
 }
 Serial.print(static_cast<int>(f));
 Serial.print('.');
 int temp = (f - static_cast<int>(f)) * 10000;
 if (temp < 10)
   Serial.print("000");
 else if (temp < 100)
   Serial.print("00");
 else if (temp < 1000)
   Serial.print("0");
 Serial.print(temp);
}

void gpsdump(TinyGPS &gps)
{
 long lat, lon;
 float flat, flon;
 unsigned long age, date, time, chars;
 int year;
 byte month, day, hour, minute, second, hundredths;
 unsigned short sentences, failed;

 gps.get_position(&lat, &lon, &age);
 Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon);
 //Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
 
 feedgps(); // If we don't feed the gps during this long routine, we may drop characters and get checksum errors

 gps.f_get_position(&flat, &flon, &age);
 Serial.print("Lat/Long(float): "); printFloat(flat); Serial.print(", "); printFloat(flon);
 //Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

 lcd.print(12,BYTE);
 delay(5);
 lcd.print(130,BYTE);
 printDouble(flat,100000);
// lcd.print(float(lat));
 lcd.print(148,BYTE);
// lcd.print(lon);
 printDouble(flon,100000);


 feedgps();

 gps.get_datetime(&date, &time, &age);
 Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): "); Serial.print(time);
// Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

 //feedgps();

 //gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
 //Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
 //Serial.print("  Time: "); Serial.print(static_cast<int>(hour)); Serial.print(":"); Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second)); Serial.print("."); Serial.print(static_cast<int>(hundredths));
 //Serial.print("  Fix age: ");  Serial.print(age); Serial.println("ms.");
 
 //lcd.print(148,BYTE);
 //lcd.print(static_cast<int>(month));
 //lcd.print("/");
 //lcd.print(static_cast<int>(day));
 //lcd.print("/");
 //lcd.print(year);
 //lcd.print(156,BYTE);
 //lcd.print(static_cast<int>(hour));
 //lcd.print(":");
 //lcd.print(static_cast<int>(minute));
 //lcd.print(":");
 //lcd.print(static_cast<int>(second));
 
 //feedgps();

 //Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): "); Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
 //Serial.print("Alt(float): "); printFloat(gps.f_altitude()); Serial.print(" Course(float): "); printFloat(gps.f_course()); Serial.println();
 //Serial.print("Speed(knots): "); printFloat(gps.f_speed_knots()); Serial.print(" (mph): ");  printFloat(gps.f_speed_mph());
 //Serial.print(" (mps): "); printFloat(gps.f_speed_mps()); Serial.print(" (kmph): "); printFloat(gps.f_speed_kmph()); Serial.println();

 feedgps();

 gps.stats(&chars, &sentences, &failed);
 Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: "); Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
}
 
bool feedgps()
{
 while (nss.available())
 {
   if (gps.encode(nss.read()))
     return true;
 }
 return false;
}

void printDouble( double val, unsigned int precision){
/* prints val with number of decimal places determine by precision
  NOTE: precision is 1 followed by the number of zeros for the
  desired number of decimal places
  Example:
  printDouble( 3.1415, 100); // prints 3.14 (two decimal places)
  */

   lcd.print (int(val));  //prints the int part
   lcd.print("."); // print the decimal point
   unsigned int frac;
   if(val >= 0)
       frac = (val - int(val)) * precision;
   else
       frac = (int(val)- val ) * precision;
   lcd.println(frac,DEC) ;
}


I do have a few questions in general about TinyGPS. Could you elaborate on the need for 'feedgps'? Also do the 'flat' and 'flon' values have one less decimal place than their integer counterparts?

mikalhart

duganj,

The idea behind TinyGPS is that you feed it characters that (usually) come in from a serial port.  Like all serial applications, if you don't read the port sufficiently often, you'll lose characters.

You can simplify the sketch below considerably by following this strategy:

Code: [Select]
void loop()
{
 if (Serial.available())
 {
   int c = Serial.read();
   if (gps.encode(c))
   {
     // got a fix: process the new data
     ... // do a lot of Serial printing here
   }
 }
}


That's fine, but if you do, be aware that "doing a lot of Serial printing" takes a long time, and you will probably lose some incoming data.  For many GPS apps, that's ok.  You get checksum errors, but then you are back in sync.

I organized the sketch to break up that "lot of Serial printing" into little chunks between which I fed the GPS with feedgps().  The whole point is just to avoid losing serial data.

I don't think the "f" version of lat/lon have less precision.  Here's a printout from a sketch I just ran with the latest TinyGPS

Code: [Select]
Lat/Long(10^-5 deg): 3024255, -9782635 Fix age: 5ms.
Lat/Long(float): 30.24255, -97.82635 Fix age: 11ms.


What are you seeing?

Mikal

duganj

I think I'm starting to understand. Checksum errors are indicating that I might have missed some data that was being fed out by the GPS not that there is some error in the parsed data. That was more my concern.

As far as the number of digits, here's what my serial monitor text looks like:
Lat/Long(10^-5 deg): 4554463, -12258925Lat/Long(float): 45.5446, -122.5892

I'm not sure why mine shows one less digit for the float vars.

mikalhart

I think that's a pretty likely explanation of the checksum problem.  Meanwhile, I think you have an old version of TinyGPS.  The new one has a better printFloat in the sample sketch:

Code: [Select]
void printFloat(double number, int digits=5)
{
 // Handle negative numbers
 if (number < 0.0)
 {
    Serial.print('-');
    number = -number;
 }

 // Round correctly so that print(1.999, 2) prints as "2.00"
 double rounding = 0.5;
 for (uint8_t i=0; i<digits; ++i)
   rounding /= 10.0;
 
 number += rounding;

 // Extract the integer part of the number and print it
 unsigned long int_part = (unsigned long)number;
 double remainder = number - (double)int_part;
 Serial.print(int_part);

 // Print the decimal point, but only if there are digits beyond
 if (digits > 0)
   Serial.print(".");

 // Extract digits from the remainder one at a time
 while (digits-- > 0)
 {
   remainder *= 10.0;
   int toPrint = int(remainder);
   Serial.print(toPrint);
   remainder -= toPrint;
 }
}


You can always get the latest version at http://www.arduiniana.org.

Mikal

Go Up