Why is my gps serial link so slow?

So after messing around with various libraries, I’ve discovered that my Ublox-NEO6m can be polled directly to ask it for data. Wow that sounds simple I thought.

Well I’ve managed to get it to to stop automatically outputting it’s NMEA strings, and I can sent it “$PUBX,00*33” and it does indeed reply, but it takes upto 2 seconds to do so!

  String a;

void setup() {
  // initialize both serial ports:
  Serial.begin(9600);
  Serial1.begin(9600);
    delay(500);
  Serial1.println(F("$PUBX,40,RMC,0,0,0,0*47")); //RMC OFF
    delay(100);
    Serial1.println(F("$PUBX,40,VTG,0,0,0,0*5E")); //VTG OFF
    delay(100);
    Serial1.println(F("$PUBX,40,GGA,0,0,0,0*5A")); //CGA OFF
    delay(100);
    Serial1.println(F("$PUBX,40,GSA,0,0,0,0*4E")); //GSA OFF
    delay(100);
    Serial1.println(F("$PUBX,40,GSV,0,0,0,0*59")); //GSV OFF
    delay(100);
    Serial1.println(F("$PUBX,40,GLL,0,0,0,0*5C")); //GLL OFF
    delay(1000);
}

void loop() {
 
  Serial1.println("$PUBX,00*33");
  Serial.println("sent req");
  Serial.println(millis());
  a = Serial1.readString();
  Serial.println(millis());
  Serial.print(a);

}

I’ve attached a screenshot of my serial monitor to show the time difference between the two printings of millis().

If anyone can help me make my gps return the data quickly, it would be a great help.

Cheers

Instead of attaching an image we have to download, just select the text in the Serial Monitor window, copy it, and paste it into your post. Be sure to put
** **[code] <your code here> [/code]** **
tags around it,

so it looks
   like this

You can even Modify your post, if you want.

And yes, you can ask the GPS device for a sentence, but it is running on its own clock. Normally, it’s running on a 1-second update interval. Because the Arduino takes time to send the command (~13ms) and the GPS device takes time to parse the command and send the response (~110ms), you have to wait for an update interval in the GPS. The response won’t get sent until the next interval begins, up to a whole second (or two?) after it receives the command. The GPS device has an internal queue of things to send. BTW, printing the response adds another ~46ms.

Are you sure you want to poll? If you let it constantly emit the sentences you really need (turn the others off), the current fix information will be ready for you when you want to use it. You can use this table to identify which sentences you really need.

If you need to keep your time synchronized with the GPS clock, polling can also make things awkward. Coordinating with the GPS character bursts may also be required if you are doing other “blocking” things, like writing to an SD card.

So after messing around with various libraries,

Have you tried NeoGPS? It’s smaller and faster than all other libraries, and can be configured to parse only the sentences and fields that you really use. The first example program, NMEA.ino, shows how to have a current fix_data structure that always contains the latest info. If nothing else, take a look at the Troubleshooting section – it describes many common timing problems.

Cheers,
/dev

Thanks /dev,

The reason I chose polling in the end was because my project is now using a wireless radio, gps, a keypad and bluetooth. Meaning that I've got so many different things going on, I wanted to just have a gpsloop that I can enter when I want to get the latest gps information. Instead of having to constantly have the program enter the gps loop. But it seems like the max polling rate is 1hz :confused: even with a 5hz nmea stream. :frowning:

I've got my gps on a hardware port, so my new theory is to keep the nmea stream at 5hz and then I can enter the gps loop and have a gps program process the received information until it get's a fix.

I wonder if I can reduce the sentence output of my gps down to just one sentence, and then the second I enter the loop, it extracts the data from the hardware serial buffer, as the data is already there waiting for it to be read? I've got a ublox neo6m which apparently supports a proprietary ublox sentence that has every bit of useful data in one sentence.

I will attempt such a hack later on today, but if you can provide any guidance, it would saveme hours of learning. I'm still confused by the

 while (Serial1.available() > 0)
