GPS Serial interface Problem ÿÿÿÿÿÿÿÿÿÿ

Hi there,

We are currently developing a high altitude ballon to take pictures of the Earths curvature for schools. The Arduino is cenral computer to control everything.

As part of the tracking component a GPS signal is pulled in evry so often and then sent to a ground station. This only happens whe the function is called to save energy as weight is imperative.

The problem is we keep getting the following …

$GPGSA,A,3,09,12,14,27,29,30,31,2.1,1.4,1.732
$GPRMC,193653.000,A,5337.7851,N,00021.7199,W,0.0,000.0,140510,A
7A
$GP0,A76
$GPGSV,3,1,12,31,33,302,45,12,57,078,52,29,40,193,50,30,84,282,51
71
$GPGSV,3,2,12,01,00,000,38,02,27,087,34,14,40,242,44,27,08,137,33*73
$GPGSV,3,3,12,09,12,136,30,04,17,040,31,32,06,316,20,03,341,*77
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$GPGGA,193703.000,5337.7838,N,00021.7191,W,1,09,0.9,97.98,M,*16

Longitude : 5337.7838,N
Latitude : 00021.7191,W
Altitude : 97.98

The ÿÿ is not aproblem in this case but sometimes it gets in the NMEA sentence like …

$GPGGA,193713.000,5337.7776,N,00021.7196,W,1,09,0.9,ÿ96.23,M,*14

Longitude : 5337.7776,N
Latitude : 00021.7196,W
Altitude : ÿ96.23


Altitude is now a false figure, this could have unexpected results at 60,000 ft up as you can imgaine.

Any idea what is going on here? what are these characters, can I get rid of them or should we just checksum the sentence and dump the odd faulty one?

Thank you for looking

#include <AikoEvents.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#define MIN_HEIGHT 1000

using namespace Aiko;
struct      gpsdata {
  int            altitudeInt;
  int            longitudeInt;
  int            latitudeInt;
  int           sectorNUM; 
  char      altitude[14];
  char      longitude[14];
  char      latitude[14];

};

int ledPin = 13;                  // LED test pin
int rxPin = 0;                    // RX PIN 
int txPin = 1;                    // TX TX
int shutterPin = 6;               // Shutter release
int runGPS = 0;                   // Defines if GPS Coords are to be pulled in
int intialALT = 0;
int RunOnce = 0;
int x;
int sector = 10;

void setup() {
  
  Events.addHandler(SectorDetermine, 5000);
  Events.addHandler(GetGPSCoords, sector * 1000);
  Events.addHandler(takePhoto, 5000);
  
  pinMode(ledPin, OUTPUT);       // Initialize LED pin
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  Serial.begin(9600);

}   

static void GetGPSCoords();
static void SectorDetermine();

gpsdata data;
void loop(){
  digitalWrite(ledPin, LOW);
 // sector = (data.sectorNUM);
 // SectorDetermine();
  Events.loop();
}

static void GetGPSCoords(){

  int i;
  int fieldLength = 12;
  int byteGPS=0;
  char linea[300] ="";
  char lineb[14] ="";
  char comandoGPR[7] = "$GPGGA";
  char comandoGPR2[7] = "$GPGSV";
  char *ptr;
  int cont=0;
  int conta=0;
  int contb=0;
  int bien=1;
  int indices[14];
  int idxStartLong= 18;
  int idxStartLat = 30;
  int idxStartAlt = 41;
  char delims[] = ",";
  char *result = NULL;

//  Serial.println("Loop Starting...");
  digitalWrite(ledPin, HIGH);
  byteGPS=Serial.read();
  if (byteGPS == -1) {
    delay(100); 
  } 
  else {                          // Read Byte Loop
 do {
  //Serial.flush();
  memset(linea,0,300);
  while (byteGPS != 36) { 
        byteGPS=Serial.read();
        Serial.print(byteGPS,BYTE);
    }
      while (byteGPS!=13) {
        linea[conta]=byteGPS;
        conta++;
        byteGPS=Serial.read();
       Serial.print(byteGPS, BYTE);
    }
     conta = 0;
 }
while (strncmp (linea, comandoGPR, 6) != 0);
 
     if (byteGPS==13){            // If the received byte is = to 13, end of transmission
    // Serial.println("...T E..");
     digitalWrite(ledPin, LOW); 
       if ( strncmp(linea, comandoGPR, 6) == 0 ) 
                {
                        strncpy(data.longitude,&linea[idxStartLong],(fieldLength-1));
                        strncpy(data.latitude,&linea[idxStartLat],fieldLength);

                        data.longitudeInt = atoi(data.longitude);
                        data.latitudeInt = atoi(data.latitude);

                        result = strtok( &linea[idxStartAlt], delims );

                        while( result != NULL ) {

                                if ( contb == 4 )
                                {
                                        strncpy(data.altitude,result,fieldLength);
                                        data.altitudeInt = atoi(data.altitude);
                                }
                                contb++;
                                result = strtok( NULL, delims );
                        }
                }
        Serial.println("");      // ... and write to the serial port
         Serial.println("");
         Serial.println("---------------");
         Serial.print("Longitude : ");
         Serial.println(data.longitude);
         Serial.print("Latitude : ");
         Serial.println(data.latitude);
         Serial.print("Altitude : ");
         Serial.println(data.altitude);
         Serial.println("");
         }
         Serial.println("---------------");
         //result = strtok( &linea[idxStartAlt], delims );
         //strncpy(data.altitude,result,fieldLength);
         data.altitudeInt = atoi(data.altitude);
         memset(linea,0,300);    
       }   
//    Serial.println("Loop Ending....");     
}
  
