Go Down

Topic: GPS: set update frequency (Read 21194 times) previous topic - next topic

petterg

Hi guys

I'm quite new to arduino (started with the blink example yesterday) so please have patience if this seems totally noob.

I've got a Skylab skm53 GPS hooked up to a Pro micro. Running the example code for TinyGPS (changed to hardware serial) I've got the GPS working. But it's only updating the long-/latitude every 3-5 minutes. I won't brag about it, but I'm able to move quite some distance between those updates!
The code is printing out data every second and I see the timestamp is updating every second, but my speed, direction and position remains the same for 3-5 minutes. When those data change they might do 3-5 updates within 3-5 seconds, then they reminds the same for another 3-5 minutes.

If I manage to read the datasheet right the gps should be able to do 10 updates per second. So how can I make this thing update position more frequently?

To test I went out on a field, far from any possible disturbance, to no avail. The gps never reported it had contact with less than 9 satellites.

Code:
https://github.com/awaxa/arduino/blob/master/libraries/TinyGPS/Examples/test_with_gps_device/test_with_gps_device.pde

Datasheet
http://www.webtronico.com/documentos/SKM53_DS_030609.pdf

int2str

Did you let the GPS run for a while?
Do you have clear line of sight to the sky?

Sounds like maybe just bad reception?

petterg

It ran for about 6 hours.
The only place I can think of with a better sight than out in the field would be the top of a mountain.

During those 6 hours it was indoors half the time - my laptop needed to charge. The circuit is powered from the laptops usb. Indoors it had connection to 9 satellites. Outdoors it had between 9 and 12.

PaulS

Quote
Running the example code for TinyGPS (changed to hardware serial)

So, you posted a link to some other code. Would you like a link to some other answer?
The art of getting good answers lies in asking good questions.

petterg

I though it would be good practice for the forum to use a link rather than posting the code. A link to the solution would be fine though.
Here's the modified code: (replaced "nss" with "Serial1", commented out softwareserial)

Code: [Select]

//#include <SoftwareSerial.h>

#include <TinyGPS.h>

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

TinyGPS gps;
//SoftwareSerial nss(3, 4);

static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
 
  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();
  Serial.println("Sats HDOP Latitude Longitude Fix  Date       Time       Date Alt     Course Speed Card  Distance Course Card  Chars Sentences Checksum");
  Serial.println("          (deg)    (deg)     Age                        Age  (m)     --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
}

void loop()
{
  bool newdata = false;
  unsigned long start = millis();
 
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps())
      newdata = true;
  }
 
  gpsdump(gps);
}

static void gpsdump(TinyGPS &gps)
{
  float flat, flon;
  unsigned long age, date, time, chars = 0;
  unsigned short sentences = 0, failed = 0;
  static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
 
  print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
  print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
  gps.f_get_position(&flat, &flon, &age);
  print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
  print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);

  print_date(gps);

  print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
  print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
  print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
  print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
  print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);

  gps.stats(&chars, &sentences, &failed);
  print_int(chars, 0xFFFFFFFF, 6);
  print_int(sentences, 0xFFFFFFFF, 10);
  print_int(failed, 0xFFFFFFFF, 9);
  Serial.println();
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
  char sz[32];
  if (val == invalid)
    strcpy(sz, "*******");
  else
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0)
    sz[len-1] = ' ';
  Serial.print(sz);
  feedgps();
}

static void print_float(float val, float invalid, int len, int prec)
{
  char sz[32];
  if (val == invalid)
  {
    strcpy(sz, "*******");
    sz[len] = 0;
        if (len > 0)
          sz[len-1] = ' ';
    for (int i=7; i<len; ++i)
        sz[i] = ' ';
    Serial.print(sz);
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1);
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(" ");
  }
  feedgps();
}

static void print_date(TinyGPS &gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned long age;
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  if (age == TinyGPS::GPS_INVALID_AGE)
    Serial.print("*******    *******    ");
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d   ",
        month, day, year, hour, minute, second);
    Serial.print(sz);
  }
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
  feedgps();
}

static void print_str(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  feedgps();
}