if (gps.encode(Serial1.read()))

command that seems present in most gps libraries. It's design confused me as it's got an if within a while. :confused:

I wanted to just have a gpsloop that I can enter when I want to get the latest gps information.

Right, NeoGPS has an example called NMEA_isr.ino. It parses GPS characters during the received character interrupt, which totally avoids having to get back to loop in time to read something. It will queue up completed fixes for you to read sometime later. A fix contains the merged information from all the sentences sent during each update interval (1 second by default). That is, only one fix is structure needs to be read each second. I'm sure your sketch could handle that. The Troubleshooting page also describes the interrupt-driven approach.

Even if you tell the GPS to run at 5Hz, NeoGPS will still only produce one fix every 0.2 seconds. No Big Deal. I would recommend this approach. Normally, NeoGPS will hold on to one fix while it is assembling the next one, but it's easy to increase that limit if you are busy doing something for more than 200ms. Each fix adds ~30 bytes, depending on your configuration (i.e., what pieces you really use).

I wonder if I can reduce the sentence output of my gps down to just one sentence, and then the second I enter the loop, it extracts the data from the hardware serial buffer, as the data is already there waiting for it to be read?

The characters stack up until you read them, to a limit of 64 characters. If your favorite sentence is longer than 64 characters, you'll never get a complete sentence unless you block inside a while loop, waiting for it. Not recommended when you have so many other things going on.

I'm still confused by the

while (Serial1.available() > 0)
** if (gps.encode(Serial1.read()))**

command that seems present in most gps libraries. It's design confused me as it's got an if within a while. :confused:

Yes, I eventually got away from that. The while loop forces all available characters to be read, one at a time, and passed to the GPS parser. 99 times out of 100, the parser returns false, because there could be 100 characters in a sentence. When the 100th character finally arrives (i.e., is available), it is read and passed to the GPS parser, which finally returns true. And when all the GPS characters have been read, the while loop terminates and the rest of your sketch gets to run.

When loop gets called again, the while loop will look for characters to read again. 999 times out of 1000, there may be nothing to read. The while loop is just skipped.

Maybe this is easier to understand:

void GPSloop()
{
  while (gps.available( gps_port )) {
    fix_data = gps.read();
    doSomeWork(); // with fix_data
  }

} // GPSloop

This is the basic loop structure in the NeoGPS examples. The loop handles entire fixes, not individual characters.

In general, you want to get back to loop as fast as possible. Don't use delay, and don't use while loops to force waiting for something to finish. Instead, use a "state" variable to remember where you're at and go back to loop to check everything else. Each time you check something, the state variable can be updated by any available data, until something is "completed". Then you can handle the completed "thing", and go back to loop again.

Serial Input Basics is a good place to start. There are several other good links here.

Cheers,
/dev

Yeah the real problem is that my project will be so varied in it's application that I really just want to be able to enter a loop, get the gps data, save it to global variables and then leave. This is because I don't know how long it will be until I can return to the loop. My two other radios can take a long time to transmit and/or recieve, plus I'm using a keypad and an MPU accelerometer.

I now thinking that a real simple approach will solve this best for me. So I'm thinking of increasing my hardware serial buffer size (it's a 1284p so I've got loads of space). And then having a GPS parser simply fire up when I enter the gpsloop and extract the info from it. Nice and simple, and the data retrieval should be almost instant as there will always be a complete sentence in the buffer.

Although now I look at it on google, the serial buffer does not overwrite the oldest data, it just drops it. Is that correct?

I thought this would be easy :frowning:

dave_sausages:
I now thinking that a real simple approach will solve this best for me. So I’m thinking of increasing my hardware serial buffer size (it’s a 1284p so I’ve got loads of space). And then having a GPS parser simply fire up when I enter the gpsloop and extract the info from it. Nice and simple, and the data retrieval should be almost instant as there will always be a complete sentence in the buffer.

