Some problems with UBX parser

Please observe that I declare ONE array called GPS_info_buffer

#define GPS_INFO_BUFFER_SIZE 60 // enough for both the strings (SOL is only 52 long)
byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];

That array is long enough for all the different messages. So I reuse that same declared location for putting the different received sentences (VELNED, POSLLH and SOL). This uses 60 bytes of RAM, where if I had declared them separately I had used 58 (SOL) + 34 (POSLLH) + 42 (VELNED) = 134 bytes of RAM.
Since I am parsing the sentences one by one, I don't need to store them all 3.
I suspect there are more elegant ways to temporary allocate RAM for a defined datastructure and free ut up after usage (hence my interest for struct), but that is beyond my knowledge. And like anyone, I have to work with what I can.

This is why you see that all sentences are parsed similarly by taking the required bytes from a given (by the datasheet) position in the GPS_info_buffer.

Example
In case of SOL and VELNED the content of GPS info buffer would be different like this:
Note: I do not store the very first 0xB5 character in the array

GPS_info_buffer      SOL                 VELNED
===================================================
[0]                  0x62                0x62
[1]                  0x01                0x01
[2]                  0x06                0x12
[3]                  Length (byte 1)     Length (byte 1)
[4]                  Length (byte 2)     Length (byte 2)
[5]                  iTOW (byte 1)       iTOW (byte 1)       
[6]                  iTOW (byte 2)       iTOW (byte 2)       
[7]                  iTOW (byte 3)       iTOW (byte 3)       
[8]                  iTOW (byte 4)       iTOW (byte 4)       
[9]                  fTOW (byte 1)       velN (byte 1)
[10]                 fTOW (byte 2)       velN (byte 2)
[11]                 fTOW (byte 3)       velN (byte 3)
[12]                 fTOW (byte 4)       velN (byte 4)
[13]                 week (byte 1)       velE (byte 1)
[14]                 week (byte 2)       velE (byte 2)
[15]                 gpsFix (byte)       velE (byte 3)
[16]                 flags  (byte)       velE (byte 4)
etc.

Now imagine there is a SOL sentence in the GPS_info_buffer and you want to know the week.According to the datasheet it is a 2 byte signed int (I2) and it is in Little Endian

Parsing it would be

week  =  (int)GPS_info_buffer[14] << 8; // take the most signifacant byte and shift it 8 position left.
week  += (int)GPS_info_buffer[13];      // add the least significant byte to it (without shifting)

Now week is a int with the two single bytes from the buffer glued together in the Little Endian order to make one integer.

Next imagine there is a VELNED sentence in the GPS_info_buffer and you want to know the velE .According to the datasheet it is a 4 byte signed int (I4) and it is in Little Endian

2 (the least significant two) out of its 4 bytes are at the same location in the GPS_info_buffer as where "week" was in the SOL sentence.

so parsing it is like what you have seen before

              velE   = (long)GPS_info_buffer[16] << 24;
              velE  += (long)GPS_info_buffer[15] << 16;
              velE  += (long)GPS_info_buffer[14] << 8;
              velE  += (long)GPS_info_buffer[13];

Now velE is a 4 byte signed long with the 4 bytes from the buffer glued together in Little Endian order to make one long.

We are also using the positions [14] and [13] again, but they have totally different content/meaning now in the second example.

Let me know if this helped, or there is something else that needs explaining. I assumed you are familiar with the bit shifting.

1 Like

Yes, I understand byte shifts and bit operations.
I often use it when working on the i2c bus.

Wire.requestFrom(address, 7);
*x = (int)(int16_t)(Wire.read() | Wire.read() << 8);
*y = (int)(int16_t)(Wire.read() | Wire.read() << 8);
*z = (int)(int16_t)(Wire.read() | Wire.read() << 8);

Perhaps a little later I will understand your train of thought and rewrite the code into the library.
For now it works and that's enough for me :roll_eyes:

Still, the code does not want to work if you add a small delay associated with the operation of other functions.
That is, the example code can only work for itself and, at most, send data to the serial port.
I need data from the parser to use in a filter to estimate position, and I'm not getting that data.
Annoyance and sadness...
The only solution is to buy a new module; after all, NEO-6M is morally and technically outdated.

Have you had experience working with the NMEA protocol and maybe have any thoughts on how to obtain 3D speeds?

We managed to assemble the code, but so far the parser data is not output.
Code gps_test.ino

#define STATUS_LED PC13
#define GPS_INFO_BUFFER_SIZE 60

#define DEBUG

#include <gps_ubx.h>

#define SERIAL_BAUD 115200 // max data rate 100 Hz
// #define SERIAL_BAUD 230400 // max data rate 200 Hz
// #define SERIAL_BAUD 921600 // max data rate 1000 Hz
#define GNSS_BAUD 230400

const long displayPeriod = 20;
unsigned long previousMillis = 0;

// feature Arduino_Core_STM32
HardwareSerial Serial2(USART2); 

//Create a instance of class GNSS
GNSS Gnss;

void setup() 
{

	Serial.begin(SERIAL_BAUD);

	pinMode(STATUS_LED, OUTPUT);  // Status LED
	
	digitalWrite(STATUS_LED, HIGH); // stm32f411 led OFF

	if (!Gnss.Begin(GNSS_BAUD, Serial2)) 
	{
	#ifdef DEBUG
	Serial.println("Connect GNSS fail");
	#endif
	while (1) {}
	}
	delay(500);
	#ifdef DEBUG
	Serial.println("Communication GNSS OK");
	#endif

}

void loop()
{ 
	Gnss.Read();
  
	if (millis() - previousMillis >= displayPeriod)
	{
	digitalWrite(STATUS_LED, !digitalRead(STATUS_LED));
	previousMillis = millis();
	#ifdef DEBUG
	Serial.print(" Longitude: ");
	Serial.println(Gnss.nav.lon);
	Serial.print(" Latitude: ");
	Serial.println(Gnss.nav.lat);
	Serial.print(" Height MSL: ");
	Serial.println(Gnss.nav.alt_msl_m);
	Serial.print(" Number satellite in view: ");
	Serial.println(Gnss.nav.numSV);
	#endif

	}
  
}

Code gps_ubx.h

#ifndef GPS_UBX_H
#define GPS_UBX_H

#include <Arduino.h>

