Guide by Jaryd; How to add GPS to Your Arduino | Add Real-Time Location to Your Project!

Jane, while I dont have a build to test with, my thoughts were more around the UART and buffers V “refresh” rate. e.g. if it was happening too fast, there may not be a full packet to decode…
that said, I assume this bit of code was meant to deal with ensuring enough time had passed

  // Check if timeout occurred with data in buffer
  if (current_time - last_data_time > timeout_ms && message_buffer.length() > 0) {
    _process_buffer();
    has_new_data = true;
  }

But if the message_buffer was == 0 then it would skip over the time delay and check the uart buffer.

Then the other bit I was not too sure on was

 // If buffer is empty or we recently received data, append to buffer
    if (message_buffer.length() == 0 || current_time - last_data_time <= timeout_ms) {
      message_buffer += data;
    } else {
      // If timeout occurred, process the old buffer first
      _process_buffer();
      // Then start a new buffer
      message_buffer = data;
      has_new_data = true;
    }

If the message buffer was > 0 bytes long, then it would not append the new data, but if it was == 0, it would append the data, but not process until next time.

To be fair here, this is a high level thought as Im reading the code, but could be that way for a very good reason.

I normally process uart data in its own thread or via IRQ. so would append data as it arrived into the buffer. Then if there was at least 1 full sentence present, parse it.
Of course that is not always ideal… and there is more the one valid way to do things.

EDIT: I just want to be clear, my thought was data could get lost if not sampled at a fair rate. That does not mean that is whats happening.

2 Likes

Hey @Euan284221,

Been looking through this, and it has stumped me a little. This code was designed for the Uno R3 and R4, but I don’t see why it won’t work on the nano?

Also, just confirming, does the serial output show the number of satellites or altitude, or is it zero as well?

1 Like

Hey @Jaryd

Yeah this has really been confusing me too. The raw serial output from the GPS shows about 7 satellites normally and the altitude is non-zero, about 100m.

Hey @Euan284221 ,

Why don’t we try taking a step back and make sure we are on the same page about your setup.

Would you be able to share some photos of your components and how they are connected, as well as the code you are currently using? I have tried to recreate your issues with a Uno R4 and a Nano Every, and couldn’t replicate this result, so hopefully this isn’t a compatibility issue with your Nano.

Maybe it’s something to do with how the data is being sent to the display?

1 Like

Sure thing!

In terms of the wiring, here is what I am currently using, I have not tried to use the OLED until I can get the parsing to the serial monitor to work.

Then the code I am using with the GPSParserV3 is:

// Arduino GPS Demo using GPSParser library

#include <SoftwareSerial.h>

#include “GPSParser.h”

// Define RX and TX pins for the GPS module

const int GPS_RX_PIN = 2;  // Arduino pin connected to GPS TX

const int GPS_TX_PIN = 3;  // Arduino pin connected to GPS RX

// Initialize the software serial port

SoftwareSerial gpsSerial(GPS_RX_PIN, GPS_TX_PIN);

// Create a GPS reader that handles all the complexity

GPSReader gps(gpsSerial);

void setup() {

// Initialize software serial for GPS communication

gpsSerial.begin(9600);

// Initialize serial for debugging

Serial.begin(9600);

}

void loop() {

// Get the GPS data (automatically updates)

GPSData gps_data = gps.get_data();

/*

.has_fix

.latitude

.longitude

.speed_knots

.time

.date

.satellites

.altitude

.hdop

.pdop

.vdop

*/

// Print the GPS data

Serial.print("Fix: ");

Serial.print(gps_data.has_fix ? “Yes” : “No”);

Serial.print(", Latitude: ");

Serial.print(gps_data.latitude, 6);

Serial.print(", Longitude: ");

Serial.print(gps_data.longitude, 6);

// Additional data

Serial.print(", Satellites: ");

Serial.print(gps_data.satellites);

Serial.print(", Altitude: ");

Serial.println(gps_data.altitude);

// Small delay

delay(100);

}
1 Like

My current thought was around the timing/frequency of the reading V uart buffer being read/emptied into the string for processing.
e.g. what if some sentences where getting dropped due to uart buffer being full, then, for example you might end up always missing the same sentences as they tend to come out in the same order ever update.

So maybe a debug line printing the raw sentence as its been processed, that should confirm that that all needed sentences needed are captured and processed.

Edit:
Maybe a debug line in :
GPSData GPSReader::_process_nmea_data(String nmea_data)

 ...
    String sentence = nmea_data.substring(start, end);
    sentence.trim();

// Add debug here to print "sentence" 

    // Parse different sentence types
    if (sentence.startsWith("$GPRMC")) {
1 Like

Hey @Euan284221 ,

I have some good and bad news! The good news is I managed to recreate your issue on my end (I was using a different Arduino Nano board version to you previously). The bad news is that this is probably an issue inherent to the board you are using and doesn’t seem to be an easy fix.

The Arduino Uno R4 suggested by the guide uses the Renesas RA4M1 while the Nano Every uses the ATmega4809 MCU which is not designed to work reliably at higher baud rates like the 9600 speed set as the default for the NEO-6 GPS module.

The datasheet has some documentation for changing the baud rate of the NEO-6 but this isn’t broken out on this particular module and I wasn’t able to successfully change this by sending a binary UBX “CFG‑PRT” (configure port) message at the start of the arduino code.

Maybe someone else more familiar with this kind of thing will have some suggestions but from what I have found, it seems like the Arduino Nano Every is not particularly well suited to work with this GPS module.

Thank you very much!

That is unfortunate. Like I said the raw data output worked fine but then when parsing the data, it was losing the altitude and satellite number data. Weirdly enough though, I tried running the same code and wiring with an Uno R3 I was using for another project, and I ran into the same issue of the raw output working fine but the parsing library not working completely. So maybe it is a combination of both the parser and nano every chip?

1 Like

After a bit of playing and sniffing changing the baud rate command also changes a few other values, so the following my need to be tweaked, but should work.
Its a 2 part process,

a) change the baud rate, and test, but leave powered on (as its not saved, so reconnect with the new baud rate..
If something goes wrong then power down and it will revert back.

b) If happy its working… save the config so it will now power up in the rate.
Note: this could be optional if you are happy just to set the baud rate in code at boot time. … there will be some pros/cons for each way.

