How to make a ublox GPS hold it's output

Hi,

I'm having a bit of trouble with my GPS unit and I'm hoping someone can help. I'm using a ublox 5 module and have it connected to Serial2 on my Arduino Mega. With the following bit of code

while(Serial2.available() > 0){
char data;
data=Serial2.read();
if(data=='$'){
Serial.print('\n');
}
Serial.print(data);
}

I get a nice print out of the NMEA data. However, the problem with this is my Arduino board does nothing but sit and read the output from the GPS unit. What I want to do is read in 10-15 bytes of data, place that in a buffer to sort through, allow my Arduino board to go and do something else, and then come back to read another 10-15 bytes of data. To do that I used the following bit of code

for(int k=0;k<10;k++){
if(Serial2.available() > 0){
char data;
data=Serial2.read();
if(data=='$'){
Serial.print('\n');
}
Serial.print(data);
}
}

However, when I use this bit of code it's clear that when I go to read the input of Serial2, I don't pick up where I left off. Instead of getting nice NMEA data, It's clear I'm missing pieces of data.

Is there a way to send a command to the u-block to have it hold it's output until I come back to it? i.e. something like the following

for(int k=0;k<10;k++){
*** Start sending data ***
if(Serial2.available() > 0){
char data;
data=Serial2.read();
if(data=='$'){
Serial.print('\n');
}
Serial.print(data);
}
*** stop sending data ***
}

Thanks for any help
Kathy

U-Blox modules have proprietary commands, so what does the module data sheet say is possible?

I use a character array to store the data from my GPS unit. I call this function every pass through loop. It only processes $GPRMC, but you can change that. It keeps adding characters to the gpsBuf array until it gets a newline character.

char gpsBuf[256];
byte tIndex[16];
char latDegrees[4];
char latMinutes[8];
char longDegrees[5];
char longMinutes[8];
char gpsSpeed[8];
char gpsHeading[8];
int charCount = 0;
boolean gpsLock = false;

void checkGPS() {
  while(Serial1.available()) {
    char ch = Serial1.read();
    
    if(charCount < 254 && ch != '\r' && ch != '\n') {
      gpsBuf[charCount] = ch;
      charCount++;      
      gpsBuf[charCount] = 0;
    }

    if(ch == '\n') {

      if(strncmp(gpsBuf,"$GPRMC",6) == 0) {
        int commaCount = 0;
        
        for(int i = 0; i < 254; i++) {
          if(gpsBuf[i] == ',') {
            tIndex[commaCount] = i + 1;
            gpsBuf[i] = 0;
            commaCount++;              
          }
          else if(gpsBuf[i] == '*') {
            gpsBuf[i] = 0;
            break;            
          }
        }


        if(gpsBuf[tIndex[1]] == 'A')
        {
          gpsLock = true;

          strcpy(latDegrees,&gpsBuf[tIndex[3]]);
          strncat(latDegrees,&gpsBuf[tIndex[2]],2);
          strcpy(latMinutes,&gpsBuf[tIndex[2] + 2]);

          strcpy(longDegrees,&gpsBuf[tIndex[5]]);
          strncat(longDegrees,&gpsBuf[tIndex[4]],3);
          strcpy(longMinutes,&gpsBuf[tIndex[4] + 3]);

          int thisSpeed = atoi(&gpsBuf[tIndex[6]]);
          itoa(thisSpeed,gpsSpeed,10);
          int thisHdg = atoi(&gpsBuf[tIndex[7]]);
          itoa(thisHdg,gpsHeading,10);
        }
        else {
          gpsLock = false;
        }
      }
            
      charCount = 0;
      gpsBuf[0] = 0;
    }
  }
}

edit: Added other arrays needed to process. This function is non-blocking, but because it isn't, you can't wait too long between calls or you will lose characters from the GPS unit.

My apology for the number of errors in the original code, but this function is from a sketch that has 9 files, and also manages an ethernet shield, a 10DOF AHRS unit, and a 16 channel servo controller.

Thanks, but I decided that that was too complicated for what I'm trying to do--I just want to log the messages directly to the log file, not to save them in an array. So I added the following code to convert the character pointer array to a string and then trim it:

//convert stringptr character array to string gps_message so we can use the trim function
    String gps_message(stringptr);
    //trim string to remove embedded new line characters
    gps_message.trim();

This successfully eliminates the new line character at the beginning of the string, and may eliminated at the end as well (I'm unsure about this one, because, just like before, when I open the serial monitor immediately after uploading the program, there is a new line character in between the end of the message and the >, but when I just plug in the board after previously uploading the program, there is no such new line character--I'm still not sure).

However, there is still an embedded new line character embedded in the middle of the string (in between each sentence), and I'm not sure how to remove it. Any suggestions?

I don't see it. These are all complete GPS sentences with a cr/lf at the end of each sentence. Can you explain where you see the embedded cr/lf? All these lines start with a $ and end with the * and checksum.

$PMTK001,314,336
$PMTK001,220,3
30
$GPGGA,191212.445,,,,,0,0$GPGGA,191213.445,,,,,0,0,,,M,,M,,44
$GPRMC,191213.445,V,,,,,0.00,0.00,130815,,,N
4F
Ready!
GPS string: <$GPGGA,191214.445,,,,,0,0,,,M,,M,,43
$GPRMC,191214.445,V,,,,,0.00,0.00,130815,,,N
48

$GPRMC,191214.445,V,,,,,0.00,0.00,130815,,,N*48

$GPGGA,191215.445,,,,,0,0,,,M,,M,,42
$GPRMC,191215.445,V,,,,,0.00,0.00,130815,,,N
49
GPS string: <$GPGGA,191216.445,,,,,0,0,,,M,,M,,41
$GPRMC,191216.445,V,,,,,0.00,0.00,130815,,,N
4A

$GPRMC,191216.445,V,,,,,0.00,0.00,130815,,,N*4A

$GPGGA,191217.445,,,,,0,0,,,M,,M,,40
$GPRMC,191217.445,V,,,,,0.00,0.00,130815,,,N
4B
GPS string: <$GPGGA,191218.445,,,,,0,0,,,M,,M,,4F
$GPRMC,191218.445,V,,,,,0.00,0.00,130815,,,N
44

$GPRMC,191218.445,V,,,,,0.00,0.00,130815,,,N*44

$GPGGA,191219.445,,,,,0,0,,,M,,M,,4E
$GPRMC,191219.445,V,,,,,0.00,0.00,130815,,,N
45
GPS string: <$GPGGA,191220.445,,,,,0,0,,,M,,M,,44
$GPRMC,191220.445,V,,,,,0.00,0.00,130815,,,N
4F

$GPRMC,191220.445,V,,,,,0.00,0.00,130815,,,N*4F

$GPGGA,191221.445,,,,,0,0,,,M,,M,,45
$GPRMC,191221.445,V,,,,,0.00,0.00,130815,,,N
4E
GPS string: <$GPGGA,191222.445,,,,,0,0,,,M,,M,,46
$GPRMC,191222.445,V,,,,,0.00,0.00,130815,,,N
4D

$GPRMC,191222.445,V,,,,,0.00,0.00,130815,,,N*4D

$GPGGA,191223.445,,,,,0,0,,,M,,M,,47
$GPRMC,191223.445,V,,,,,0.00,0.00,130815,,,N
4C
GPS string: <$GPGGA,191224.445,,,,,0,0,,,M,,M,,40
$GPRMC,191224.445,V,,,,,0.00,0.00,130815,,,N
4B