class GNSS {
	
/* struct NAVstruct {
    // uint32_t iTOW;
    uint32_t iTOW_velned;
    int32_t lon;
    int32_t lat;
    // int32_t height_above_sea_level;
    int32_t alt_msl_m;
    uint32_t hAcc;
    uint32_t vAcc;
    int32_t north_vel_mps;
    int32_t east_vel_mps;
    int32_t down_vel_mps;
    // int32_t velN;
    // int32_t velE;
    // int32_t velD;
    uint32_t gSpeed;
    int32_t heading;
    uint32_t sAcc;
    uint32_t pDOP;
    uint32_t numSV;
}; */
	
/* struct NAVstruct {
  // posllh
  unsigned char cls_posllh;
  unsigned char id_posllh;
  unsigned short len_posllh;
  unsigned long iTOW_posllh;
  long lon;
  long lat;
  // long lat_lon;
  long alt_msl_m;
  unsigned long hAcc;
  unsigned long vAcc;
  // velned
  unsigned char cls_velned;
  unsigned char id_velned;
  unsigned short len_velned;
  unsigned long iTOW_velned; // U4
  long north_vel_mps; // I4
  long east_vel_mps;
  long down_vel_mps;
  unsigned long speed; // Spd (3D)
  unsigned long gSpeed;
  long heading;
  unsigned long sAcc;
  unsigned long numSV;
	}; */

public:

struct NAVstruct {
    // uint32_t iTOW;
    uint32_t iTOW_velned;
    int32_t lon;
    int32_t lat;
    // int32_t height_above_sea_level;
    int32_t alt_msl_m;
    uint32_t hAcc;
    uint32_t vAcc;
    int32_t north_vel_mps;
    int32_t east_vel_mps;
    int32_t down_vel_mps;
    // int32_t velN;
    // int32_t velE;
    // int32_t velD;
    uint32_t speed;
    uint32_t gSpeed;
    int32_t heading;
    uint32_t sAcc;
    uint32_t pDOP;
    uint32_t numSV;
};

	  NAVstruct nav;

	GNSS() {
	  message_started = false;
	  received_char = 0;
	  string_length = 0;
	}

	// void Begin(int baud) {
	  // Serial2.begin(baud);
	// }

	bool Begin(long baudRate, HardwareSerial& serialPort) {
	  serialPort.begin(baudRate);
	  serialPort_ = &serialPort;
	  return true;
	}

	bool Read() {
	  // if (Serial2.available()) {
	  if (serialPort_->available()) {
		// byte GPS_info_char = Serial2.read();
		byte GPS_info_char = serialPort_->read();
		if (GPS_info_char == 0xb5) {
		  message_started = true;
		  received_char = 0;
		} else if (message_started == true) {
		  if (received_char < string_length) {
			GPS_info_buffer[received_char] = GPS_info_char;
			if (GPS_info_buffer[2] == 0x12) string_length = 42;
			if (GPS_info_buffer[2] == 0x02) string_length = 34;
			if (GPS_info_buffer[2] == 0x06) string_length = 58;
			received_char++;
		  } else {
			GPS_info_buffer[received_char] = GPS_info_char;
			UBX_calculate_checksum(GPS_info_buffer, 1, (string_length - 2));

			switch (string_length) {
		  case 42: // VELNED string received
			if (CK_A == GPS_info_buffer[41] && CK_B == GPS_info_buffer[42]) { // confirm received and calculated checksums are the same
			  digitalWrite(STATUS_LED, HIGH); // stm32f411 led OFF
			  // convert the GPS buffer array bytes 5,6,7,8 into one "unsigned long" (4 byte) field
			  iTOW   = (long)GPS_info_buffer[8] << 24;
			  iTOW  += (long)GPS_info_buffer[7] << 16;
			  iTOW  += (long)GPS_info_buffer[6] << 8;
			  iTOW  += (long)GPS_info_buffer[5];
			  nav.iTOW_velned = iTOW;
			  return nav.iTOW_velned;
			  // return;
			  // Serial.print(" iTOW: "); Serial.println(nav.iTOW_velned);
			  // convert the GPS buffer array bytes 9,10,11,12 into one "unsigned long" (4 byte) field
			  velN   = (long)GPS_info_buffer[12] << 24;
			  velN  += (long)GPS_info_buffer[11] << 16;
			  velN  += (long)GPS_info_buffer[10] << 8;
			  velN  += (long)GPS_info_buffer[9];
			  nav.north_vel_mps = velN;
			  return nav.north_vel_mps;
			  // return;
			  // Serial.print(" velN: "); Serial.println(nav.velN * 1e-2f);
			  // convert the GPS buffer array bytes 13,14,15,16 into one "unsigned long" (4 byte) field
			  velE   = (long)GPS_info_buffer[16] << 24;
			  velE  += (long)GPS_info_buffer[15] << 16;
			  velE  += (long)GPS_info_buffer[14] << 8;
			  velE  += (long)GPS_info_buffer[13];
			  nav.east_vel_mps = velE;
			  return nav.east_vel_mps;
			  // return;
			  // Serial.print(" velE: "); Serial.println(nav.velE * 1e-2f);
			  // convert the GPS buffer array bytes 17,18,19,20 into one "unsigned long" (4 byte) field
			  velD   = (long)GPS_info_buffer[20] << 24;
			  velD  += (long)GPS_info_buffer[19] << 16;
			  velD  += (long)GPS_info_buffer[18] << 8;
			  velD  += (long)GPS_info_buffer[17];
			  nav.down_vel_mps = velD;
			  return nav.down_vel_mps;
			  // return;
			  // Serial.print(" velD: "); Serial.println(nav.velD * 1e-2f);

			  // convert the GPS buffer array bytes 24,23,22,21 into one "unsigned long" (4 byte) field
			  velocity_3d   = (long)GPS_info_buffer[24] << 24;
			  velocity_3d  += (long)GPS_info_buffer[23] << 16;
			  velocity_3d  += (long)GPS_info_buffer[22] << 8;
			  velocity_3d  += (long)GPS_info_buffer[21];
			  spd_kts = (((float)velocity_3d * 1.94381) / 100);

			  // convert the GPS buffer array bytes 28,27,26,25 into one "unsigned long" (4 byte) field
			  ground_speed  = (long)GPS_info_buffer[28] << 24;
			  ground_speed += (long)GPS_info_buffer[27] << 16;
			  ground_speed += (long)GPS_info_buffer[26] << 8;
			  ground_speed += (long)GPS_info_buffer[25];
			  ground_speed = ((float)ground_speed / 100);

			  // convert the GPS buffer array bytes 32,31,30,29 into one "unsigned long" (4 byte) field
			  hdg  = (long)GPS_info_buffer[32] << 24;
			  hdg += (long)GPS_info_buffer[31] << 16;
			  hdg += (long)GPS_info_buffer[30] << 8;
			  hdg += (long)GPS_info_buffer[29];
			  hdg = ((float)hdg / 100000);
			}
			else {// when checksum error set speed = 0
			  spd_kts = 0;
			  ground_speed = 0;
			  hdg = 0;
			}

			// gps_speed.value = ground_speed;               //in 0.001 kts
			nav.gSpeed = ground_speed;               //in 0.001 kts
			return nav.gSpeed;
			// return;
			// Serial.print(" gSpeed: "); Serial.println(nav.gSpeed);
			// gps_cog.value = heading;                  //in 0.01 degrees
			nav.heading = hdg;                  //in 0.01 degrees
			return nav.heading;
			// return;
			// Serial.print(" heading: "); Serial.println(nav.heading);
	//            gps_date_time.value = 0;                //t.b.d. difficult to understand formula/mechanism
			// ass_airspeed.value = spd_kts;            //in 0.1 kts
			nav.speed = spd_kts;            //in 0.1 kts
			return nav.speed;
			// return;
			// Serial.print(" speed: "); Serial.println(nav.speed);

			break;
		  case 34: //POSLLH string received

			if (CK_A == GPS_info_buffer[33] && CK_B == GPS_info_buffer[34]) { // confirm received and calculated checksums are the same
			  // convert the GPS buffer array bytes into one "long" (4 byte) field
			  longitude   = (long)GPS_info_buffer[12] << 24;
			  longitude  += (long)GPS_info_buffer[11] << 16;
			  longitude  += (long)GPS_info_buffer[10] << 8;
			  longitude  += (long)GPS_info_buffer[9];

			  nav.lon = longitude;
			  return nav.lon;
			  // return;

			  // Serial.print(" lat/lon: ");
			  // Serial.print(longitude/10000000.0f);

			  latitude   = (long)GPS_info_buffer[16] << 24;
			  latitude  += (long)GPS_info_buffer[15] << 16;
			  latitude  += (long)GPS_info_buffer[14] << 8;
			  latitude  += (long)GPS_info_buffer[13];

			  nav.lat = latitude;
			  return nav.lat;
			  // return;

			  // Serial.print(","); 
			  // Serial.println(latitude/10000000.0f);

			  height_above_sea_level   = (long)GPS_info_buffer[24] << 24;
			  height_above_sea_level  += (long)GPS_info_buffer[23] << 16;
			  height_above_sea_level  += (long)GPS_info_buffer[22] << 8;
			  height_above_sea_level  += (long)GPS_info_buffer[21];
			  height_above_sea_level  = (height_above_sea_level / 1000);

			  nav.alt_msl_m = height_above_sea_level;                //in cm but per 10cm displayed
			  return nav.alt_msl_m;
			  // return;
			  // Serial.print(" height: "); Serial.println(nav.height);
			}
			else {
			  longitude = 0;
			  latitude = 0;
			  height_above_sea_level = 0;
			}
			break;
			// Set GPS data
			// if (sendlat == 0) {
			//   gps_lat_lon.value = (( ((((uint32_t)( longitude < 0 ? -longitude : longitude)) / 10 ) * 6 ) / 10 ) & 0x3FFFFFFF)  | 0x80000000;
			  // // nav.lat_lon = (( ((((uint32_t)( longitude < 0 ? -longitude : longitude)) / 10 ) * 6 ) / 10 ) & 0x3FFFFFFF)  | 0x80000000;
			//   if (longitude < 0) gps_lat_lon.value |= 0x40000000;
			  // if (longitude < 0) nav.lat_lon |= 0x40000000;
			  // sendlat = 1;
			  // Serial.print(" lat_lon: "); Serial.println(nav.lat_lon);
			// }
			// else {
			//   gps_lat_lon.value = ((  ((((uint32_t)( latitude < 0 ? -latitude : latitude)) / 10 ) * 6 ) / 10 ) & 0x3FFFFFFF ) ;
			  // // nav.lat_lon = ((  ((((uint32_t)( latitude < 0 ? -latitude : latitude)) / 10 ) * 6 ) / 10 ) & 0x3FFFFFFF ) ;
			//   if (latitude < 0) gps_lat_lon.value |= 0x40000000;
			  // if (latitude < 0) nav.lat_lon |= 0x40000000;
			  // sendlat = 0;
			  // Serial.print(" lat_lon: "); Serial.println(nav.lat_lon);
			// }
			// gps_alt.value = height_above_sea_level;                //in cm but per 10cm displayed
		// ubxPrint();
		  case 58: // SOL string received
			if (CK_A == GPS_info_buffer[57] && CK_B == GPS_info_buffer[58]) { // confirm received and calculated checksums are the same
			  fixok = (( GPS_info_buffer[11 + 5] & B00000001) && ( GPS_info_buffer[10 + 5]) == 0x03); // fix status flag = 1 AND a 3Dfix
			  digitalWrite(STATUS_LED, !fixok);

			  satInView = GPS_info_buffer[47 + 5];

			  // satInView  = (long)GPS_info_buffer[52] << 24;
			  // satInView += (long)GPS_info_buffer[51] << 16;
			  // satInView += (long)GPS_info_buffer[50] << 8;
			  // satInView += (long)GPS_info_buffer[49];

			  nav.numSV = satInView;
			  return nav.numSV;
			  // return;

			  // Serial.print(" satInView: "); Serial.println(nav.numSV);
			}
		  break;
		}
			}
			message_started = false;
		  }
		}
return true;
	}
	
