MKR GPS Shield Sampling Frequency

I have the MKR 1010 and am working on a circuit that needs realtime GPS positioning. I bought the MKR GPS Shield, and am using it on the I2C bus (attached via cable to the 1010 board).

I am attempting VERY basic interaction with the board at the moment, and basically just want to print out the GPS coordinates to the serial.

I am using the GPS.begin() method in setup, and then in my loop:

#include <Arduino_MKRGPS.h>

void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // If you are using the MKR GPS as shield, change the next line to pass
  // the GPS_MODE_SHIELD parameter to the GPS.begin(...)
  if (!GPS.begin()) {
    Serial.println("Failed to initialize GPS!");
    while (1);
  }
}

void loop() {
  // check if there is new GPS data available
  if (GPS.available()) {
    // read GPS values
    float latitude   = GPS.latitude();
    float longitude  = GPS.longitude();
    float altitude   = GPS.altitude();
    float speed      = GPS.speed();
    int   satellites = GPS.satellites();

    // print GPS values
    Serial.print("Location: ");
    Serial.print(latitude, 7);
    Serial.print(", ");
    Serial.println(longitude, 7);

    Serial.print("Altitude: ");
    Serial.print(altitude);
    Serial.println("m");

    Serial.print("Ground speed: ");
    Serial.print(speed);
    Serial.println(" km/h");

    Serial.print("Number of satellites: ");
    Serial.println(satellites);

    Serial.println();
  }

  // adding this delay causes GPS to require 30-60 seconds between each
  // iteration of GPS.available() returning true...
  delay(100);
}
}

What I'm seeing is that the GPS takes on the order of 30-90 secs to initialize, and then only provides new updated coords every 20-30 secs.

Is that really what to expect from this module? I was under the impression that it could provide several samples per second. Documentation seems to be very lacking. Anyone else have insights or experience with this module?

Thanks!

It turns out that my troubles were caused by the arduino delay(...) method. It seems that delay causes the GPS to lose its satelite data.

In summary, if you want realtime tracking of the GPS, you can't have a delay in your loop.

1 Like

Posting a minute fragment of you code makes it very difficult to help.

If your unknown code is just reading the GPS, then whilst delay() can cause problems with reading the data, it should not affect the actual GPS in any way.

I updated my original post with the full sketch. I'm just using the sample that comes with the library, but adding a small delay(100) at the end of the loop function.

Even without the delay, I only seem to be able to squeeze about one update per second from the library, which means that I don't think that I can use this module for my use cases, unless maybe there's a way to increase the frequency of samples delivered from the GPS.

The SAM-M8Q chip that the module is based on indicates that the GPS can deliver updates from 10-18Hz, so I'm thinking something about the library is limiting things, or perhaps it's the data rate of the serial interface.

Any thoughts on how to improve things would be much appreciated!

dk

Nothing to do with the library or the baud rate really.

1Hz updates is the standard setting for most GPSs , fine for the vast majority of uses.

If you want faster updates you need to configre the GPS to send the position sentences more often and turn off the ones you dont want. Details in the manual or the Ublox U-Center application.

Well, I'm no expert, but when looking at the ublox docs, they seemed to indicate that the GPS would indeed be limited by the baud rate.

I did a quick test of changing the baud rate that the library sets on the serial port that it uses to communicate with the GPS from 9600 to 230400 and bingo, refresh rates are MUCH better.

There are lots of use cases for high data rate GPS (robots, drones, etc). Not sure of the power implications of the higher baud rate,but maybe a pull request is in order?

Thanks!

I use #include <TinyGPS++.h>, works great on a ESP32 to read my Ada Fruit Ultimate GPS.

I read the GPS once a milliSecond.

void fGPS_Parse(  void *pvParameters )
{
  for (;;)
  {
    xEventGroupWaitBits (eg, evtGPS_Parse, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( xSemaphoreTake( sema_GPS_Gate, xTicksToWait0 ) == pdTRUE )
    {
      //query GPS: has a new complete chunk of data been received?
      if ( GPSSerial.available() > 1 )
      {
        if ( GPS.encode(GPSSerial.read()) )
        {
          if (  GPS.location.isValid())
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Lat = GPS.location.lat();// store data into structure
              xPosit.Lon = GPS.location.lng();
              xSemaphoreGive( sema_Posit );
            }
          } // if (  GPS.location.isValid())
          if (GPS.speed.isValid())
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.MPH = GPS.speed.mph();
              xPosit.KPH = GPS.speed.kmph();
              xSemaphoreGive( sema_Posit );
            }
          } //  if (GPS.speed.isValid())
          if (GPS.time.isValid())
          {
            if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xTime.iSeconds = GPS.time.second();
              xTime.iMinutes = GPS.time.minute();
              xTime.iHours = GPS.time.hour();
              xSemaphoreGive( sema_Time );
            }
          } // if (GPS.time.isValid())
          if (GPS.date.isValid())
          {
            if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xDate.iMonth = GPS.date. month();
              xDate.iDay = GPS.date.day();
              xDate.iYear = GPS.date.year();
              xSemaphoreGive( sema_Date );
            }
          } // if (GPS.date.isValid())
          if (  GPS.altitude.isValid() )
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Alti = GPS.altitude.meters();
              xSemaphoreGive( sema_Posit );
            }
          } //  if (  GPS.altitude.isValid() )
          if ( GPS.course.isUpdated() )
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Hdg = GPS.course.deg();
              xSemaphoreGive( sema_Posit );
            }
          } // if ( GPS.course.isUpdated() )
          if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
          {
            xQueueOverwrite( xQ_Posit, (void *) &xPosit );
            xSemaphoreGive( sema_Posit );
          }
        } // if ( GPS.encode(GPSSerial.read()))
      } // if ( GPSSerial.available() > 0 )
      xSemaphoreGive( sema_GPS_Gate );
    }
  } // for (;;)
  vTaskDelete( NULL );
} // void fGPS_Parse(  void *pvParameters )