I don’t think this is a good way to go about it. If your code is so slow that it takes more than a half a second to execute the loop() once, you REALLY need to go back and optimize your code. It doesn’t matter if you have a complicated project, you still need to worry about optimization and speed. Increasing the buffer is just a band-aid solution and you should never need to do it.

dave_sausages:
Although now I look at it on google, the serial buffer does not overwrite the oldest data, it just drops it. Is that correct?

Sort of. It drops the oldest byte by overwriting it - provided that the buffer is completely full.

dave_sausages:
I thought this would be easy :frowning:

Embedded projects never are, my friend :slight_smile: . That is, if you want to do anything more useful than blinking an LED, lol. I had a class at VT a couple of semesters ago called Microcontroller Interfacing. We used the PIC32 instead of an Arduino and had 4 major projects. Each of the projects took anywhere from 24 - 30 hours of solid work within a 6 day period to complete. Doing microcontroller projects are very difficult, especially when you are learning.

I really just want to be able to enter a loop, get the gps data save it to global variables and then leave.

I guess I didn’t phrase this correctly: “parsing GPS characters during the received character interrupt totally avoids having to get back to loop in time to read something.”

Or this: “In general, you want to get back to loop as fast as possible. Don’t use delay, and don’t use while loops to force waiting for something to finish.”

It’s like this guy:

balancing plates.jpg

He has to visit each plate quickly. If he “blocks” too long at one plate, something breaks. You’ll need to do the same thing. Don’t hang around in the radio TX code, waiting for it to complete… write the data, set a flag and return. Then call the same routine again and look at the flag. If it’s set, see if the last transmission is completed. If not, just return.

Each one of your devices needs to be serviced like that. Check something, read/write a little, set some variables and return. Go on to the next thing.

So don’t think about “entering a loop” and staying there until you get what you want. Just check to see if it’s there… if it’s not there yet, return. If it’s there, hooray! You can finally do something with it.

Sometimes it is possible to do what you are thinking of doing. Unfortunately, changing something in one place usually has an effect on some other unrelated place. The timing changes, and a dish falls.

This is kind of inside-out from the linear, top-to-bottom program. On the Arduino, you need to let loop run as frequently as you can: DON’T WAIT FOR ANYTHING. Go check all the other things and come back to see if it’s done.

For the GPS data, this means feeding one character at a time to the parser… and then do something else. When the parser says a fix is finally ready, then you can handle it. That could be as simple as copying the fix to a global variable for the rest of your sketch to use whenever.

The radio RX code should be the same. In fact, servicing the GPS and the radio like this are specific examples of the recvWithEndMarker function in example 2, inside Serial Input Basics. Take a look; it’ll be good for ya’. :wink:

Cheers,
/dev

Power_Broker:
Sort of. It drops the oldest byte by overwriting it - provided that the buffer is completely full.

Nah, it just drops the byte. Look at _rx_complete_irq in HardwareSerial_private.h (IDE 1.6.8).

/dev:
Nah, it just drops the byte. Look at _rx_complete_irq in HardwareSerial_private.h (IDE 1.6.8).

I see, interesting. Must have been confused with the PIC32. At least, I think that's how the PIC does it.

/dev:
Right, NeoGPS has an example called NMEA_isr.ino. It parses GPS characters during the received character interrupt, which totally avoids having to get back to loop in time to read something. It will queue up completed fixes for you to read sometime later.

So if I use the ISR method of Neogps, it just parses the gps data stream in the background and I don't even need to call it?

Anyway, I'm beginning to think this is above me. I just can't find clear enough instructions for me on how to do these things, which probably means I'm just not ready for it.

So if I use the ISR method of Neogps, it just parses the gps data stream in the background and I don't even need to call it?

Yes, you don't need to call it to handle characters. The ISR does that in the background and pushes a fix structure into the queue @ 1 per second. The serial input buffer will never overflow, because the characters are parsed immediately.

However, you still need to call NeoGPS to get a fix structure. If you don't, the fixes will stack up in the queue. Once it contains FIX_MAX (whatever you choose) entries, the new fixes will be dropped. Just like the 65th character into the Serial input buffer.