		void UBX_calculate_checksum(uint8_t* array, unsigned int array_start, unsigned int array_length) {
		  CK_A = 0;
		  CK_B = 0;
		  for (unsigned int i = 0; i < array_length; i++) {
			CK_A = CK_A + array[array_start + i];
			CK_B = CK_B + CK_A;
		  }
		}	
	


private:
	// NAVstruct nav;
	HardwareSerial* serialPort_;
	bool message_started;
	byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
	byte string_length = 58;
	unsigned int received_char;
	byte fixok = 0; // flag to indicate a valid GPS fix was received.
	//CHECKSUM CALCULATION VARIABLE
	unsigned char CK_A;
	unsigned char CK_B;	
	// variables
	unsigned long iTOW; // time of week
	unsigned long velocity_3d; // speed in centimeter / second
	unsigned long ground_speed;
	unsigned long satInView; // Number of SVs used in Nav Solution
	long velN; // speed in centimeter / second
	long velE; // speed in centimeter / second
	long velD; // speed in centimeter / second
	long longitude;//longitude
	long latitude;//latitude
	long height_above_sea_level;//height above main sea level
	float spd_kts; //speed in knots
	float hdg;  
}; // close class

#endif

Compile OK

compileOK

Output in serial port

Communication GNSS OK
 Longitude: 0
 Latitude: 0
 Height MSL: 0
 Number satellite in view: 0

gps_test.zip (4,7 КБ)

I get the same print as you. All zero values. So something is wrong with your code, since when I try my own sketch, to print some VELNED parsed fields it works just fine.

this sketch

/*******************************************************************************************
  This example uses 2 serial ports, one for connecting a NEO-M6N GPS and one for printing
*******************************************************************************************/
#define GPS_BAUD_RATE 9600  // The GPS Shield module defaults to 9600 baud

// choose the UART for connecting your GPS and the UARRT to print with
// I am using Atmega328PB, which has two UARTS Serial and Serial1
#define gpsPort Serial
#define SerialMonitor Serial1