As you can see this line "if ( GPSSerial.available() > 1 )" is used to determine if the GPS has data available and if so process that data. My display is updated once a second.

What do you mean by real time GPS data?

The GPS satellite broadcasts a signal that the GPS receiver process, that signal, from a satellite traveling at +17,000 miles per hour, tells the receiver where the satellite was. Already real time starts to break down. The GPS signal takes a few moments of time to reach the GPS receiver and then the receiver takes time to process the signal, more break down of real time. Now if you have moved from the time the signal is sent to when the signal is processed by the GPS, your data is old. Again breaking down real time. Now, lets say your are using a 8bit UNO to parse the GPS data and do a floating point calculation or two or not, another real time data break down.

So what do you mean by real time?

keyesdav:
Well, I'm no expert, but when looking at the ublox docs, they seemed to indicate that the GPS would indeed be limited by the baud rate.

Ultimatly yes, but you were asking if the the 10-18hz update was possible, and at 10hz and 9600baud it is, just about. You can turn off all the normal NMEA sentences and poll the navigation information direct.

Not sure of the power implications of the higher baud rate,but maybe a pull request is in order?

No power implications that I can think of, but where would you be submitting a pull request ?

All the functionality you need is available, if you want to send commands to the GPS, its not difficult to do so.

Idahowalker:
So what do you mean by real time?

Well, exactly, what does 'real time' really mean ?

For instance in the context of the OPs questions is a 10hz GPS update 'real time' and a 1hz GPS 'not real time' ?

Yeah, sorry for the confusion. I do understand that GPS offers an estimate of location, subject to all kinds of error.

What I want is pretty simple I think (maybe I'm wrong). I want more frequent estimates (as many as possible) per second. The mkr GPS shield hardware and its associated library seem to only deliver one per second max.

If there's any guidance that you can give on how to use the mkr GPS and the associated library to get ten samples per second, that would be much appreciated.

Increasing the baud rate helps, but as pointed out earlier I think that I also need to configure the GPS to sample more frequently, so that the availble() method will return true multiple times per second. I'm not sure how to do that.

My apologies for not being an expert in this stuff. Just trying to muddle my way through!

Change this line  delay(100); to   // delay(100);

keyesdav:
If there's any guidance that you can give on how to use the mkr GPS and the associated library to get ten samples per second, that would be much appreciated.

Increasing the baud rate helps, but as pointed out earlier I think that I also need to configure the GPS to sample more frequently, so that the availble() method will return true multiple times per second. I'm not sure how to do that.

So just to give others who stumble on this thread some kind of starting place, I'm going to answer myself here. After some digging, I did eventually discover how to adjust the data rate of the ublox module. I had to make the following two changes to the Arduino_MKRGPS library:

  1. increase baud rate of the GPS connection. In the very last line of GPS.cpp...
GPSClass GPS(Serial1, 460800, serialDDC, 400000, 7);
  1. In GPS.h, make the sendUbx method a public member of the GPS class. This allows me to send low-level commands to the SAM-M8Q from my sketch.

After this, I can construct low-level messages in my sketch and configure the GPS to my liking. Here's what I did to increase the sample rate to 3Hz in my sketch's setup method:

  Serial.println("Configuring GPS refresh rate...");

  //  UBX-CFG-RATE (0x06 0x08) Navigation/Measurement Rate Settings
  //  See UBX-13003221 section 32.10.23.1
  byte payload[6];

  memset(payload, 0x00, sizeof(payload));
    
  uint16_t measRate = 333;    // ms between gps data publish  (min of 100)
  uint16_t navRate  =   1;    // ratio between measurements and nav solution calculations
  uint16_t timeRef  =   1;    // The time system to which measurements are aligned (0: UTC, 1:GPS, ...)

  // write out the unsigned shorts in little-endian form
  payload[0] = measRate & 0xff;    
  payload[1] = (measRate >> 8) & 0xff;    
  payload[2] = navRate & 0xff;
  payload[3] = (navRate >> 8) & 0xff;
  payload[4] = timeRef & 0xff;
  payload[5] = (timeRef >>8) && 0xff;

  GPS.sendUbx(0x06, 0x08, payload, sizeof(payload));

  Serial.println("  > done");

Hope this helps someone else struggling with higher data rate use cases. There's still room for improvement, I think (as suggested by @srnet above), in particular by reducing the number of sentences returned by the GPS. I haven't been able to get the sample rate higher than 5Hz, while technically the GPS is supposed to be capable of doing 10Hz. I'm not sure where the bottleneck is, but 3Hz is good enough for my use case, so I'll not be digging deeper right now.