static bool feedgps()
{
  while (Serial1.available())
  {
    if (gps.encode(Serial1.read()))
      return true;
  }
  return false;
}

MarkT

#5
Oct 03, 2013, 01:29 pm Last Edit: Oct 03, 2013, 01:33 pm by MarkT Reason: 1

I though it would be good practice for the forum to use a link rather than posting the code.


Good practice is explained in detail in the sticky threads...  Its there to facilitate rapid
and accurate solutions to peoples problems and reduce the to-ing and fro-ing of questions
and answers and wasted effort in answering a different problem from the actual problem :)
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

PaulS

Code: [Select]
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps())
      newdata = true;
  }

That code does not do what the comment says.

Try this:
Code: [Select]
if(feedgps())
   gosdump(gps);

Nothing else in loop().
The art of getting good answers lies in asking good questions.

petterg

That helped quite a bit!
Now it's printing position about 3 times pr second, continuously updating for a while (30-60 secondes) - then it stop updating for a couple of minutes. Then it starts updating again for a another 30-60 seconds. ...And so on.

Could it be that the serial read comes out of sync with the data stream? Does the serial buffer need to be read continuously?
Could the solution be to flush buffer and wait for the start of a new sentence in order to start a new read? If so, how would the pro micro recognize the start of a new sentence?

(I don't fully understand every part of the sample code yet.)

MarkT

Have you thought of buffering an entire NMEA sentence before passing to the library?  Then
it won't matter if the libraries slow in parsing it.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

PaulS

Quote
Could the solution be to flush buffer

No.

What is the purpose of sending data TO the GPS? What do you expect it to do with it?
The art of getting good answers lies in asking good questions.

petterg


Have you thought of buffering an entire NMEA sentence before passing to the library?  Then
it won't matter if the libraries slow in parsing it.


That could be an idea. How would I start/stop the buffering?
How does the buffer work? Will it automatically throw away old data when full, or does it drop new data when full? Does it receive data in the background independently of what code the mpu is currently executing?

petterg


Quote
Could the solution be to flush buffer

No.

What is the purpose of sending data TO the GPS? What do you expect it to do with it?


The purpose would be to say "Hey, I'd like some data now. Send me a sentence."
Then I would know that what is in the buffer is one full sentence ready for parsing/decoding.

PaulS

Quote
Then I would know that what is in the buffer is one full sentence ready for parsing/decoding.

You know that the GPS has sent a complete sentence because feedgps() returned true.
The art of getting good answers lies in asking good questions.

petterg


Quote
Then I would know that what is in the buffer is one full sentence ready for parsing/decoding.

You know that the GPS has sent a complete sentence because feedgps() returned true.


Ah! That is useful knowledge!

I found this comment about the tinygps library:
Quote

NEMA format GPS data is usually transmitted at 4800 baud, in 8N1 format. The resulting maximum incoming speed is 480 bytes per second. By default, Teensyduino's UART Serial buffers up to 64 bytes, or 0.133 seconds of incoming data.

If your program must perform some operation for more than 0.13 seconds, it should check for new data and give it to TinyGPS with gps.encode() within that time period.


This gps run at 9600 baud. That would make the buffer fill every 0.0665 second.
As the position is printed to pc about 3 times pr second after PaulS' suggested modification to loop {}, the gps.encode() seems to need 0.3 seconds to run. That is 4.5 times longer than the buffer fill. I guess that  would be the cause of trouble.

So, if flushing buffer is not the way to handle this, then what is?

Quote
Could the solution be to flush buffer

No.

PaulS

Quote
As the position is printed to pc about 3 times pr second after PaulS' suggested modification to loop {}, the gps.encode() seems to need 0.3 seconds to run. That is 4.5 times longer than the buffer fill. I guess that  would be the cause of trouble.

How are you measuring that? The gps.encode() function get called only when a complete sentence has arrived. Since that happens roughly once a second, it should not cause the buffer to overflow, since the GPS will be quiet for a while after the end of the sentence has arrived, before it starts sending the next one.

Doubling the baud rate halves the time it takes to receive the data, not doubles it.
The art of getting good answers lies in asking good questions.

Go Up