//format hex command strings for sending to UBLOX
const char velned[] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1e, 0x67};
const char airborne[] = {0xb5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xff, 0xff, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27,
                         0x00, 0x00, 0x05, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x64, 0x00, 0x2c, 0x01, 0x00, 0x3c, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0b, 0xb5, 0x62, 0x06, 0x24,
                         0x00, 0x00, 0x2a, 0x84
                        };
const char rate_a[] = {0xb5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xfa, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x96};
const char rate_b[] = {0xb5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0e, 0x30};


#define GPS_INFO_BUFFER_SIZE 50
//char GPS_info_char;
byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
unsigned int received_char;
int i = 0; // counter
bool message_started = false;

unsigned long ms_time_week; //GPS millicecond Time of Week
unsigned long velocity_3d; // speed in centimeter / second
float spd_kph; //speed in kilometers per hour
unsigned long velocity_accuracy; // in centimeter / second 


//CHECKSUM CALCULATION VARIABLE
unsigned char CK_A = 0;
unsigned char CK_B = 0;


void setup()
{
  delay(1000);
  gpsPort.begin(GPS_BAUD_RATE);
  SerialMonitor.begin(9600);
  SerialMonitor.println("start of setup");
  delay(100);
  gpsPort.println(F("$PUBX,40,RMC,0,0,0,0*47")); //RMC OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,VTG,0,0,0,0*5E")); //VTG OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GGA,0,0,0,0*5A")); //CGA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSA,0,0,0,0*4E")); //GSA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSV,0,0,0,0*59")); //GSV OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GLL,0,0,0,0*5C")); //GLL OFF
  delay(100);


  gpsPort.write(airborne, sizeof(airborne)); //set GPS mode to airborne < 4g
  delay(100);
  gpsPort.write(rate_a, sizeof(rate_a)); //set GPS update rate to 4Hz
  delay(100);
  gpsPort.write(rate_b, sizeof(rate_b)); //set GPS update rate to 4Hz
  delay(100);
  gpsPort.write(velned, sizeof(velned)); // VELNED (VELocity, North, East, Down) message ON
}

void loop()
{ //start loop
  if (gpsPort.available()) { // If GPS data is available
    byte *GPS_info_char = gpsPort.read();  // Read it and store as HEX char

    if (GPS_info_char == 0xb5) { // ublox B5 gevonden
      //      Serial.println("UBLUX b5 gevonden");
      message_started = true;
      received_char = 0;
    } // end ublox B5 gevonden
    else if (message_started == true) { // the message is already started and I got a new character
      if (received_char < 42) { // buffer not full
        GPS_info_buffer[received_char] = GPS_info_char;
        received_char++;
      } else { // final character received
        GPS_info_buffer[received_char] = GPS_info_char;

        //        for (i = 0; i <= received_char; i++) {
        //          Serial.print(GPS_info_buffer[i], HEX); // writes the buffer to the PC once it has been completely received
        //          Serial.print("."); // writes dot inbetween characters
        //        }
        //        SerialMonitor.print("...checksum received..."); // the last 2 received characters are the checksum
        //        SerialMonitor.print(GPS_info_buffer[41],HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines
        //        SerialMonitor.print(GPS_info_buffer[42],HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines

        UBX_calculate_checksum(GPS_info_buffer, 1, 40); // calculates checksum
        //        SerialMonitor.print("...calculated checksum..."); // calculated checksum from received characters
        //        SerialMonitor.print(CK_A,HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines
        //        SerialMonitor.print(CK_B,HEX);
        //        SerialMonitor.println("."); // writes dot inbetween lines

        if (CK_A == GPS_info_buffer[41] && CK_B == GPS_info_buffer[42]) { // confirm received and calculated checksums are the same

          //        Serial.println("Checksum ok");
          // convert the GPS buffer array bytes 8,7,6,5 into one "unsigned long" (4 byte) field
          ms_time_week  = (long)GPS_info_buffer[8] << 24;
          ms_time_week += (long)GPS_info_buffer[7] << 16;
          ms_time_week += (long)GPS_info_buffer[6] << 8;
          ms_time_week += (long)GPS_info_buffer[5];
          SerialMonitor.print(" Timestamp: ");
          SerialMonitor.print(ms_time_week,DEC);

          // convert the GPS buffer array bytes 24,23,22,21 into one "unsigned long" (4 byte) field
          velocity_3d   = (long)GPS_info_buffer[24] << 24;
          velocity_3d  += (long)GPS_info_buffer[23] << 16;
          velocity_3d  += (long)GPS_info_buffer[22] << 8;
          velocity_3d  += (long)GPS_info_buffer[21];
          SerialMonitor.print(" Velocity_3D: ");
          SerialMonitor.print(velocity_3d, DEC);

          spd_kph = (((float)velocity_3d * 36)/ 1000);
          SerialMonitor.print(" Km/h.. ");
          SerialMonitor.print(spd_kph,2);

          // convert the GPS buffer array bytes 36,35,34,33 into one "unsigned long" (4 byte) field
          velocity_accuracy   = (long)GPS_info_buffer[36] << 24;
          velocity_accuracy  += (long)GPS_info_buffer[35] << 16;
          velocity_accuracy  += (long)GPS_info_buffer[34] << 8;
          velocity_accuracy  += (long)GPS_info_buffer[33];
          SerialMonitor.print(" Velocity_accuracy: ");
          SerialMonitor.print(velocity_accuracy, DEC);
          SerialMonitor.println();

        }
        else    SerialMonitor.println("Checksum error");
        message_started = false; // ready for the new message
      } // end final character received
    } // end the message is already started and I got a new character
  } // end If GPS data is available

// rest of programming here
  
} // end loop

// CALCULATES THE UBX CHECKSUM OF A CHAR ARRAY
void UBX_calculate_checksum(uint8_t* array, unsigned int array_start, unsigned int array_length) {
  CK_A = 0;
  CK_B = 0;
  unsigned int i;
  for (i = 0; i < array_length; i++) {
    CK_A = CK_A + array[array_start + i];
    CK_B = CK_B + CK_A;
  }
}

gives me this

start of setup
 Timestamp: 43117750 Velocity_3D: 28 Km/h.. 1.01 Velocity_accuracy: 109
 Timestamp: 43118750 Velocity_3D: 76 Km/h.. 2.74 Velocity_accuracy: 115
 Timestamp: 43119000 Velocity_3D: 123 Km/h.. 4.43 Velocity_accuracy: 121
 Timestamp: 43119250 Velocity_3D: 119 Km/h.. 4.28 Velocity_accuracy: 137
 Timestamp: 43119500 Velocity_3D: 154 Km/h.. 5.54 Velocity_accuracy: 140
 Timestamp: 43119750 Velocity_3D: 114 Km/h.. 4.10 Velocity_accuracy: 143
 Timestamp: 43120000 Velocity_3D: 111 Km/h.. 4.00 Velocity_accuracy: 137
 Timestamp: 43120250 Velocity_3D: 86 Km/h.. 3.10 Velocity_accuracy: 126
 Timestamp: 43120500 Velocity_3D: 72 Km/h.. 2.59 Velocity_accuracy: 125
 Timestamp: 43120750 Velocity_3D: 67 Km/h.. 2.41 Velocity_accuracy: 111
 Timestamp: 43121000 Velocity_3D: 80 Km/h.. 2.88 Velocity_accuracy: 135
 Timestamp: 43121250 Velocity_3D: 40 Km/h.. 1.44 Velocity_accuracy: 103