static void SectorDetermine(){
//   Serial.print("Sector: " );
//   Serial.print(data.sectorNUM);
//   Serial.print("ALT: " );
//   Serial.println(data.altitudeInt);
  if ((data.altitudeInt) <= 300){
    (data.sectorNUM) = 20;
//    Serial.print("Sector :");
//    Serial.println(data.sectorNUM);
  }
    if (data.altitudeInt >= 300 && data.altitudeInt <= 1500){
      (data.sectorNUM) = 30;
//      Serial.println(data.sectorNUM);
    }
  data.sectorNUM = sector;
//  Serial.println(sector);
}

void takePhoto(){
  digitalWrite(shutterPin, HIGH);
  delay(500);
  digitalWrite(shutterPin, LOW);
}
while (byteGPS != 36) {
        byteGPS=Serial.read();

How do you know that there are characters available to read? What is the hex value of the weird characters?

[edit]And before you shoot yourself in the derriere, just toggling the internal pull-up may not trigger your shutter reliably.[/edit]

ÿ = ff in hex. Perhaps it’s just a loose connection - like it’s not being pulled low when it should be so it’s just seeing the pulled up state.

ÿ = ff in hex

== -1 in decimal. Nothing to do with loose connections. http://arduino.cc/en/Serial/Read

Perhaps you could share your insight about what is causing the -1?

The clue being hinted at is Serial.available(). You are "reading" when there is nothing to read; you should use Serial.available() to test if there's something to read before calling Serial.read(). Note how the garbage mostly occurs between "bursts" of NMEA sentences, which occur once a second (by default).

Once you get that one figured out, do a bit of googling for "NMEA checksum". You can (and should) make sure that NMEA sentence is valid before you use it.

There's also a nifty arduino library called TinyGPS that may be useful.

-j

Perhaps you could share your insight about what is causing the -1?

I already did.

Hi Guys,

Thank you for the input, would you add Serial.available like this? I have only been using the Arduino and C for the last four weeks so its a learning curve. :-)

do { //Serial.flush(); memset(linea,0,300); while (byteGPS != 36) { if (Serial.available()){ byteGPS=Serial.read(); Serial.print(byteGPS,BYTE); } } while (byteGPS!=13) { linea[conta]=byteGPS; conta++; if (Serial.available()){ byteGPS=Serial.read(); Serial.print(byteGPS, BYTE); } } conta = 0; } while (strncmp (linea, comandoGPR, 6) != 0);

The whole do/while loop belongs inside the if(Serial.available() > 0) loop, not the other way around.

The whole do/while loop belongs inside the if(Serial.available() > 0) loop,

no it doesn't - look at the memset().

At a glance, your code looks OK to me.

-j

Let me repeat: you should look at TinyGPS. It parses sentences, checks checksums, etc. You appear to be reinventing the wheel.

Also, a stylistic thing: I had to go look at an ASCII chart to see what while (byteGPS != 36) was testing for. If you had written while (byteGPS != ' it would be exactly equivalent, but infinitely clearer to those of us who don't have the entire ASCII table memorized.

-j )` it would be exactly equivalent, but infinitely clearer to those of us who don't have the entire ASCII table memorized.

-j

no it doesn't - look at the memset().

OK. So why is memset() called inside this loop:

do
{
}
while(strncmp (linea, comandoGPR, 6) != 0);

In my opinion, memset should be called before this loop. Not that memset is the proper function to be using. Proper character array handling does not require that every element in the array contains a NULL.

completely ignoring the memset(), he's using the code to a) gather a complete NMEA sentence, then b) skip it and get another if it's not a GGA. The big loop is OK.

-j

Hi Guys

Thank you for the tips, for everyone else this is what I have found.

When I use TinyGPS (which is great) it itself gets malformed NMEA sentences, so I think the code is OK but needs a checksum adding in.

I think TinyGPS suffers the same way but just dumps any false data thats alll.

Thats is good to know though, so if you pull in NMEA expect some malformed sentences. Hence why they have checksums!

cheers :)