LS20031, TinyGPS and NewSoftSerial issues

My LS20031 gps is outputting data with this sketch:

#include <NewSoftSerial.h>
NewSoftSerial nss (2,3);

void setup() {
  Serial.begin(115200);
  nss.begin(57600);
}

void loop() {
  if(nss.available()) {
    Serial.print(nss.read(),BYTE);
  }
}

If I use the example sketch from Tinygps but use HW serial it also works after changing baudrate to that of gps:

//#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);  Use HW Serial Instead
void gpsdump(TinyGPS &gps);
bool feedgps();
void printFloat(double f, int digits = 2);

void setup()
{
  Serial.begin(57600);
  //nss.begin(57600);
  
  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(double number, int digits)
{
  // 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; 
  } 
}

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, 5); Serial.print(", "); printFloat(flon, 5);
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  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.");
  
  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 (Serial.available())  //Changed to Serial from nss
  {
    if (gps.encode(Serial.read()))  //Changed to Serial from nss

      return true;
  }
  return false;
}

But using the example as is, it seems the program is never getting valid data. Output monitor stops after 'Sizeof(gpsobject) = 103'. It seems like TinyGPS and NewSoftSerial aren't working together.
I'm using a Duemilanove if that helps.

Thanks,

Dave

Dave, what's probably happening in this case is that NewSoftSerial is dropping a character every once in a while from the GPS stream. 57.6K baud is right at the cusp of what's possible with software serial reception.

Does your GPS have the capacity to crank down its baud rate a bit?

Mikal

mikal,

Thanks for the quick response.
I believe I can. I'll have to do some logic level shifting before I can transmit to unit.

Dave

I updated the gps to 38400 and only transmitting GGA and MRC @ 2Hz. Still nothing. HW serial continues to work fine. I did notice several checksum errors at 57600 with all sentences. Now that I dropped the baudrate and amount of data, failed checksum consistantly reads 0.
Do I need to slow down even more? I only have so many eeprom updates I can give this gps.

Thanks,

Dave

same problem here. nss does not seem to handle my current setup 38400 and 5Hz.
There a few comments around saying that nss does not work with a gps higher than 1hz...

Can you check nss.overflow to see if the data is arriving faster than you are processing it?

M

I dropped mine to 9600 at 2 Hz. Seems to work fine with no errors.

Dave

yes, i go get some overflow.

I just did
if(nss.available()) {
Serial.print(nss.read(),BYTE);
Serial.print((bool)nss.overflow());
}

not sure if it was the right way??. But i do get some 1 and 0s.
at 38400 and 5hz, with RMC and GGA only on, I get 90% of the GGA and nothing of the RMC.

Will try to decrease the baud rate even more, but I'd like to increase the frequency to 10hz.

If you are getting overflow() when trying to monitor a NewSoftSerial RX stream, one solution is of course to lower the baud rate. But frequently the problem can be solved by re-examining your code to make sure that you are not doing any unnecessary delay()s or Serial.prints(), etc.

But yeah, 5Hz and 38.4K baud is pretty fast.

M

Have you tried the GPS_NMEA or GPS_UBLOX libraries? I have the same GPS unit working perfectly at 115200baud, albeit with a little tweaking of the settings on the GPS unit. From my experience the LS20031 units are not factory set to the specifications set out in the user manual and you will need to send the change baud rate message to the unit to set the rate you require (the default for my unit was 57600) connect at this rate and send the following ASCII to the port you have the unit connected to:
"$PMTK251,38400*27"
^^^
the baud rate goes here

if you have further issues I can send the code I used to get mine working.

I had the same problem.
There is a bug in the example sketch from Tinygps.
You need to change

NewSoftSerial nss (2,3);

to

NewSoftSerial nss (3,2);

Let's not be too hasty here. For people that have chosen to connect the RX from the GPS module to their Arduino pin 2, the code works without modification. In your setup it appears that you are using pin 3 for RX, but it's misleading to conclude that the code is wrong. It's called "sample" code because it's designed to give people an example of how they might design an application. The pin assignments are completely arbitrary.

Mikal

To call it wrong might have been too hasty. I should have suggested , the person have a look at what why he/she has the TX/RX set up. I have been using the sparkfun GPS shield, and to get that to work you need to switch TX and RX.
To NewSoftSerial nss (3,2);

Ah, yes, that's something that should be pointed out. The Sparkfun shield does indeed use pin assignments that require reversing the NewSoftSerial object declaration in the TinyGPS sample code.

Thanks!

M