uBlox and Arduino serial communications

I am working on integrating a fourth uBlox binary UBX message (TIMEUTC) for date and time logging into the ArduIMU.

The problem is (i believe) that the total of all four messages counts to 132 bytes. The arduino’s serial buffer can only do 128 so I am dropping the last four bytes which ends up throwing off the minutes and seconds and last checksums. Unfortunately I cannot adjust the messages coming out of the uBlox (i would love to create a custom message) :(.

Does anyone know a better way to read the serial buffer in order to get additional message support??
The ArduIMU code snippet is here

void decode_gps(void)
{
  static unsigned long GPS_timer=0;
  byte data;
  int numc;
  
  numc = Serial.available();
  if (numc > 0)
    for (int i=0; i<numc; i++)  // Process bytes received
    {
      data = Serial.read();
      switch(UBX_step)     //Normally we start from zero. This is a state machine
      {
      case 0:  
        if(data==0xB5)  // UBX sync char 1
          UBX_step++;   //OH first data packet is correct, so jump to the next step
        break; 
      case 1:  
        if(data==0x62)  // UBX sync char 2
          UBX_step++;   //ooh! The second data packet is correct, jump to the step 2
        else 
          UBX_step=0;   //Nope, its not correct so go to step zero and try again.     
        break;
      case 2:
        UBX_class=data;
        checksum(UBX_class);
        UBX_step++;
        break;
      case 3:
        UBX_id=data;
        checksum(UBX_id);
        UBX_step++;
        break;
      case 4:
        UBX_payload_length_hi=data;
        checksum(UBX_payload_length_hi);
        UBX_step++;
        break;
      case 5:
        UBX_payload_length_lo=data;
        checksum(UBX_payload_length_lo);
        UBX_step++;
        break;
      case 6:         // Payload data read...
      if (UBX_payload_counter < UBX_payload_length_hi)  // We stay in this state until we reach the payload_length
        {
          UBX_buffer[UBX_payload_counter] = data;
          checksum(data);
          UBX_payload_counter++;
        }
        else
          UBX_step++; 
        break;
      case 7:
        UBX_ck_a=data;   // First checksum byte
        UBX_step++;
        break;
      case 8:
        UBX_ck_b=data;   // Second checksum byte
       
        // We end the GPS read...
        if((ck_a=UBX_ck_a)&&(ck_b=UBX_ck_a))   // Verify the received checksum with the generated checksum.. 
              parse_ubx_gps();               // Parse new GPS packet...
        
        for (int q=0;q<41;q++)
          {
            UBX_buffer[q] = 0;
          }
        
        UBX_step=0;
        UBX_payload_counter=0;
        ck_a=0;
        ck_b=0;
        GPS_timer=millis(); //Restarting timer...
        break;
        
      } // End Switch
    } // End For

}

Thank You!

Wow, two different forums, two posts and it seems everyone is stumped.

How often is decode_gps being called?

It should be calling at 50Hz. But I have not measured it yet. Do you think calling this function faster will help?

I know there is a way to sketch up a function that displays the loop rate but I forgot it.

I tried to simplify the code a bit more and let it run as fast as possible with the same result. It randomly drops those last bytes. I included the full sketch.

/*GPS variables*/
int gpsFix=1;
int gpsFixnew=0;
float lat=0;
float lon=0;
float alt_MSL=0;
long iTOW=0;
long alt=0; 
float speed_3d=0;
float ground_speed=0;
float ground_course=90;
char data_update_event=0;
short time_year=0;
int time_month=0;
int time_day=0;
int time_hour=0;
int time_minute=0;
int time_second=0;
byte ck_a=0;
byte ck_b=0;
byte UBX_step=0;
byte UBX_class=0;
byte UBX_id=0;
byte UBX_payload_length_hi=0;
byte UBX_payload_length_lo=0;
byte UBX_payload_counter=0;
byte UBX_buffer[40];
byte UBX_ck_a=0;
byte UBX_ck_b=0;
/********************************************************************************************************************************/
void setup()
{ 
  Serial.begin(38400);
  pinMode(2,OUTPUT); //Serial Mux
  digitalWrite(2,HIGH); //Serial Mux
  pinMode(5,OUTPUT); //Red LED
  pinMode(6,OUTPUT); // BLue LED
  pinMode(7,OUTPUT); // Yellow LED
  pinMode(9,OUTPUT);
  Serial.println("ArduIMU");
}
/********************************************************************************************************************************/
void loop() //Main Loop
{
    decode_gps();
    printdata();
}

/****************************************************************
  Here you have all the parsing stuff for uBlox
 ****************************************************************/
 // Code from Jordi, modified by Jose

 // Baud Rate:38400

void decode_gps(void)
{
  static unsigned long GPS_timer=0;
  byte data;
  int numc;
  
  numc = Serial.available();
  if (numc > 0)
    for (int i=0; i<numc; i++)  // Process bytes received
    {
      data = Serial.read();
      switch(UBX_step)     //Normally we start from zero. This is a state machine
      {
      case 0:  
        if(data==0xB5)  // UBX sync char 1
          UBX_step++;   //OH first data packet is correct, so jump to the next step
        break; 
      case 1:  
        if(data==0x62)  // UBX sync char 2
          UBX_step++;   //ooh! The second data packet is correct, jump to the step 2
        else 
          UBX_step=0;   //Nope, its not correct so go to step zero and try again.     
        break;
      case 2:
        UBX_class=data;
        checksum(UBX_class);
        UBX_step++;
        break;
      case 3:
        UBX_id=data;
        checksum(UBX_id);
        UBX_step++;
        break;
      case 4:
        UBX_payload_length_hi=data;
        checksum(UBX_payload_length_hi);
        UBX_step++;
        break;
      case 5:
        UBX_payload_length_lo=data;
        checksum(UBX_payload_length_lo);
        UBX_step++;
        break;
      case 6:         // Payload data read...
      if (UBX_payload_counter < UBX_payload_length_hi)  // We stay in this state until we reach the payload_length
        {
          UBX_buffer[UBX_payload_counter] = data;
          checksum(data);
          UBX_payload_counter++;
        }
        else
          UBX_step++; 
        break;
      case 7:
        UBX_ck_a=data;   // First checksum byte
        UBX_step++;
        break;
      case 8:
        UBX_ck_b=data;   // Second checksum byte
       
        // We end the GPS read...
        if((ck_a=UBX_ck_a)&&(ck_b=UBX_ck_a))   // Verify the received checksum with the generated checksum.. 
              parse_ubx_gps();               // Parse new GPS packet...
        
        for (int q=0;q<41;q++)
          {
            UBX_buffer[q] = 0;
          }
        
        UBX_step=0;
        UBX_payload_counter=0;
        ck_a=0;
        ck_b=0;
        GPS_timer=millis(); //Restarting timer...
        break;
        
      } // End Switch
    } // End For

}
/********************************************************************************************************************************/
void parse_ubx_gps()
{
 
//Verifing if we are in class 1, you can change this "IF" for a "Switch" in case you want to use other UBX classes.. 
//In this case all the message im using are in class 1, to know more about classes check PAGE 60 of DataSheet.
  if(UBX_class==0x01) 
  {
    switch(UBX_id)//Checking the UBX ID
    {
    case 0x02: //ID NAV-POSLLH 
      iTOW    = join_4_bytes(&UBX_buffer[0]);
      lon     = (float)join_4_bytes(&UBX_buffer[4])/10000000.0;
      lat     = (float)join_4_bytes(&UBX_buffer[8])/10000000.0;
      alt     = (float)join_4_bytes(&UBX_buffer[12])/1000.0;
      alt_MSL = (float)join_4_bytes(&UBX_buffer[16])/1000.0;
      data_update_event|=0x01;
      break;
      
    case 0x03://ID NAV-STATUS 
      if(UBX_buffer[4] >= 0x03)
      {
        gpsFix=0; //valid position
        gpsFixnew=1;  //new information available flag for binary message
        digitalWrite(6,HIGH);  //Turn LED when gps is fixed. 
      }
      else
      {
        gpsFix=1; //invalid position
        digitalWrite(6,LOW);
      }
      break;

    case 0x12:// ID NAV-VELNED 
      speed_3d      = (float)join_4_bytes(&UBX_buffer[16])/100.0; // m/s
      ground_speed  = (float)join_4_bytes(&UBX_buffer[20])/100.0; // Ground speed 2D
      ground_course = (float)join_4_bytes(&UBX_buffer[24])/100000.0; // Heading 2D
      data_update_event|=0x02; //Update the flag to indicate the new data has arrived.
      break; 
      
    case 0x21:// ID NAV-TIMEUTC
      time_month  = join_1_bytes(&UBX_buffer[14]);
      time_day    = join_1_bytes(&UBX_buffer[15]);
      time_year   = join_2_bytes(&UBX_buffer[12]);
      time_hour   = join_1_bytes(&UBX_buffer[16]);
      time_minute = join_1_bytes(&UBX_buffer[17]);
      time_second = join_1_bytes(&UBX_buffer[18]);
      break; 
      }
   }

}

/********************************************************************************************************************************/
 // Join 4 bytes into a long
int32_t join_4_bytes(byte Buffer[])
{
  longUnion.byte[0] = *Buffer;
  longUnion.byte[1] = *(Buffer+1);
  longUnion.byte[2] = *(Buffer+2);
  longUnion.byte[3] = *(Buffer+3);
  return(longUnion.dword);
}
/********************************************************************************************************************************/
 // Join 2 bytes into a long
int32_t join_2_bytes(byte Buffer[])
{
  longUnion.byte[0] = *Buffer;
  longUnion.byte[1] = *(Buffer+1);

  return(longUnion.dword);
}
/********************************************************************************************************************************/
 // Join 1 byte into an int
int32_t join_1_bytes(byte Buffer[])
{
  intUnion.byte[0] = *Buffer;

  return(intUnion.word);
}
/********************************************************************************************************************************/
void checksum(byte ubx_data)
{
  ck_a += ubx_data;
  ck_b += ck_a; 
}
/********************************************************************************************************************************/
void printdata(void)//ToDeg(x)
{    
 
      Serial.print("LAT:");
      Serial.print((long)(lat*10000000));
      Serial.print(",LON:");
      Serial.print((long)(lon*10000000));
      Serial.print(",ALT:");
      Serial.print(alt_MSL);
      Serial.print(",COG:");
      Serial.print((ground_course));
      Serial.print(",SOG:");
      Serial.print(ground_speed);
      Serial.print(",FIX:");
      Serial.print((int)gpsFix);
      Serial.print(",Time:");
      Serial.print(time_month);
      Serial.print("/");
      Serial.print(time_day);
      Serial.print("/");
      Serial.print(time_year);
      Serial.print("---");
      Serial.print(time_hour);
      Serial.print(":");
      Serial.print(time_minute);
      Serial.print(".");
      Serial.print(time_second);      
      Serial.println("***");    
}
/********************************************************************************************************************************/
union long_union {
      int32_t dword;
      uint8_t  byte[4];
} longUnion;

union int_union {
      int16_t word;
      uint8_t  byte[2];
} intUnion;

Try calling printdata less often. Maybe something like this...

/********************************************************************************************************************************/
unsigned long LastMS;
/********************************************************************************************************************************/
void setup()
{
// existing setup code goes here
  LastMS = millis();
}
/********************************************************************************************************************************/
void loop() //Main Loop
{
    decode_gps();

    unsigned long ThisMS = milli();

    if ( ThisMS - LastMS >= 1000 )
    {
        printdata();
        LastMS = ThisMS;
    }
}

That worked a little. Below is the output. I ran it with the 1000ms delay and then played with it from 50ms on up. It produced the output where any two or three of the parameters (lat,lon, speed, etc) were updating, the rest of the parameters were not updating. I should also note that I am using the GPS Emulator from Happy Kilmore which outputs the UBlox protocol without having to stand outside (too cold right now.) It is setup to send the 4 messages at 4Hz at 38400 baud. I wish I could wrap my head around this better but I am having a mental block. I could set the Ublox to a lower rate, 3hz, but I would like the 4Hz. I would also like to keep the loop running at no less than 5Hz. Thanks,

LAT:500119296,LON:330130624,ALT:10352.50,COG:86.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:77.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:68.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:59.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:50.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:41.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:32.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:23.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:14.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:5.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:356.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***
LAT:500119296,LON:330130624,ALT:10352.50,COG:347.00,SOG:54.99,FIX:0,Time:2/12/2010---21:18.57***

Does using a lower baud rate (like 9600) make a difference?

I did make some progress. After doing more digging in the forums I changed the RX_BUFFER_SIZE from 128 to 132. I ran a very simple sketch that basically printed the hex vaules that the GPS is sending. I verified that all the bytes are getting there.

I also changed the baud rate as low as 4800 with the same effect (either two of the datafields are locking up while the others are being updated correctly.) Once I disable one of the messages on the GPS side all other datafields begin to work again. I can't see why this would happen.

Yeah! I got it. I can now get all the information updating. I believe it was the checksuming that may have been the culprit. I also replaced the switch in the parse_ubx_gps() with an IF. Anyway heres the code. Now time to move on to the rest of my project ( ArduIMU Logging.)

Thanks Again,

The Code…

union long_union {
      int32_t dword;
      uint8_t  byte[4];
} longUnion;

union int_union {
      int16_t word;
      uint8_t  byte[2];
} intUnion;

/*GPS variables*/
int gpsFix=1;
int gpsFixnew=0;
float lat=0;
float lon=0;
float alt_MSL=0;
long iTOW=0;
long alt=0; 
float speed_3d=0;
float ground_speed=0;
float ground_course=90;
char data_update_event=0;
short time_year=0;
int time_month=0;
int time_day=0;
int time_hour=0;
int time_minute=0;
int time_second=0;
byte ck_a=0;
byte ck_b=0;
byte GPS_step=0;
byte UBX_class=0;
byte UBX_id=0;
byte UBX_payload_length_hi=0;
byte UBX_payload_length_lo=0;
byte UBX_payload_counter=0;
byte UBX_buffer[40];
byte UBX_ck_a=0;
byte UBX_ck_b=0;
unsigned long LastMS;

/********************************************************************************************************************************/
void setup()
{ 
  Serial.begin(38400);
  pinMode(2,OUTPUT); //Serial Mux
  digitalWrite(2,HIGH); //Serial Mux
  pinMode(5,OUTPUT); //Red LED
  pinMode(6,OUTPUT); // BLue LED
  pinMode(7,OUTPUT); // Yellow LED
  pinMode(9,OUTPUT);
  LastMS = millis();
}
/********************************************************************************************************************************/
void loop() // Main Loop
{
    decode_gps();
    unsigned long ThisMS = millis();

    if ( ThisMS - LastMS >= 250 ){
        printdata();
        LastMS = ThisMS;}
} // End Main loop
/*******************************************************
  Here you have all the parsing stuff for uBlox
 ****************************************************/
// Code from Jordi, modified by Jose
void decode_gps(void)
{
  static unsigned long GPS_timer=0;
  byte data;
  int numc;
  numc = Serial.available();
if (numc > 0){
  for (int i=0; i<numc; i++){ // We will loop through the serial buffer and store the incoming data into the array UBX_buffer[]
    data = Serial.read(); // On each loop of this for we are placing one byte at a time from the serial buffer
    switch(GPS_step){ //Normally we start from zero. This is a state machine
      case 0:      
            if(data==0xB5) // UBX sync char 1
                GPS_step++; //ooh! first data packet is correct. Jump to the next step.
            break; 
      case 1:      
            if(data==0x62) // UBX sync char 2
              GPS_step++; // The second data packet is correct, jump to step 2
            else GPS_step=0; //Nope, incorrect. Restart to step zero and try again.             
            break;
      case 2:
            UBX_class = data; // This is the byte that will give our uBlox class
            checksum(UBX_class);
            GPS_step++;
            break;
      case 3:
            UBX_id = data; // This is the byte that will give our uBlox ID such as NAV-POSLLH, VELNED, STATUS, etc
            checksum(UBX_id);
            GPS_step++;
            break;
      case 4:
            UBX_payload_length_hi = data; // This is the first byte that will give us the payload length
            checksum(UBX_payload_length_hi);
            GPS_step++;
            break;
      case 5:
            UBX_payload_length_lo = data; // This is the second byte that will give us the payload length
            checksum(UBX_payload_length_lo);
            GPS_step++;
            break;
      // revised version thx to Christopher Barnes
      case 6: // Payload data read...
            // We need to process the data byte before we check the number of bytes so far
            UBX_buffer[UBX_payload_counter] = data;
            checksum(data);
            UBX_payload_counter++;
            if (UBX_payload_counter < UBX_payload_length_hi) // We stay in this state until we reach the payload_length
                { 
                } 
                else 
                {
                  GPS_step++; // payload_length reached - next byte is checksum
            }
            break;
      case 7:
            UBX_ck_a=data;       // First checksum byte
            GPS_step++;
            break;
      case 8: // We end the GPS read...
            UBX_ck_b=data;       // Second checksum byte
            if((ck_a == UBX_ck_a) && (ck_b == UBX_ck_b)) // Verify the received checksum with the generated checksum
                { 
              parse_ubx_gps(); // Parse the new GPS packet
              GPS_timer = millis(); //Restarting timer...
            }
      // Variable re-initialization
            GPS_step = 0;
            UBX_payload_counter = 0;
            ck_a = 0;
            ck_b = 0;
            break;
      } // End Switch
    } // End For
  } // End IF
} // End Function void decode_gps(void)
/****************************************************/
void parse_ubx_gps()
{
  if(UBX_id==0x02){ //ID NAV-POSLLH
      lon     = (float)join_4_bytes(&UBX_buffer[4])/10000000.0;
      lat     = (float)join_4_bytes(&UBX_buffer[8])/10000000.0;
      alt     = (float)join_4_bytes(&UBX_buffer[12])/1000.0;
      alt_MSL = (float)join_4_bytes(&UBX_buffer[16])/1000.0;}
     
    if(UBX_id==0x03){ //ID NAV-STATUS
      if(UBX_buffer[4] >= 0x03) { gpsFix=0; digitalWrite(6,HIGH); }
      else { gpsFix=1; digitalWrite(6,LOW); }}
      
    if(UBX_id==0x12){ // ID NAV-VELNED
      speed_3d      = (float)join_4_bytes(&UBX_buffer[16])/100.0;
      ground_speed  = (float)join_4_bytes(&UBX_buffer[20])/100.0;
      ground_course = (float)join_4_bytes(&UBX_buffer[24])/100000.0;}
      
    if(UBX_id==0x21){ // ID NAV-TIMEUTC
      time_month  = join_1_bytes(&UBX_buffer[14]);
      time_day    = join_1_bytes(&UBX_buffer[15]);
      time_year   = join_2_bytes(&UBX_buffer[12]);
      time_hour   = join_1_bytes(&UBX_buffer[16]);
      time_minute = join_1_bytes(&UBX_buffer[17]);
      time_second = join_1_bytes(&UBX_buffer[18]);}
} // End Function void parse_ubx_gps()

/******************************************************/
 // Join 4 bytes into a long
int32_t join_4_bytes(byte Buffer[]){
  longUnion.byte[0] = *Buffer;
  longUnion.byte[1] = *(Buffer+1);
  longUnion.byte[2] = *(Buffer+2);
  longUnion.byte[3] = *(Buffer+3);
  return(longUnion.dword);}
/********************************************************************************************************************************/
 // Join 2 bytes into a long
int32_t join_2_bytes(byte Buffer[]){
  longUnion.byte[0] = *Buffer;
  longUnion.byte[1] = *(Buffer+1);
  return(longUnion.dword);}
/********************************************************************************************************************************/
 // Join 1 byte into an int
int32_t join_1_bytes(byte Buffer[]){
  intUnion.byte[0] = *Buffer;
  return(intUnion.word);}
/********************************************************************************************************************************/
void checksum(byte ubx_data){
  ck_a += ubx_data;
  ck_b += ck_a;}
/********************************************************************************************************************************/
void printdata(void)
{    
      Serial.print("LAT:");
      Serial.print((long)(lat*10000000));
      Serial.print(",LON:");
      Serial.print((long)(lon*10000000));
      Serial.print(",ALT:");
      Serial.print(alt_MSL);
      Serial.print(",COG:");
      Serial.print((ground_course));
      Serial.print(",SOG:");
      Serial.print(ground_speed);
      Serial.print(",FIX:");
      Serial.print((int)gpsFix);
      Serial.print(",Time:");
      Serial.print(time_month);
      Serial.print("/");
      Serial.print(time_day);
      Serial.print("/");
      Serial.print(time_year);
      Serial.print("---");
      Serial.print(time_hour);
      Serial.print(":");
      Serial.print(time_minute);
      Serial.print(".");
      Serial.print(time_second);      
      Serial.println("***");    
}