GPS: GlobalSat EM-406A   (questions & issues)

I've been working on my EM-406A GPS module I have for my Decimilia. I went outside today to test its signal but I found that it was tracking my location correctly up to the millisecond.

For example, a few of my latitude readings would be something like this:

NORTH
3404.2256
3404.2260
3404.2263
3404.2265
3404.2266
3404.2268
3404.2270
...
3404.2311
3404.2311
3404.2310
3404.2311
3404.2308
3404.2305
...
3404.2244
3404.2244
3404.2245
2404.2245

Notice how the readings increase and decrease slightly at a rapid pace. The values tend to level out after I stay absolutely still for a few minutes. The same problems apply to the longitude. My question is why is this happening and how could I fix this so that I can get an accurate signal for use on a robotic rover?

I have included the code I used to test the GPS module. In the code I have a few items commented as questions about some small nuances in the code that I don't quite understand. (This code is kind of messy at the moment for testing purposes)

In the char2string() function, why must the interior while loop be organized like it is? I tried to simplify that loop but I ended up getting garbled characters. Does it have something to do with processing speed?

It didn't say in the module's data sheet, but apparently I have to transmit a constant HIGH to the module's RX in order to get a GPS reading back from it. Why is that? Do I have to do that "just cus I gotta"? Is there any interesting things I can send to the EM-406A specifically for it to do anything unique?

I also would like to better understand GPS bauds. I know they send data at 4800 baud, but I don't understand why I had to set the delays at 100 and 200 microseconds as seen in the beginning of the code.

//Created August 15 2006
//Heather Dewey-Hagborg
//http://www.arduino.cc
//reworked to GPS reader
/***********************************
Dirk, december 2006
/***********************************
Edited By:    Peter Chang
              UCLA Robotics
              
Last Modifed: April 25, 2008

Description:
  Recieves data bit-by-bit from GPS unit EM-406A while sending
 a constant HIGH signal to GPS unit's RX.
 
    -Simplified and modified for EM-406A & Decimilia
                  *TEST FILE*
*/



//#include <ctype.h>
//#include <string.h>

#define bit4800Delay 200 //1 bit per 0.2 ms
#define halfBit4800Delay 100 

byte rx = 6;    //Connect to EM-406A's TX
byte tx = 7;    //Connect to EM-406A's RX
//byte SWval;
//char dataformat[7] = "$GPRMC";    //RMC
char dataformat[7] = "$GPGGA";    //GGA
//char dataformat[7] = "$GPGSV";    //GSV
//char dataformat[7] = "$GPGSA";    //GSA
//char dataformat[7] = "$GPGLL";    //GLL
//char dataformat[7] = "$GPVTG";    //VTG
char messageline[80] = "";
int i= 0;     //Im guessing, declaring here saves time?
char latitude[10];
char longitude[11];

void setup() {
  pinMode(rx,INPUT);
  pinMode(tx,OUTPUT);
  digitalWrite(tx,HIGH);  //NEEDS TO BE CONSTANT HIGH TO RECIEVE DATA
  digitalWrite(13,HIGH); //turn on debugging LED
  //SWprint('h');  //debugging hello
  //SWprint('i');
  //SWprint(10); //carriage return
  Serial.begin(9600);  // this is used to echo what is read from the GPS out the USB->SerialDebugMonitor
}

/*
void SWprint(int data)
{
  byte mask;
  //startbit
  digitalWrite(tx,LOW);
  delayMicroseconds(bit4800Delay);
  for (mask = 0x01; mask>0; mask <<= 1) {
    if (data & mask){ // choose bit
      digitalWrite(tx,HIGH); // send 1
    }
    else{
      digitalWrite(tx,LOW); // send 0
    }
    delayMicroseconds(bit4800Delay);
  }
  //stop bit
  digitalWrite(tx, HIGH);
  delayMicroseconds(bit4800Delay);
}
*/


char SWread()
{
  byte val = 0;
  //Wait for start bit (0)
  while(digitalRead(rx) == HIGH); 
  
  if (digitalRead(rx) == LOW) //Must find seccond low bit?
  {
    delayMicroseconds(halfBit4800Delay);
    
    //Read Character
    for (int offset = 0; offset < 8; offset++) 
    {
      delayMicroseconds(bit4800Delay);
      val |= digitalRead(rx) << offset;
        //Eg: 1, 0, 1, 1, 0, 0 = 001101 (Notice reverse ordering)
    }
    
    //wait for stop bit + extra
      //Why 2 delays? 
    delayMicroseconds(bit4800Delay); 
    //delayMicroseconds(bit4800Delay);
    
    if( val > 128 )  //Why do some values have such large ascii values?
      return val-128;
    else
      return val; 
  }
}