So send the commands, you need to cloud out a binary string.

Set 4800 0xB5620600140001000000D0080000 C0120000 0700030000000000 CFE4              
Set 9600 0xB5620600140001000000D0080000 80250000 0700030000000000 A2B5 
Save 0xB56206090D0000000000FFFF00000000000003 1DAB  

I separated the baud value location, but keep in mind if you change that you will need to re-calc the 2 check sum bytes.

Note for more control you would need to break down each field.
I used u-center to find a working command, BUT its seemed to set the protocol out to nothing in my setup, so I got no data from the gps. I then set the protocol out to be UBX and NMEA, which will give the ack/nak in binary for the UBX commands.

A rough version of the checksum function (so tweak as per your pref.

Not the check sum “data” is everything from byte 2 (0 and 1 are header sync) up to the end of the data, the append as the last 2 bytes, CS_A CS_B

void TForm1::NeoGPSCheckBytes (uint8_t *data, int len, uint8_t *chk_a, uint8_t *chk_b)
{
	uint8_t cka, ckb;

	cka = 0;
	ckb = 0;

	for (int i = 0; i < len; i++) {
		cka = cka + data[i];
		ckb = ckb + cka;
	}
	*chk_a = cka;
	*chk_b = ckb;

}

Edit: Source Refence Document : https://content.u-blox.com/sites/default/files/products/documents/u-blox6_ReceiverDescrProtSpec_(GPS.G6-SW-10018)_Public.pdf

1 Like

That is very interesting thank you very much @Michael99645 , I can definitely have a try of changing the baud rate. What does stand out to me is that when I tried with my Uno R3, which should work, I ran into the same issue, so I agree with your previous point that something must be going on in the GPSParser library that it is not getting all the data it should.

Just a thought here… in the post above where you pasted the screen short of the sentence output, I not you have this set
GPRMC GPVTG GPGGA GPGSA GPGSV GPGLL

The GPS library, is (currently) only using
GPRMC GPGGA GPGSA

Bu turning off the others, there will be less data sent from the GPS to the module, thus less chance of buffer full.
GPVTG GPGSV GPGLL

Turn off GPVTG : B5 62 06 01 08 00 F0 05 00 00 00 00 00 00 04 46 
Turn on GPVTG  : B5 62 06 01 08 00 F0 05 01 01 01 01 01 01 0A 5B 

Turn off GPGSV : B5 62 06 01 08 00 F0 03 00 00 00 00 00 00 02 38 
Turn on GPGSV  : B5 62 06 01 08 00 F0 03 01 01 01 01 01 01 08 4D 

Turn off GPGLL : B5 62 06 01 08 00 F0 01 00 00 00 00 00 00 00 2A 
Turn on GPGLL  : B5 62 06 01 08 00 F0 01 01 01 01 01 01 01 06 3F 

Note: these are full packets with correct check bytes ready to go for the Neo 6

1 Like

One finaly thought… You will need to check this for your exact board and setup.
From a google.

“…While the default is 64 bytes, it is possible to increase the buffer size in some cases, such as for the Nano Every, where it can be increased by powers of 2 up to 256 bytes by modifying the relevant core file. For other Arduino boards, the buffer size can be modified by changing the SERIAL_RX_BUFFER_SIZE macro in HardwareSerial.h or by using build flags in development environments like PlatformIO…”

So if the buffer is only 64 Bytes, then that would need to be cleared fairly often.
64 may not even be enough for 1 sentence to fit.
On my quick test with the sentences limit to just the 3 needed, i had about 204 bytes. So limiting sentences and increase the uart buffer to 256 should be more stable.

Some math:
9600 8 data bits 1 stop bit, no parity, 1 start bit.
10 Bits per byte,
10 * 204 bytes = 2040 bits
(assuming no real pause between bytes, fastest time)
2040 / 9600 = 212.5 ms for those three sentences.

For a 64 byte buffer,
640 bits / 9600 = 67 ms to fill the buffer when it starts, so you would need to check more frequent then that to ensure no data loss/uart buffer full,

For testing in your main loop, maybe try dropping down the 100ms to 30ms. I say 30ms as your code will have other overhead so 30+overhead needs the be less the 67ms between checks

1 Like

Thank you so much @Michael99645 for your advice, I really appreciate it! I tried increasing the buffer size like you said and that seemed to help it, but pairing that with updating the gps using the line gps.update a couple of times every loop completely fixed the issue, and now I have it all up and running as per the guide with the OLED. I think the updating is achieving what you mentioend of tweaking the 100ms delay.

Once again thank you everyone for your insights and assistance in fixing my issue!!

EDIT: For anyone else who might be having a similar issue, it doesn’t hurt to use the extra hardware serial the nano every on pins D1 and D0 for more stable results, in conjunction with increasing the buffer size and refreshing the gps in the loop program :slight_smile:

3 Likes

Great, good to know we could get it working with tweaking the UART buffer size and keeping it empty with more frequent calls.

1 Like