My code removes the cr/lf characters from the array. Disregard the code that parses the gpsBuf array.

    if(ch == '\n') {
      // the array is complete. Display it 
      Serial.println(gpsBuf);
      // and save to the SD card
      SD.println(gpsBuf);
      // then reset the gpsBuf pointer
      charCount = 0;
      // and set the first character to zero
      gpsBuf[0] = 0;

Thanks for all the advice. I don't think I was being clear enough on what I'm trying to do. Let me give a bit more background on my project to help. I've build a quad-copter and written the software all from scratch. Right now it just goes up, hovers 2 meters and then lands softly. I want to use the GPS to measure and control it's position. I've already written several functions to read the GPS data, store it in an array, parse through it to find the $GPRMC string, pull out the data I need, and covert that to meters moved. Everything works great and when I walk it around my block it draws out a rough square shape.

The problem is I need it to do all this in the time restraints of my feedback loop to keep the quad copter stable. As such, it can't spend more than say 4-5ms messing with the GPS during each loop. To get around this, my functions read in only 10 characters, stores it an array, and spreads the processing out over several time steps (If people would be interested in the code, I'd be more than happy to post it). Now when I use the i2c communication function of the GPS unit during each loop it reads in 10 characters, the code does it thing, and during the next loop the code reads in the next 10 characters, and it figures out my position well before the GPS refreshes with a new set of data. Unfortunately, using the GPS i2c communication causes all sorts of additional noise in all the other sensors using the i2c bus. After 3 weeks of messing around with logic level converters and pull up resistors I've given up trying to fix the noise the GPS adds to the i2c bus and have switched over to UART communication which doesn't cause any problems with creating noise. However when using UART, it doesn't pick up where it left off reading the data. For example, say my NMEA string is

$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62

During the first loop I read in the first 10 characters $GPRMC,081 store that in an array for parsing and move on. During the second iteration of the loop when I use Serial2.read() I want it to start reading at 836,A,3751 but instead it picks up somewhere way down the line. Since it didn't pick up where it left off, none of my code works.

What I need is to read in the first 10 characters $GPRMC,081 and send the GPS a command to stop sending data. Then during the next loop have the GPS start sending data again and read in the next 10 characters.

As jremington pointed out, u-blox has proprietary commands (UBX protocol) however the data sheet is very confusing and I was hoping someone with more experience with u-blox might be able to offer some advice on how to use the UBX commands or atleast point me in the direction of a tutorial.

Thanks again,
Kathy

During the first loop I read in the first 10 characters $GPRMC,081 store that in an array for parsing and move on. During the second iteration of the loop when I use Serial2.read() I want it to start reading at 836,A,3751 but instead it picks up somewhere way down the line. Since it didn't pick up where it left off, none of my code works.

Then you are not reading the serial data often enough. If you don't, as I mentioned earlier, you will lose characters when the serial buffer overflows.

This function is non-blocking, but because it isn't, you can't wait too long between calls or you will lose characters from the GPS unit.

edit: Here is a section in the playground on the ublox GPS with code for programming it.
http://playground.arduino.cc/UBlox/GPS

If you examine my code in reply #2, you will notice it doesn't read a set number of characters. It empties the serial buffer every call. It may be that reading 10 characters per call is not enough.

The problem is I need it to do all this in the time restraints of my feedback loop to keep the quad copter stable. As such, it can't spend more than say 4-5ms messing with the GPS during each loop.

I wrote the NeoGPS library just for this kind of application and time constraint. It's more than fast enough for what you are trying to do. At about 1ms (or less) per sentence, it is the fastest and smallest library out there. It does not use any RAM for buffering.

You basically feed it the characters when it's "a good time". In your case, you can feed it up to 10 characters and then go back to doing whatever you need to do. Whenever the end of a sentence is received, NeoGPS returns a COMPLETED code. However, almost all the parsing has already been completed by that time, so there is no big processing effort at the end of a sentence. The parse processing is actually distributed across all the characters, as they are received.

As SurferTim mentioned, reading 10 characters per loop may not be enough to keep up with the GPS stream. It depends on how much time the rest of you loop takes. You could also process a few characters in several places in your loop. A little here, a little there. I can say the NeoGPS wiil process the chars more quickly than all other libraries... if it can't keep up, nothing else will. :slight_smile:

I don't know if you've looked into coherency, but NeoGPS supports that fairly easily. It also implements the ublox binary protocol (UBX), but I'm not sure you really need that yet. I'd stick with the NMEA protocol first and see if it's fast enough. UBX will be harder to debug, although it is slightly faster.

NeoGPS is true C++ and has many configuration options. If you decide it's worth the effort, please don't hesitate to ask any questions.

Cheers,
/dev