2 Likes

So the code is similar to yours, the READ function is one to one.
So I can’t understand why the zero values.
Add a delay of 10-15 ms in the endless loop, after
SerialMonitor.println();
and you should also have zero values.

Why would I do that? That's deliberately making sure that the loop() cannot keep up with the baudrate of the serial datastream coming out of the GPS. The UART buffer can hold one character, but that needs to be dealt with before the next character arrives.

Thinking about this again. Probably the "Serial" function has a multibyte software buffer also. I think I even had to change that once, so you would have to repeat receiving the characters until that buffer is empty.
The

if (gpsPort.available()) { // If GPS data is available

is most likely not looking at the HW UART buffer, but at the Serial buffer. But I don't know much about how Serial has been built on Arduino. It uses a LOT of memory, so probably complicated.

1 Like

Well, the work of the program should be useful.
Now the code only works for itself, and you cannot get data from it.
By introducing a delay, we simulate the operation of other algorithms in an endless loop.
The only option is to take one microcontroller to work with the GPS module and supply data to the series, and another MCU to receive this data.
But is this redundant?
The following code works, but as soon as I add an imitation of another program using a delay of even 10 ms, I immediately get zero values.
Which does not allow the use of a parser and another part of the program that receives data on the same microcontroller.

#define SERIAL_BAUD 115200
#define GNSS_BAUD 115200

#define STATUS_LED PC13

HardwareSerial Serial2(USART2); // PA2(TX2), PA3(RX2)

#define GPS_INFO_BUFFER_SIZE 100 // enough for both the strings (SOL is only 52 long)
byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
byte string_length = 58;  //VELNED lenght is 42, POSLLH lenght is 34, SOL length is 58. Initialize with longest string.
unsigned int received_char;
int i = 0; // counter
bool message_started = false;

unsigned long iTOW; // time of week
long velN; // speed in centimeter / second
long velE; // speed in centimeter / second
long velD; // speed in centimeter / second
unsigned long velocity_3d; // speed in centimeter / second
float spd_kts; //speed in knots
long longitude;//longitude
long latitude;//latitude
long height_above_sea_level;//height above main sea level
unsigned long ground_speed;
unsigned long satInView; // Number of SVs used in Nav Solution
float heading;

//CHECKSUM CALCULATION VARIABLE
unsigned char CK_A = 0;
unsigned char CK_B = 0;

byte fixok = 0; // flag to indicate a valid GPS fix was received.

struct NAV {
  // posllh
  unsigned char cls_posllh;
  unsigned char id_posllh;
  unsigned short len_posllh;
  unsigned long iTOW_posllh;
  long lon;
  long lat;
  long lat_lon;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
  // velned
  unsigned char cls_velned;
  unsigned char id_velned;
  unsigned short len_velned;
  unsigned long iTOW_velned; // U4
  long velN; // I4
  long velE;
  long velD;
  unsigned long speed; // Spd (3D)
  unsigned long gSpeed;
  long heading;
  unsigned long sAcc;
  unsigned long numSV;
} nav;

void setup() {

  pinMode(STATUS_LED, OUTPUT);
  digitalWrite(STATUS_LED, LOW); // stm32f411 led ON

    Serial.begin(SERIAL_BAUD);
    Serial2.begin(GNSS_BAUD);

} // end setup

void loop() {
  if (Serial2.available()) { // If GPS data is available
    byte GPS_info_char = Serial2.read();  // Read it and store as HEX char
    if (GPS_info_char == 0xb5) { // ublox B5 record found
      message_started = true;
      received_char = 0;
    } // end ublox B5 record found
    else if (message_started == true) { // the message is already started and I got a new character
      if (received_char < string_length) { // buffer not full
        GPS_info_buffer[received_char] = GPS_info_char;
        if (GPS_info_buffer[2] == 0x12) string_length = 42;  //VELNED lenght is 36 + 6
        if (GPS_info_buffer[2] == 0x02) string_length = 34;  //POSLLH lenght is 28 + 6
        if (GPS_info_buffer[2] == 0x06) string_length = 58;  //SOL lenght is 52 + 6
        received_char++;
      } // end buffer not full
      else { // final character received
        GPS_info_buffer[received_char] = GPS_info_char;
        UBX_calculate_checksum(GPS_info_buffer, 1, (string_length - 2)); // calculates checksum

        switch (string_length) {
          case 42: // VELNED string received
            if (CK_A == GPS_info_buffer[41] && CK_B == GPS_info_buffer[42]) { // confirm received and calculated checksums are the same
              digitalWrite(STATUS_LED, HIGH); // stm32f411 led OFF
              // convert the GPS buffer array bytes 5,6,7,8 into one "unsigned long" (4 byte) field
              iTOW   = (long)GPS_info_buffer[8] << 24;
              iTOW  += (long)GPS_info_buffer[7] << 16;
              iTOW  += (long)GPS_info_buffer[6] << 8;
              iTOW  += (long)GPS_info_buffer[5];
              nav.iTOW_velned = iTOW;
              // Serial.print(" iTOW: "); Serial.println(nav.iTOW_velned);
              // convert the GPS buffer array bytes 9,10,11,12 into one "unsigned long" (4 byte) field
              velN   = (long)GPS_info_buffer[12] << 24;
              velN  += (long)GPS_info_buffer[11] << 16;
              velN  += (long)GPS_info_buffer[10] << 8;
              velN  += (long)GPS_info_buffer[9];
              nav.velN = velN;
              // Serial.print(" velN: "); Serial.println(nav.velN * 1e-2f);
              // convert the GPS buffer array bytes 13,14,15,16 into one "unsigned long" (4 byte) field
              velE   = (long)GPS_info_buffer[16] << 24;
              velE  += (long)GPS_info_buffer[15] << 16;
              velE  += (long)GPS_info_buffer[14] << 8;
              velE  += (long)GPS_info_buffer[13];
              nav.velE = velE;
              // Serial.print(" velE: "); Serial.println(nav.velE * 1e-2f);
              // convert the GPS buffer array bytes 17,18,19,20 into one "unsigned long" (4 byte) field
              velD   = (long)GPS_info_buffer[20] << 24;
              velD  += (long)GPS_info_buffer[19] << 16;
              velD  += (long)GPS_info_buffer[18] << 8;
              velD  += (long)GPS_info_buffer[17];
              nav.velD = velD;
              // Serial.print(" velD: "); Serial.println(nav.velD * 1e-2f);

              // convert the GPS buffer array bytes 24,23,22,21 into one "unsigned long" (4 byte) field
              velocity_3d   = (long)GPS_info_buffer[24] << 24;
              velocity_3d  += (long)GPS_info_buffer[23] << 16;
              velocity_3d  += (long)GPS_info_buffer[22] << 8;
              velocity_3d  += (long)GPS_info_buffer[21];
              spd_kts = (((float)velocity_3d * 1.94381) / 100);

              nav.speed = spd_kts;            //in 0.1 kts
              // convert the GPS buffer array bytes 28,27,26,25 into one "unsigned long" (4 byte) field
              ground_speed  = (long)GPS_info_buffer[28] << 24;
              ground_speed += (long)GPS_info_buffer[27] << 16;
              ground_speed += (long)GPS_info_buffer[26] << 8;
              ground_speed += (long)GPS_info_buffer[25];
              ground_speed = ((float)ground_speed / 100);

              nav.gSpeed = ground_speed;               //in 0.001 kts
              // convert the GPS buffer array bytes 32,31,30,29 into one "unsigned long" (4 byte) field
              heading  = (long)GPS_info_buffer[32] << 24;
              heading += (long)GPS_info_buffer[31] << 16;
              heading += (long)GPS_info_buffer[30] << 8;
              heading += (long)GPS_info_buffer[29];
              heading = ((float)heading / 100000);

              nav.heading = heading;                  //in 0.01 degrees
            }
            else {// when checksum error set speed = 0
              spd_kts = 0;
              ground_speed = 0;
              heading = 0;
            }

            // gps_speed.value = ground_speed;               //in 0.001 kts
            // Serial.print(" gSpeed: "); Serial.println(nav.gSpeed);
            // gps_cog.value = heading;                  //in 0.01 degrees
            // Serial.print(" heading: "); Serial.println(nav.heading);
//            gps_date_time.value = 0;                //t.b.d. difficult to understand formula/mechanism
            // ass_airspeed.value = spd_kts;            //in 0.1 kts
            // Serial.print(" speed: "); Serial.println(nav.speed);

            break;
          case 34: //POSLLH string received

            if (CK_A == GPS_info_buffer[33] && CK_B == GPS_info_buffer[34]) { // confirm received and calculated checksums are the same
              // convert the GPS buffer array bytes into one "long" (4 byte) field
              longitude   = (long)GPS_info_buffer[12] << 24;
              longitude  += (long)GPS_info_buffer[11] << 16;
              longitude  += (long)GPS_info_buffer[10] << 8;
              longitude  += (long)GPS_info_buffer[9];

              nav.lon = longitude;

              // Serial.print(" lat/lon: ");
              // Serial.print(longitude/10000000.0f);

              latitude   = (long)GPS_info_buffer[16] << 24;
              latitude  += (long)GPS_info_buffer[15] << 16;
              latitude  += (long)GPS_info_buffer[14] << 8;
              latitude  += (long)GPS_info_buffer[13];

              nav.lat = latitude;

              // Serial.print(","); 
              // Serial.println(latitude/10000000.0f);

              height_above_sea_level   = (long)GPS_info_buffer[24] << 24;
              height_above_sea_level  += (long)GPS_info_buffer[23] << 16;
              height_above_sea_level  += (long)GPS_info_buffer[22] << 8;
              height_above_sea_level  += (long)GPS_info_buffer[21];
              height_above_sea_level  = (height_above_sea_level / 1000);

              nav.height = height_above_sea_level;                //in cm but per 10cm displayed
              // Serial.print(" height: "); Serial.println(nav.height);
            }
            else {
              longitude = 0;
              latitude = 0;
              height_above_sea_level = 0;
            }
            break;

          case 58: // SOL string received
            if (CK_A == GPS_info_buffer[57] && CK_B == GPS_info_buffer[58]) { // confirm received and calculated checksums are the same
              satInView = GPS_info_buffer[47 + 5];
              fixok = (( GPS_info_buffer[11 + 5] & B00000001) && ( GPS_info_buffer[10 + 5]) == 0x03); // fix status flag = 1 AND a 3Dfix
              digitalWrite(STATUS_LED, !fixok);


              // satInView  = (long)GPS_info_buffer[52] << 24;
              // satInView += (long)GPS_info_buffer[51] << 16;
              // satInView += (long)GPS_info_buffer[50] << 8;
              // satInView += (long)GPS_info_buffer[49];

              nav.numSV = satInView;

              // Serial.print(" satInView: "); Serial.println(nav.numSV);
            } else {
              satInView = 0;
            }
          break;
        }
        ubxPrint();
        message_started = false; // ready for the new message
      } // end final character received
    } // end the message is already started and I got a new character
  } // end If GPS data is available
//   hub.handle();                         //Handle new data
} // end loop

// CALCULATES THE UBX CHECKSUM OF A CHAR ARRAY
void UBX_calculate_checksum(uint8_t* array, unsigned int array_start, unsigned int array_length) {
  CK_A = 0;
  CK_B = 0;
  unsigned int i;
  for (i = 0; i < array_length; i++) {
    CK_A = CK_A + array[array_start + i];
    CK_B = CK_B + CK_A;
  }
}

void ubxPrint(){

  Serial.print(" iTOW: "); Serial.print(nav.iTOW_velned); // GPS Millisecond Time of Week
  Serial.print(" velN: "); Serial.print(nav.velN * 1e-2f); // m/s
  Serial.print(" velE: "); Serial.print(nav.velE * 1e-2f); // m/s
  Serial.print(" velD: "); Serial.print(nav.velD * 1e-2f); // m/s
  Serial.print(" speed: "); Serial.print(nav.speed); // m/s
  Serial.print(" gSpeed: "); Serial.print(nav.gSpeed); // m/s
  Serial.print(" heading: "); Serial.print(nav.heading); // m/s
  Serial.print(" lon: "); Serial.print(nav.lon/10000000.0f); // m/s
  Serial.print(" lat: "); Serial.print(nav.lat/10000000.0f); // m/s
  Serial.print(" height: "); Serial.print(nav.height); // m/s
  Serial.print(" satInView: "); Serial.println(nav.numSV);
  Serial.println();
// delay(10);
}
1 Like

At 9600 Baud GPS output I can add a delay(5) and then it works again.

You could try a lower baudrate for your GPS.

Remember that I use the parsing to send to a telemetry receiver. That receiver protocol expects my loop to run at a speed of 1 millisecond or faster. Or it can't keep up with the telemetry baudrate.

If I had something that takes 20 milliseconds to process, then I would have to create a separate ISR triggered by the UART (or a timer) that would take care of receiving the GPS characters and store them in the GPS_info_buffer.

Once the flag is set for buffer complete you can take all afternoon to parse it and do whatever needs done with the content.
And then give the ISR the "go ahead" to capture another one.

1 Like

Excepted!
The minimum speed is 115200, and there are plans to increase it to 921600, but probably not with the neo-6m module.
In general, this module adds a lot of problems.
Firstly, it is not clear what ubx protocol it has, judging by the uBlox family of GPS receivers it should be version 6, but when you read the firmware data, it is version 7.03 and in theory it should already have NAV-PVT, but my module does not have it.
All modern libraries work with nav-pvt, at least I did not find any libraries that work with my neo-6m module.
Regarding the code that I wrote above - even without explicitly specifying the delay, output to the ubxPrint() function occurs spontaneously and is associated with the calculation of the checksum, I can judge this by the blinking of the LED that responds to fixok
That is, the output of previous values goes on endlessly in a loop, only the values are not updated.

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8       

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 48714600 velN: 0.02 velE: 0.08 velD: 0.02 speed: 0 gSpeed: 0 heading: 272 lon: 0.00 lat: 0.00 height: 0 satInView: 8    

As soon as the LED flashes once, the values are updated and displayed again indefinitely.

 iTOW: 49524700 velN: -0.07 velE: 0.23 velD: 0.20 speed: 0 gSpeed: 0 heading: 311 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 49524700 velN: -0.07 velE: 0.23 velD: 0.20 speed: 0 gSpeed: 0 heading: 311 lon: 0.00 lat: 0.00 height: 0 satInView: 8

 iTOW: 49524700 velN: -0.07 velE: 0.23 velD: 0.20 speed: 0 gSpeed: 0 heading: 311 lon: 0.00 lat: 0.00 height: 0 satInView: 8

There may be 2 seconds between cycles, or maybe 15 seconds.
Did you run the code from post #25 and you also have null values, what do you think is the problem?
The idea was to use your code as a library, so as not to spontaneously receive data, but upon request through the Gnss.Read() function and with output in variables.

I ran that code after making a small modification to the definition of the two UART ports of my Atmega328PB board.

I got the null values like you.

I suspect it may have to do with how you defined your fields. Even when I put a fixed value right in the GPS datafield, the prints shows zero. The data just does not get picked up.

I suggest you first create a very small library concept and test if data defined inside your library is shown in a print in the main loop().

1 Like

I see in the NEO6M datasheet that it has ROM version 7.03

1 Like

You have to keep up with the speed that the GPS is outputting. It's not waiting for you to ask for something. And given the fact you want to increase baudrate, that's only getting worse.

The Serial.read() function in Arduino does that already. It is triggered by the USARTn_RX interrupt vector (USARTn Rx Complete) to take a character from the two byte UART rx buffer and put it in the serial read buffer, waiting for your serial.read() to pick it up.

So what you need to do is read ALL available characters from the serial.read()buffer, so that the serial.read() buffer is empty. Once it is empty, you have time to do something else, that takes 20 milliseconds. Because while doing that, the Arduino serial function will fill the serial.read buffer in the background, via the USARTn_RX interrupt

Just by adding one "else" statement you can accomplish that

// rest of programming here
  else { // there are no characters to be processed in the serial.read buffer
  delay(250);  // so there is time to do something else
  SerialMonitor.println("delaying"); // 
  }
} // end loop 

