Sending geographical coordinates from PC to Arduino

Hello,

I just ordered a GPS modem and some other stuff for basic navigation, and I am planning to build a basic waypoint-navigating rover.

I am trying to figure out how to send coordinates of the waypoints to the Arduino over a serial connection. I am planning to use XBee for the serial connection, but for now I am working on this over USB.

What I am trying to achieve:
1) Send geographical coordinates to Arduino over serial (for example: 605522.93N263618.87E)
2) Store the sent coordinates into variables
3) Make calculations using these variables

This is where I am so far:

char buff[] = "000000000"; // Buffer array
char lat[] = "000000000"; // Array to store the latitude into
char lon[] = "000000000"; // Array to store the longitude into

// Setup
void setup() {
  Serial.begin(9600); // Begin the serial communication 
}

// Loop
void loop() {
  // Loop this as long as there is something
  // unread in the serial buffer
  while (Serial.available() > 0) {
    for (int i=0; i<9; i++) { // Move all entries down one in the buffer array
      buff[i]=buff[i+1];
    }
    buff[9]=Serial.read(); // Read the oldest data in the serial buffer into the buffer array
    if (buff[9]=='N') { // If the data is char N it means the buffer array now contains the latitude
      for (int a=0; a<9; a++) { // Insert the latitude data from the buffer array into the latitude array
        lat[a] = buff[a];
      }
    }
    if (buff[9]=='E') { // If the data is char E it means the buffer array now contains the longitude
      for (int a=0; a<9; a++) { // Insert the longitude data from the buffer array into the longitude array
        lon[a] = buff[a];
      }
    }
    if (buff[9]=='S') { // If the data is char S the code should print out both lat and lon arrays for debugging
      Serial.print("N: ");
      Serial.print(lat);
      Serial.print(" E: ");
      Serial.println(lon);
    }
  }
}

This code works just like it should: by running it and sending the line “605522.93N263618.87E” with the serial monitor the coordinates are stored into the lat and lon arrays. Sending “S” prints the coordinates stored into the arrays.

However, I can’t do any calculations with these values as they are chars (right?). I also can’t compare these coordinates to the ones sent by the GPS chip as they are stored into float variables. This is what I am trying to figure out.

Also, if anyone has a better idea how to send/read the coordinates feel free to contribute!

You need to parse the ascii string containing the lat / long value to convert the string into numbers.

Do it in two parts: split the string into tokens that contain only the decimal digits for a given number; Parse that sequence of digits to convert them into a number.

There are lots of different ways to do it, but you could use the AVR library functions in strings.h to tokenise the string and then atof() to convert to a float.

However, I can't do any calculations with these values as they are chars (right?).

Yes, they are char arrays. You can pass them to atof(), though, to convert them to floats, once you fix some problems.

char buff[] = "000000000"; // Buffer array

9 initializers, so buff[0] to buff[8] are the elements.

    buff[9]=Serial.read(); // Read the oldest data in the serial buffer into the buffer array
    if (buff[9]=='N') { // If the data is char N it means the buffer array now contains the latitude

Oops. buff[9] doesn't exist.

You need to make the array large enough to hold the trailing NULL, too, and actually NULL terminate the array.

Thanks for the informative answers PeterH and PaulS!

PaulS:

However, I can’t do any calculations with these values as they are chars (right?).

Yes, they are char arrays. You can pass them to atof(), though, to convert them to floats, once you fix some problems.

char buff[] = "000000000"; // Buffer array

9 initializers, so buff[0] to buff[8] are the elements.

    buff[9]=Serial.read(); // Read the oldest data in the serial buffer into the buffer array

if (buff[9]==‘N’) { // If the data is char N it means the buffer array now contains the latitude



Oops. buff[9] doesn't exist.

You need to make the array large enough to hold the trailing NULL, too, and actually NULL terminate the array.

I have never really done any serious C or C++ programming, I am more of a Python guy… But I think I fixed the problems You were pointing out and I actually got the program working! It now functions as it should, storing the user inputted coordinates into float variables which can be used for calculations.

Here is the working code, please point out if it still has some errors:

char buff[] = "0000000000"; // Buffer array
char lat[] = "0000000000"; // Array to store the latitude into
char lon[] = "0000000000"; // Array to store the longitude into
float latCalc; // Float variables for the coordinate calculations
float lonCalc;

// Setup
void setup() {
  Serial.begin(9600); // Begin the serial communication 
}

// Loop
void loop() {
  // Loop this as long as there is something
  // unread in the serial buffer
  while (Serial.available() > 0) {
    for (int i=0; i<9; i++) { // Move all entries down one in the buffer array
      buff[i]=buff[i+1];
    }
    buff[9]=Serial.read(); // Read the oldest data in the serial buffer into the buffer array
    if (buff[9]=='N') { // If the data is char N it means the buffer array now contains the latitude
      for (int a=0; a<9; a++) { // Insert the latitude data from the buffer array into the latitude array
        lat[a] = buff[a];
      }
      lat[9] = '\0'; // NULL terminate the array
    }
    if (buff[9]=='E') { // If the data is char E it means the buffer array now contains the longitude
      for (int a=0; a<9; a++) { // Insert the longitude data from the buffer array into the longitude array
        lon[a] = buff[a];
      }
      lon[9] = '\0'; // NULL terminate the array
    }
    if (buff[9]=='S') { // If the data is char S we print the current values for some debugging    
      Serial.print("P: ");
      Serial.print(lat);
      Serial.print(" I: ");
      Serial.println(lon);
      Serial.print(latCalc);
      Serial.print(", ");
      Serial.println(lonCalc);
    }
    latCalc = atof(lat); // Convert the array containing the latitude into a float variable for calculations
    lonCalc = atof(lon); // Convert the array containing the longitude into a float variable for calculations
  }
}

Many thanks!

I don’t like this:

char buff[] = "0000000000"; // Buffer array
char lat[] = "0000000000"; // Array to store the latitude into
char lon[] = "0000000000"; // Array to store the longitude into

Much better, in my opinion, is to explicitly size the arrays, and let the compiler do the initialization

char buff[10]; // Buffer array
float lat;
float lon;

You are shuffling arrays around a lot. Much better to fill the array from left to right, instead of from right to left.

Add another global variable, index, initialized to 0. When N or E or S arrives (hope you never move), reset index to 0.

while(Serial.available() > 0)
{
   char aChar = Serial.read();
   if(aChar >= '0' && aChar <= '9' || aChar == '.') // Only store numbers and decimal points
   {
      buff[index++] = aChar;
      buff[index] = '\0'; // NULL terminator
   }
   else
   {
      // Got a letter
      if(aChar) == 'N')
      {
         lat = atof(buff);
      }
      else if(aChar == 'E')
      {
         lon = atof(buff);
      }
      else
      {
         // print stuff
      }

      index = 0;
   }
}

With this code, the serial data does not have to arrive all at once. It can arrive in bits and pieces. The values of lat and lon will not be computed until the whole value has arrived, and will not be printed until both values arrive.

@PaulS:

I got rid of the extra arrays and made the changes you suggested! It works just as expected, and I am ready to expand it for storing multiple waypoints.

PaulS: When N or E or S arrives (hope you never move), reset index to 0.

I know this is bad code since I assume the coordinates will always be northern & eastern hemisphere. I will fix this once I get the GPS module and run some tests with it.

Thanks, this problem is now solved!