Let's say you define FIX_MAX to 10. For the "Nominal" configuration, that will use 310 bytes of RAM. And it will take 10 seconds for the ISR to push 10 fixes into the queue (or 2 seconds @ 5Hz). Then NeoGPS will drop the newest fixes until you get make room in the queue by reading some out.

Here's the short version of a fix structure:

struct gps_fix
  {
    int32_t latitude, longitude;
    int32_t speed;
    int32_t altitude;
  };

You'll declare a variable of this type, and call gps.read() to get a fix and copy it into your variable:

gps_fix myFix;

void GPSloop()
{
  while (gps.available()) {
    myFix = gps.read(); // pulls one out of the queue and copies it.
  }
}

Since myFix is a global variable, the rest of your sketch can use it:

void foo()
{
  if (distanceFrom( homeLat, homeLon, myFix.latitude, myFix.longitude ) > 5) { // km?
    Serial.print( "Ankle Bracelet is angry!" );
  }

It's a little more complicated than that, but that's the general idea.

Anyway, I'm beginning to think this is above me. I just can't find clear enough instructions for me on how to do these things, which probably means I'm just not ready for it.

Hey, we all start somewhere. I think you're stuck in the linear programming mode... understanding the "check for a char and return to loop()" concept in Serial Input Basics is crucial.

When that light goes on, you'll be ready for a sketch that looks like this:

void loop()
{
  GPSloop();
  RadioLoop();
  KeypadLoop();
  BlueToothLoop();
}

Generically, each of those routines will look something like this:

void xxxLoop()
{
  while (key or char available) {  //  or if (old status != new status)
     do something with key or character or status
  }
}

If there is no key/char available or status change, the while/if is just skipped and it returns. Quickly. loop() just goes round and round, calling each of these functions to check on something.

Cheers,
/dev

Thank /dev, in the past you have helped me, and you continue to do so.

Okay so I thinking I’m understanding this serial business a little more now.

And I have created this:

#include <TinyGPS++.h>
/*
   This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
// The TinyGPS++ object
TinyGPSPlus gps;
long gpscurrmillis;
long gpsprevmillis;
int gpsinterval = 1000;


void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);

  Serial.println(F("DeviceExample.ino"));
  Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
}


void loop()
{
   recvgps();
   displayInfo();
}

void recvgps()
{
 // This sketch displays information every time a new sentence is correctly encoded.
  while (Serial1.available() > 0)     //this line looks to see if there is serial1 data in the Serial buffer. And if there is anything more than 1 byte it executes the next line.
    (gps.encode(Serial1.read()));      //this line runs the gps.encode function and the data that is got from the serial1 buffer.
      

  if (millis() > 5000 && gps.charsProcessed() < 10) //if after 5 seconds since bootup no more than 5 character have been recieved, then declare a wiring fault.
  {
    Serial.println(F("No GPS detected: check wiring."));
    while(true);
  }
}



void displayInfo()
{
  gpscurrmillis = millis();
  if(gpscurrmillis - gpsprevmillis > gpsinterval)
  {
   gpsprevmillis = gpscurrmillis;    
   Serial.print(F("Location: ")); 
  if (gps.location.isValid())
  {
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Date/Time: "));
  if (gps.date.isValid())
  {
    Serial.print(gps.date.month());
    Serial.print(F("/"));
    Serial.print(gps.date.day());
    Serial.print(F("/"));
    Serial.print(gps.date.year());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F(" "));
  if (gps.time.isValid())
  {
    if (gps.time.hour() < 10) Serial.print(F("0"));
    Serial.print(gps.time.hour());
    Serial.print(F(":"));
    if (gps.time.minute() < 10) Serial.print(F("0"));
    Serial.print(gps.time.minute());
    Serial.print(F(":"));
    if (gps.time.second() < 10) Serial.print(F("0"));
    Serial.print(gps.time.second());
    Serial.print(F("."));
    if (gps.time.centisecond() < 10) Serial.print(F("0"));
    Serial.print(gps.time.centisecond());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.println();

    
  }
  
  
  
}

It works how I expect it to, and as I understand it, the “recvgps” loop looks each time to see if new data is in the serial buffer, and if it is, then the gps.encode function does something useful with it and files away in the current gps fix data table.

Going on what you said about flags, I have created a very crude one that if at the start of “displayinfo” loop, it sees that more than 1 second passed, then it runs a section of code that displays the gps info.

If less than 1 second has passed, then it skips it, and continues to loop through the various loops at break-neck speeds. meaning I never miss any serial data.

Have it got that right? From this structure I assume that as long as no flag executed loop such as “displayinfo” takes too long, I could run many of these loops for many different devices and never miss any data.

And sorry to double post, but you seem to be able to grasp these things very easily and allow me to learn, so I have one more question:

I am also using an mpu6050 in my project (6 dof accel and gyro), and I was hoping to use my new found serial knowledge to slot it into my project in a non blocking manner (at the moment I simply erase the 1024 byte fifo bufffer, and wait for a packet of data to arrive).

However the correct way to do this seems to involve interrupt triggered reading of the fifo buffer, and no matter how much I search I can't find an explanation anywhere on the exact way this works. As I understand it, when the MPU's int triggers, the arduino stops whatever it is doing and processes the MPU data.

However if I were halfway through printing serial data, and the int triggers, wouldn't that stop my serial printing halfway through.

Here is the example code in case you're able to help

Damn! Can't post it as it makes the post over 9000 characters. But here's the code in github that can be easily viewed i2cdevlib/MPU6050_DMP6.ino at master · jrowberg/i2cdevlib · GitHub

And thank you so much!

dave_sausages:
And sorry to double post, but you seem to be able to grasp these things very easily and allow me to learn, so I have one more question:

I am also using an mpu6050 in my project (6 dof accel and gyro), and I was hoping to use my new found serial knowledge to slot it into my project in a non blocking manner (at the moment I simply erase the 1024 byte fifo bufffer, and wait for a packet of data to arrive).

However the correct way to do this seems to involve interrupt triggered reading of the fifo buffer, and no matter how much I search I can’t find an explanation anywhere on the exact way this works. As I understand it, when the MPU’s int triggers, the arduino stops whatever it is doing and processes the MPU data.

However if I were halfway through printing serial data, and the int triggers, wouldn’t that stop my serial printing halfway through.

Here is the example code in case you’re able to help

Damn! Can’t post it as it makes the post over 9000 characters. But here’s the code in github that can be easily viewed i2cdevlib/MPU6050_DMP6.ino at master · jrowberg/i2cdevlib · GitHub

And thank you so much!

I don’t think you need to worry about interrupts messing up serial communication. The reason is because when you send a byte via serial, you dump the whole byte into the outgoing serial UART buffer. The UART module then sends the byte one bit at a time through the serial port autonomously. This, though, is only how the hardware serial port works. If your using softserial, then the library uses “bit banging” in software instead of using a UART.

Even in that case, your ISR should be fast enough that it doesn’t affect the serial transmission (not sure, though, would be a good idea to test it).

The real question is “why use the FIFO”? Why not just poll the data registers when you need to? You wouldn’t need to worry about interrupts and you still get the data when you need it.

dave_sausages:
Have I got that [TinyGPS++ program] right?

No, and I'm really not interested in fixing TinyGPS++ again. That's why I wrote NeoGPS. The NMEA.ino example program is structured correctly. If you only want Date, Time and Location, comment out all the other defines in GPSfix_cfg.h:

#ifndef GPS_FIX_CFG
#define GPS_FIX_CFG

/**
 * Enable/disable the storage for the members of a fix.
 *
 * Disabling a member prevents it from being parsed from a received message.
 * The disabled member cannot be accessed or stored, and its validity flag 
 * would not be available.  It will not be declared, and code that uses that
 * member will not compile.
 *
 * DATE and TIME are somewhat coupled in that they share a single `time_t`,
 * but they have separate validity flags.
 *
 * See also note regarding the DOP members, below.
 *
 */

#define GPS_FIX_DATE
#define GPS_FIX_TIME
#define GPS_FIX_LOCATION
//#define GPS_FIX_LOCATION_DMS
//#define GPS_FIX_ALTITUDE
//#define GPS_FIX_SPEED
//#define GPS_FIX_HEADING
//#define GPS_FIX_SATELLITES
//#define GPS_FIX_HDOP
//#define GPS_FIX_VDOP
//#define GPS_FIX_PDOP
//#define GPS_FIX_LAT_ERR
//#define GPS_FIX_LON_ERR
//#define GPS_FIX_ALT_ERR
//#define GPS_FIX_GEOID_HEIGHT

#endif

That sketch will "displayInfo" (date, time and location) exactly once per second with trace_all (see doSomeWork and GPSloop here). NMEAloc.ino is another example that prints the location without using the Streamers code, trace_all.

the correct way [to read the MPU6050 FIFO] seems be interrupt-triggered reading

You don't have to handle the MPU6050 INT with an interrupt. You could use it like Serial.available:

void MPU6050loop()
{
  if (digitalRead( MPU6050_INT_PIN )) {
    // read some FIFO samples?
      ...
  }
}

void loop()
{
  MPU6050loop();
  GPSloop();
    ...other loops...
}

...but I'm not sure what you're trying to do with the samples. BTW, that example is blocking! The interrupt routine just sets a flag, and the flag is tested in loop:

    while (!mpuInterrupt...

:stuck_out_tongue: Bad juju.

Power_broker:
The real question is "why use the FIFO"? Why not just poll the data registers when you need to? You wouldn't need to worry about interrupts and you still get the data when you need it.

Because it would more than double the I2C transactions, and using the FIFO guarantees a particular frequency of sampling. Polling the data registers would occur at different intervals, and would be dependent on the non-deterministic Arduino interrupts from Serial, Timer0, etc. Using the FIFO is good, just like using the Serial input buffer is good. There are very few times when polling the UART is good, for the same reason.

Cheers,
/dev

/dev:
No, and I'm really not interested in fixing TinyGPS++ again.

Are you saying that I've not understood it right, or the tinygps++ just isn't right. I understand that your neogps is technically superior, but there are several function integrated into tinygps++ that I like, like the 'distance to' function, that eliminates the need for yet another library to be included and called. As my project progresses I will be using more features of tinygps++. Which is why I'm now keen to write my code in a non blocking manner, so as not to have any of those spinning plates fall on the floor.

My use of tinygps++ seems to be correct as far as I can see, but it's possible I have inadvertently done something wrong as I'm still learning.

As for the MPU usage:

My application is for a portable security alarm module that I can place on something, and if it is moved, it triggers an another module to alarm over a radio link. both modules have gps so module 1 can tell where module 2 is (hence the 'distance to' calculation).

As I understand it, when you highlighted
while (!mpuInterrupt...
That means that the piece of code does "Check if mpuInterrupt is true, if not, then just wait here in the bracketed loop until it is"?

and your example of code

void MPU6050loop()
{
  if (digitalRead( MPU6050_INT_PIN )) {
    // read some FIFO samples?
      ...
  }
}

void loop()
{
  MPU6050loop();
  GPSloop();
    ...other loops...
}

works in a way that:

 if (digitalRead( MPU6050_INT_PIN )) {
    // read some FIFO samples?
      ...
  }

looks at the state of the interrupt pin using a digital read, and if it is high, then it runs the bracketed code (read the fifo registers and save their data somewhere useful for example). And if the interupt pin is not high, then just move on as there's no new data to be read from the fifo. Is that correct? Sorry if it very simplisitic, but I want to make sure the foundation of my knowledge is sound before progressing.

And I'm guessing that using this approach, I REALLY don't want any non clocking code, as if I miss the interrupt signal, I miss the data.

the 'distance to' function.

That is available in NeoGPS here. It's a recent addition, so I haven't added it to the docs yet. And the 'course to' function is in my queue, maybe in a couple of days. Is there something else? After a quick scan, that's the only other thing I can see.

The Location class also provides "equirectangular distance to", which is quite a bit faster than the Haversine algorithm. This faster approximation is within a cm of the Haversine value when the dLat/dLon is less than 0.1 degrees (about 4-10km for most users). That's certainly your case, if you are using radio modules.

My use of tinygps++ seems to be correct...

Indeed, that's what everyone thinks. It's what I thought. Then, as I extended the examples to do more work, with more demanding performance, I had to stop and restructure everything. Grrr...

After looking at the RAM usage as well, NeoGPS was born. I also made it so the GPS data could be handled during the RX interrupt. In a delightful change, the GPSloop was checking for complete fixes, not just one character of one sentence. The timing of getting to the GPS serial port was no longer an issue: Once per second is an eternity in Arduino code time. Writing to SD cards reliably was also much easier, because the SD writes were blocking, causing character loss. No so with an interrupt-driven program structure. Not that you have to do that, too, unless the MPU handling starts to cause GPS character loss.

that the piece of code does "Check if mpuInterrupt is true, if not, then just wait here in the bracketed loop until it is"?

Yes, that's blocking.

And I'm guessing that using this approach, I REALLY don't want any non blocking code, as if I miss the interrupt signal, I miss the data.

Well, I'm not exactly sure of how the MPU6050 works, but I would think the INT stays high until it's serviced. I don't think it's a pulse, it's probably a level. Maybe someone else knows, or you could check the data sheet.

Cheers,
/dev

First off /dev I just wanted to say thank you.

Through your guidance I set about understanding non-blocking code and I managed to successfully re-write the MPU6050 example to avoid using interupts and instead use the digital reading of pin 3 to read the fifo buffer.

I'm really pleased with myself that I managed it and that I'm now starting to understand how to code properly instead of just copy and pasting things. I'm sure my code is horrific to someone as good as yourself, but I'm proud of it :slight_smile:

Can't post it of course due to the forums silly 9000 charcter limit*

And I didn't realise that you'd included the distance to calculation in neogps. In that case I will switch my code when the documentation appears (I'm still way off being able to do it without haha).

Is there something else?

I do like the ease and cleanliness in which I can implement tinygps++ just with a simple "include" whereas yours requires manual copying of files into the same folder as the sketch. But I believe there's reasons for it, so I'll live with it :slight_smile:

Can’t post it of course due to the forums silly 9000 charcter limit

You can attach files. In your post above, select “More…” in the lower right, then select “Modify”. This lets you change an old post. Then select “Attachments and other options”, select your files, and select “Open”. When you select “Save”, the files will appear at the bottom of your (modified) post.

I do like the ease and cleanliness in which I can implement tinygps++ just with a simple “include” whereas yours requires manual copying of files into the same folder as the sketch. But I believe there’s reasons for it, so I’ll live with it

The reasons are the stupid IDE. Without some silly gyrations, you can’t mix local includes with library includes. That is, double-quoted includes in the library, like this in Libraries/NMEAGPS.h:

    #include "NMEAGPS_cfg.h"

to get the sketch’s config, cannot be mixed with this in the .INO file:

    #include <NMEAGPS.h>

But I’m not the first to complain about the differences between the IDE and a “normal” C/C++ directory structure. Oh well. The other thing is that most users don’t like to modify files in the Libaries subdirectory, with good reason. So I am reluctant to put the config files in a Libraries/NeoGPS subdirectory. That would also force all sketches to use the same configuration, not something I am willing to do, having a great variety of test programs.

Sounds like you’re enjoying the challenge!

Cheers,
/dev

dave_sausages:
when the documentation appears

I just finished adding the distance, bearing (aka course_to) and offset (new!) calculations, documented here. The OffsetBy method allows you to calculate a new location, given a bearing and distance to “travel”.

Cheers,
/dev