In this example I can afford a 250 millisecond delay and it contines to run. This is with a GPS baudrate of 9600. With your higher baudrate the delay you can afford will be less, but that is easy to try.

/******************************************************************************
  This example uses SoftwareSerial to communicate with the GPS module on
  pins 8 and 9. SoftwareSerial should work on most Arduinos, but it's a
  necessity on Arduino Mega's, Arduino Uno's, RedBoard's and any other Arduino
  based around an ATmega328P.

  After uploading the code, open your serial monitor, set it to 9600 baud, and
  watch the GPS module's NMEA strings begin to flow by. See if you can pick
  out the latitude and longitude.
******************************************************************************/

#
#define GPS_BAUD_RATE 9600  // The GPS Shield module defaults to 9600 baud
// Create a SoftwareSerial object called gps:

// We'll also define a more descriptive moniker for the Serial Monitor port.
// This is the hardware serial port on pins 0/1.
#define gpsPort Serial
#define SerialMonitor Serial1

//format hex command strings for sending to UBLOX
const char velned[] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1e, 0x67};
const char airborne[] = {0xb5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xff, 0xff, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27,
                         0x00, 0x00, 0x05, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x64, 0x00, 0x2c, 0x01, 0x00, 0x3c, 0x00, 0x00,
                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0b, 0xb5, 0x62, 0x06, 0x24,
                         0x00, 0x00, 0x2a, 0x84
                        };
