Just reading this thread for the first time. I had similar problems described above and made a few adjustments in the loop to compensate. And I also changed to the tinygps library as it looked a lot cleaner.
The problem I observed was the serial buffer would fill and then not accept any more characters until it was emptied. Depending on timing it would contain only part of a sentence, or an incomplete sentence. These would be rejected of course and by chance I would also begin reading a new sentence as the buffer was being emptied and continue to read as the sentence completed. If I output what I was reading to the console character by character it would often look like garbage.
To make a long story short what I did to make the loop reliable was to throw away all the old data in the buffer at the start of every cycle, then continue waiting and reading to synchronize on the start of a new sentence. This could take up to a second or so. Then keep reading and process the data normally. No more errors ever after adopting this process.
void loop()
{
bool isValidGPS = false, validStart = false;
unsigned long d = 0, x = 0;
int sentences = 0;
int avail = Serial1.available();
if (avail >= 63) {
for (int x = 0; x < avail; x++) {
Serial1.read();
}
}
if (Serial1.available() > 0 && Serial1.peek() != '$') {
while (Serial1.peek() != '$' && Serial1.peek() != -1)
Serial1.read(); // empty the buffer up to a new $ or end of buffer
}
for (unsigned long start = millis(); millis() - start < 1000 || (validStart && sentences <= 5);)
{
while (Serial1.available())
{
char c = Serial1.read();
if (!validStart && c == '$') {
validStart = true; // mark the beginning of the sentence
d = millis() - start;
}
// incrementally handle and parse gps data. returns true after a valid sentence received
if (validStart) {
if (gps.encode(c)) {
isValidGPS = true;
validStart = false;
sentences++;
}
}
}
x = millis() - start;
}
if (isValidGPS){
float lat, lon;
unsigned long age;
gps.f_get_position(&lat, &lon, &age);
sprintf(szInfo, "%.4f,%.4f alt: %.1f course: %.1f sats: %d",
(lat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lat), (lon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : lon),
gps.f_altitude(), gps.f_course(), gps.satellites());
}
else{
// Not a vlid GPS location, jsut pass 0.0,0.0
// This is not correct because 0.0,0.0 is a valid GPS location, we have to pass a invalid GPS location
// and check it at the client side
sprintf(szInfo, "0.0,0.0");
}
Particle.publish("gpsloc", szInfo);
unsigned long chars;
unsigned short good_sentences, failed_cs;
gps.stats(&chars, &good_sentences, &failed_cs);
sprintf(szInfo, "D: %ld, C: %ld, S: %d, B: %d, X: %ld", d, chars, good_sentences, failed_cs, x);
delay(20);
Particle.publish("stats", szInfo);
Serial.write(String::format("\r\nend cserr:%u dur:%ul\r\n", failed_cs, x));
delay(sleep);
}