void char2string()
{
  i = 0;
  messageline[0] = SWread();
  if (messageline[0] == '

) //string starts with $
 {
   i++;
   messageline[i] = SWread();
   while(messageline[i] != 13 & i<80) //carriage return (13) or max size
   {
     i++;
     messageline[i] = SWread();
   }
   //Why must I initialize and implement this while loop exactly like this to get readable data
   
   messageline[i+1] = '\0'; //make end to string
 }
}

void loop()
{
    char2string();
    if (strncmp(messageline, dataformat, 6) == 0 & i>4)  //see top of code for "dataformat"
    {
      Serial.println(messageline);
     
      /Lat/Lon  RMA**
      messageline[29] = '\0';
      messageline[42] = '\0';
      strcpy(latitude, messageline+20);
      strcpy(longitude, messageline+32);
      Serial.println("NORTH      WEST");
      Serial.print(latitude);
      Serial.print("  ");
      Serial.println(longitude);
      ******************************/
    }
 
 //
 // way to print ALL RECEIVED MESSAGES!
 //
 
 //Serial.print(SWread(),BYTE); //use this to get all GPS output, comment out from char2string till here
 
}

GPS has error in the measurement. This drift is the nature of the noise. In typical autonomous vehicle applications GPS is used along with other sensors, like accelerometers and gyros, that are more precise over the short term.

As for holding the TX pin high in order to receive, ask the chip designer. (: TX to the GPS is good for changing which sentences get transmitted, how often they get transmitted, uploading new firmware, uploading waypoints (if it has a display), etc.

You've got what's known in Arduino circles as a "software serial" implementation, aka bit-banged serial. The timing is based on the baud rate requirements. For your GPS NMEA standard requires 4800 baud. "Baud" is transitions per second, so for 4800 transitions per second, each bit time takes 1/4800 of a second, or about 208mS. In order to stay away from the edges of a transition and possibly miss something if your timing is off, what is typically done in bit-banged implementations is to look for the edge of the first bit (RS232 has a start bit, which is quite helpful in this clock recovery process), wait half a bit time (that's 104mS) so that we're looking for the signal in the middle of that bit, then read bits, sleeping the bit time between reads.

hope this helps.

-j

Thanks for explaining bauds, that makes much more sense. I can see why the function for char2string() can throw the data off if the processing speed for each line of code is too long or too short.

As for accelerometers and GPS, I attended an Air Force seminar that said that system was something like EGI (embeded GPS Inertial). Ill try posting it up if I find some more information. But in the meantime if anyone knows a few things about EGI, how could I get an accurate initial reading? In particular since the GPS initially sends data the fluctuates quite a bit, how can I know where my actual position is exactly? I'm guessing I could just take the average of the max and min of the shifting data so I can roughly pinpoint my initial position quickly.

Hmm. Take a look at this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1199022761/0

Your "exact" position depends on how you define "exact". :expressionless:

You can average without moving and get a bit closer, but the simple fact is that standard commercial GPS has accuracy on the order of 10m (ten meters, not a typo). Some units seem to do better than others (more satellites is better), but there are inherent limitations. DGPS (differential GPS) gives corrections and gets better accuracy (IIRC, on the order of a couple of feet) through use of a rather pricey base station. WAAS (wide area augmentation system) is similar to DGPS (wider coverage, you get a free ride, but less accuracy than DGPS) and also improves accuracy. Military grade GPS uses some restricted stuff and sets you back US$20k if you can get it, but gets ridiculous accuracy.

For a short mission, it's possible that the error from GPS will be relatively constant in magnitude and direction, so you can pretend it's correct after some initial zeroing.

I really have no idea how the autonomous vehicle stuff is done, maybe google some of their stuff. There are folks beginning to play with home built AAV systems.

-j

Nothing that requires centimeter resolution / accuracy relies on GPS. There are just too many factors that stop it from giving this type of accuracy - signal strangth, atmospheric interferance, and by far the biggest problem (in my experience), multipathing.

For automomous use, anything that requires a higher level of accuracy will use GPS to get as close a possible, then use another guidance system to finish, for example lasers guiding missiles, Air Traffic Control transmitters guiding UAVs etc.