const char rate_a[] = {0xb5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xfa, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x96};
const char rate_b[] = {0xb5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0e, 0x30};


#define GPS_INFO_BUFFER_SIZE 50
//char GPS_info_char;
byte GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
unsigned int received_char;
int i = 0; // counter
bool message_started = false;

unsigned long ms_time_week; //GPS millicecond Time of Week
unsigned long velocity_3d; // speed in centimeter / second
float spd_kph; //speed in kilometers per hour
unsigned long velocity_accuracy; // in centimeter / second 


//CHECKSUM CALCULATION VARIABLE
unsigned char CK_A = 0;
unsigned char CK_B = 0;


void setup()
{
  delay(1000);
  gpsPort.begin(GPS_BAUD_RATE);
  SerialMonitor.begin(9600);
  SerialMonitor.println("start of setup");
  delay(100);
  gpsPort.println(F("$PUBX,40,RMC,0,0,0,0*47")); //RMC OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,VTG,0,0,0,0*5E")); //VTG OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GGA,0,0,0,0*5A")); //CGA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSA,0,0,0,0*4E")); //GSA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSV,0,0,0,0*59")); //GSV OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GLL,0,0,0,0*5C")); //GLL OFF
  delay(100);


  gpsPort.write(airborne, sizeof(airborne)); //set GPS mode to airborne < 4g
  delay(100);
  gpsPort.write(rate_a, sizeof(rate_a)); //set GPS update rate to 4Hz
  delay(100);
  gpsPort.write(rate_b, sizeof(rate_b)); //set GPS update rate to 4Hz
  delay(100);
  gpsPort.write(velned, sizeof(velned)); // VELNED (VELocity, North, East, Down) message ON
}

void loop()
{ //start loop
  if (gpsPort.available()) { // If GPS data is available
    byte *GPS_info_char = gpsPort.read();  // Read it and store as HEX char

    if (GPS_info_char == 0xb5) { // ublox B5 gevonden
      //SerialMonitor.println("UBLUX b5 gevonden");
      message_started = true;
      received_char = 0;
    } // end ublox B5 gevonden
    else if (message_started == true) { // the message is already started and I got a new character
      if (received_char < 42) { // buffer not full
        GPS_info_buffer[received_char] = GPS_info_char;
        received_char++;
      } else { // final character received
        GPS_info_buffer[received_char] = GPS_info_char;

        //        for (i = 0; i <= received_char; i++) {
        //          SerialMonitor.print(GPS_info_buffer[i], HEX); // writes the buffer to the PC once it has been completely received
        //          SerialMonitor.print("."); // writes dot inbetween characters
        //        }
        //        SerialMonitor.print("...checksum received..."); // the last 2 received characters are the checksum
        //        SerialMonitor.print(GPS_info_buffer[41],HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines
        //        SerialMonitor.print(GPS_info_buffer[42],HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines

        UBX_calculate_checksum(GPS_info_buffer, 1, 40); // calculates checksum
        //        SerialMonitor.print("...calculated checksum..."); // calculated checksum from received characters
        //        SerialMonitor.print(CK_A,HEX);
        //        SerialMonitor.print("."); // writes dot inbetween lines
        //        SerialMonitor.print(CK_B,HEX);
        //        SerialMonitor.println("."); // writes dot inbetween lines

        if (CK_A == GPS_info_buffer[41] && CK_B == GPS_info_buffer[42]) { // confirm received and calculated checksums are the same

          //        Serial.println("Checksum ok");
          // convert the GPS buffer array bytes 8,7,6,5 into one "unsigned long" (4 byte) field
          ms_time_week  = (long)GPS_info_buffer[8] << 24;
          ms_time_week += (long)GPS_info_buffer[7] << 16;
          ms_time_week += (long)GPS_info_buffer[6] << 8;
          ms_time_week += (long)GPS_info_buffer[5];
          SerialMonitor.print(" Timestamp: ");
          SerialMonitor.print(ms_time_week,DEC);

          // convert the GPS buffer array bytes 24,23,22,21 into one "unsigned long" (4 byte) field
          velocity_3d   = (long)GPS_info_buffer[24] << 24;
          velocity_3d  += (long)GPS_info_buffer[23] << 16;
          velocity_3d  += (long)GPS_info_buffer[22] << 8;
          velocity_3d  += (long)GPS_info_buffer[21];
//          SerialMonitor.print(" Velocity_3D: ");
//          SerialMonitor.print(velocity_3d, DEC);

          spd_kph = (((float)velocity_3d * 36)/ 1000);
          SerialMonitor.print(" Km/h.. ");
          SerialMonitor.print(spd_kph,2);

          // convert the GPS buffer array bytes 36,35,34,33 into one "unsigned long" (4 byte) field
          velocity_accuracy   = (long)GPS_info_buffer[36] << 24;
          velocity_accuracy  += (long)GPS_info_buffer[35] << 16;
          velocity_accuracy  += (long)GPS_info_buffer[34] << 8;
          velocity_accuracy  += (long)GPS_info_buffer[33];
//          SerialMonitor.print(" Velocity_accuracy: ");
//          SerialMonitor.print(velocity_accuracy, DEC);
          SerialMonitor.println();
        }
        else    SerialMonitor.println("Checksum error");
        message_started = false; // ready for the new message
      } // end final character received
    } // end the message is already started and I got a new character
  } // end If GPS data is available

// rest of programming here
  else { // there are no characters to be processed in the serial.read buffer
  delay(250);  // so there is time to do something else
  SerialMonitor.println("delaying"); // 
  }
} // end loop 

// CALCULATES THE UBX CHECKSUM OF A CHAR ARRAY
void UBX_calculate_checksum(uint8_t* array, unsigned int array_start, unsigned int array_length) {
  CK_A = 0;
  CK_B = 0;
  unsigned int i;
  for (i = 0; i < array_length; i++) {
    CK_A = CK_A + array[array_start + i];
    CK_B = CK_B + CK_A;
  }
}
1 Like

A few clarifications on your code:

  1. This line
    byte *GPS_info_char = gpsPort.read();
    my compiler does not understand it, and I removed the star (pointeris not appropriate here).
  2. String
// rest of programming here
   else { // there are no characters to be processed in the serial.read buffer
   delay(250); // so there is time to do something else
   SerialMonitor.println("delaying"); //
   }

My output, even at 9600 speed.

delaying
delaying
delaying
delaying
delaying
delaying
delaying
delaying
delaying
delaying

But, I use
if (GPS_info_char == 0xb5 && GPS_info_char == 0x62)
Like in originally ubx protocol rules.

Then I changed on
if (GPS_info_char == 0xb5)
Output makes sense

 iTOW: 217692600
 velN: -0.40
 velE: 1.20
 velD: 0.06
 speed: 127
 gSpeed: 127
 heading: 109
delaying
delaying
delaying
 iTOW: 217692800
 velN: -0.43
 velE: 1.25
 velD: 0.07
 speed: 133
 gSpeed: 133
 heading: 109
delaying
delaying
 iTOW: 217693000
 velN: -0.43
 velE: 1.25

This condition refers to if (gpsPort.available()) and in principle it is not fulfilled, because in operation the GPS port is always available, so you can set a delay there of at least 250 seconds, the code simply will not notice it, because it does not go to this condition.
Probably using information read from the serial port buffer directly is not entirely correct?
Regarding solving the problem of empty values in class code from post #25
I'm trying to understand the logic of the parser code from professionals

These guys use the memcpy function
But I have never used it and attempts to use it also do not give results.
Continue these attempts, but I still ordered a newer neo-8n GPS module and when it arrives, I’ll probably give up trying to extract data using the ubx protocol from neo-6m.

As you have discovered your interpretation of the UBX protocol rules is wrong. The condition you are testing will always be false, as GPS_info_char can never be two different values at the same time

The first character is 'u' (0xb5) and the second 'b' (0x62) to identify a UBX sentence

Please notice that gpsPort is a redefinition of Serial. See the second line of my program.

#define gpsPort Serial

So in fact I am using the statement if Serial.available()

You can read in the Arduino reference what this command actually means.

I start to get the feeling that the UBX protocol nor the neo-6m is the problem, but the problem is between your keyboard and your chair :slight_smile:

So this is the root cause :grinning:
I'm far from a programmer, but I like to deal with complexities.

For my ancorwatch project I only need UTC and Lat-Lon data from the GPS-module.
But it is sending too much useless NMEA sentences.
So I found a way how to reduce the output of my NEO. (see u-blox neo6 manual)
There are some commands wich can supress NMEAs.

first:
#include <SoftwareSerial.h>
SoftwareSerial gps(RXPin, TXPin); //choose pins for serial port

SETUP section:

gps.begin(9600); //GPSmodul
delay(100);
gps.println("$PUBX,40,GLL,1,0,0,0,0,0(star)5D"); //no GLL
gps.println("$PUBX,40,GSV,1,0,0,0,0,0(star)58"); //no GSV
gps.println("$PUBX,40,GSA,1,0,0,0,0,0(star)4F"); //no GSA
gps.println("$PUBX,40,GGA,1,0,0,0,0,0(star)5B"); //no GGA

Now you will only receive $GPRMC and $GPVTG.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.