Go Down

Topic: Storing very first input (Read 1 time) previous topic - next topic

mjaredwilson

Mar 06, 2010, 12:56 am Last Edit: Mar 06, 2010, 12:56 am by mjaredwilson Reason: 1
I was looking to take in latitude and longitude data and set the very first reading as the origin point on an led.  All other location readings would be displayed on the screen in respect to the first stored location.  

This is what I tried first:
Code: [Select]

int m = 0;

void loop(){
if(m=0){
  origin_lat = int_lat;
  origin_long = int_long;
  m++;
}
}


But the values of origin_lat and origin_long equal 0 and don't match int_lat or int_long.  Is there an easier way to go about this?

PaulS

Quote
But the values of origin_lat and origin_long equal 0 and don't match int_lat or int_long.


How do you know this? The code snippet you posted looks correct. The rest of the code must be where the problem lies. Care to post more (or, better yet, all) of it?

AlphaBeta


mjaredwilson

I changed the stupid double equals error, but i still have the same results.

[code]
#include <OLED320.h>
#include <string.h>
#include <ctype.h>
#include <print.h>

int rx1Pin = 19;                    // RX1 PIN
int tx1Pin = 18;                    // TX1 TX
int byteGPS=-1;
char linea[300] = "";
char arguments[13][11];
float flt_arguments[13];
char comandoGPR[7] = "$GPRMC";
int cont=0;
int bien=0;
int conta=0;
int indices[13];
float latitude, longitude, lat_rad, long_rad;
float origin_lat, origin_long, int_lat, int_long;
int m = 0;

OLED320 LED;

void setup() {
pinMode(rx1Pin, INPUT);
pinMode(tx1Pin, OUTPUT);
Serial1.begin(4800);
Serial2.begin(9600);
Serial.begin(19200);
  //delay(100);
for (int i=0;i<300;i++){       // Initialize a buffer for received data
 linea=' ';
}

Serial2.print(0x55,BYTE);
delay(1000);

LED.LED_Clear();
delay(100);

}

void loop() {
 gps();
}

void gps(){
 byteGPS=Serial1.read();         // Read a byte of the serial port
 if (byteGPS == -1) {           // See if the port is empty yet
    delay(100);
 } else {
    linea[conta]=byteGPS;        // If there is serial port data, it is put in the buffer
    conta++;                      
    //Serial.print(byteGPS, BYTE);
    if (byteGPS==13){            // If the received byte is = to 13, end of transmission
      cont=0;
      bien=0;
      for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
        if (linea==comandoGPR[i-1]){
          bien++;
        }
      }
      if(bien==6){               // If yes, continue and process the data        
          char* str = linea;              //direct linea char array to str pointer array
          char seperator = ',';
          int count = 0, index = 0, sIndex = 0;
          int theSize = 299;
          arguments[index][count] = '\0';  // clear first argument before starting
          flt_arguments[index] = '\0';
       
          while (theSize > sIndex + 1){
            if (*str != seperator){
              arguments[index][count] = *str;  //store array sections into argument arrays
            }
            else {
              arguments[index][count] = '\0';
            }
            *str++;
            count++;
            sIndex++;

            if (*str == seperator){
              *str++;                          // jump over the separator
              count = 0;
              index++;
              arguments[index][count] = '\0';  // clear argument before starting
            }
           
          }          
                           
         for(int i=1; i<10; i++){
           flt_arguments = atof (arguments);      //convert character in argument array into floating point
         }
         
         latitude = flt_arguments[3];      //assign latitude floating point array to a single floating point variable
         longitude = flt_arguments[5];     //assign longitude floating point array to a single floating point variable
         int_lat = latitude*10000;
         int_long = longitude*10000;
         
         Serial.print("INT LAT: ");
         Serial.println(int_lat);
         Serial.print("INT LONG: ");
         Serial.println(int_long);
         Serial.println("________");
         
         if(m==0){
           origin_lat = int_lat;
           origin_long = int_long;
           m++;
         }

         getpoint(origin_lat, origin_long, int_lat, int_long);
      }
      conta=0;                    // Reset the buffer
      for (int i=0;i<300;i++){    //  
        linea=' ';            
      }                
    }
  }
}

void getpoint(float origin_lati, float origin_longi, float current_lat, float current_long){
 int ya, yb;
 float tempx, tempy;
 tempx = (current_lat - origin_lati);      //set original coordiates at (0,0)
 tempy = (current_long - origin_longi);
 int x = (int)(tempx*10);
 int y = (int)tempy;
 
 if(y<256){
   ya = 0;
   yb = y;
 }
 else{
   ya = 1;
   yb = y-256;
 }
   
 Serial.print("origin_lat: ");
 Serial.println(origin_lati);
 Serial.print("origin_long: ");
 Serial.println(origin_longi);
 Serial.print("current_lat: ");
 Serial.println(current_lat);
 Serial.print("current_long: ");
 Serial.println(current_long);
 Serial.print("tempx: ");
 Serial.println(tempx);
 Serial.print("tempy: ");
 Serial.println(tempy);
 Serial.print("x: ");
 Serial.println(x);
 Serial.print("y: ");
 Serial.println(y);
 Serial.println("_________");
 
}

PaulS

There are some things that could be changed in this sketch:

Code: [Select]
flt_arguments[index] = '\0';

flt_arguments is an array of floats. Storing a NULL in a float does not make sense. Storing 0.0 does. The end result might be the same, but storing a NULL in a float looks weird.

Code: [Select]
   linea[conta]=byteGPS;        // If there is serial port data, it is put in the buffer
   conta++;                      


So, linea[0] thru linea[n] are set. Then,
Code: [Select]
     for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
       if (linea[i]==comandoGPR[i-1]){
         bien++;
       }
     }

linea[1] thru linea[6] are compared to comandoGPR[0] thru comandoGPR[5]. Why is linea[0] ignored?

Why are you storing each token in an array, as well as the token converted to a float? You never use the character array again.

Why are you not using strtok to tokenize the input string? It's optimized for just this sort of thing.

Code: [Select]
        int_lat = latitude*10000;
        int_long = longitude*10000;


Why are you multiplying latitude and longitude by 10000?

Code: [Select]
if(y<256){
  ya = 0;
  yb = y;
}
else{
  ya = 1;
  yb = y-256;
}


What's this code for? These values are not used.

What does your output look like?

AlphaBeta

@mjaredwilson: Please post code using the
  • button in the forum post editor  :)

mjaredwilson

I am working off of the GPS tutorial here: http://www.arduino.cc/playground/Tutorials/GPS

The latitude and Longitude values are given for example as 2907.3422 and 09607.3453 so I was attempting to convert these into integers.  The (int)latitude approach wasn't working correctly.

I know the values because I am printing them on the Serial Monitor.

And the if else statement storing values into ya and yb split the y value into two parts.  I am displaying a dot on a 4D OLED display and the coordinates of the dot have to be sent a byte at a time.



here is the complete code:
http://people.tamu.edu/~jwil04/dir/main_parallax.pde

mjaredwilson

#7
Mar 07, 2010, 12:03 am Last Edit: Mar 07, 2010, 12:07 am by mjaredwilson Reason: 1


Oh and i changed the if statement to:

Code: [Select]
if(m==0)

PaulS

I asked a number of questions. You danced around and gave partial answers to half the questions. I'll try again.

What is the purpose of saving each token in an array? You never use the array after you convert the value in the array to a float. Just convert the token to a float and store it in the float array.

Where are you checking that there is room in the character array for the character you are adding?

Where do you NULL terminate the character array entries?

Why are you not using strtok? The strtok function has been around for years. It's highly optimized, professionally written and thoroughly tested. It will make your job so much easier if you quit trying to re-invent the strtok function.

If you do nothing else, try printing m along with the other output. Maybe that will give you (and us) a clue.

mjaredwilson

Well, I am just working off of the example code I found and it has been working so I didn't try to change up the code and implement the strtok function.

I printed the value of m in the previous post.

I am not sure when to terminate the character array entries.

PaulS

I think that you are overwriting memory somewhere. Notice that m never changes. Since you have an m++ statement, it should. Since it doesn't, it means that it is being stepped on by something else. That something else is most likely happening in your string parsing code.

There is no reason to save the string twice. First you collect all the data in a string. Then, you parse it, and save all the tokens in an array. Then, you convert some of the tokens in that array to floats. There are all kinds of possibilities for where you could be overwriting memory.

All of them could be eliminated by using strtok to do the parsing. It returns a pointer to a token, managing allocation of space to hold that token. Then, all you need to do is convert that token to a float, and store the float in the float array.

If you persist in writing your own parser, fine. But, I think you need to understand what you are doing a lot more than you do.

You have no error checking. A token could be 15 characters long, and you happily stuff than into an array that is sized to hold 11 or 13, counting the terminating NULL, which you never add.

Then, you call atof. The atof function expects its input to be a string. You are supplying an array of characters.

There is a subtle difference between a string and an array of characters. The difference is that a string is an array of characters [glow]that is NULL terminated[/glow].

I'll keep harping on this because it is so important. You can not expect reasonable results if you supply bad input. Google "GIGO". You're providing the first part, and getting the second part.

Quote
I am not sure when to terminate the character array entries./quote]

Then, you should be using a function or library that does.

mjaredwilson

Ok so how about something along these lines...

Code: [Select]
void gps(){
 byteGPS=Serial1.read();         // Read a byte of the serial port
 if (byteGPS == -1) {           // See if the port is empty yet
    delay(100);
 } else {
    linea[conta]=byteGPS;        // If there is serial port data, it is put in the buffer
    conta++;                      
    //Serial.print(byteGPS, BYTE);
    if (byteGPS==13){            // If the received byte is = to 13, end of transmission
      cont=0;
      bien=0;
      for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
        if (linea[i]==comandoGPR[i-1]){
          bien++;
        }
      }
      if(bien==6){               // If yes, continue and process the data          
              char delims[] = ",";
              char* result1 = NULL;
              char* result2 = NULL;
              char* result3 = NULL;
             
              result1 = strtok(linea, delims);
              result2 = strtok(NULL, delims);
              result3 = strtok(NULL, delims);
}



giving:
result1 = "$GPRMC"
result2 = "123519"
result3 = "A"

for example.

$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

PaulS

So far, so good. If you know what the order of the tokens is, there's no reason to store pointers to them individually, if you never need the string representation of the value again.

For instance, result1 is a pointer that points to the string "$GPRMC". Do you care about result1 later? If not, do something like this:

Code: [Select]
char *token;
int tokNum;

token = strtok(linea, ",");
if(strcmp(token, "$GPRMC") == 0)
{
  // Good string. Tokenize the rest...
  tokNum = 0;
  token = strtok(NULL, ",");
  while(token)
  {
     tokNum++;

     // Decide whether to save or convert the token, or not
     switch(tokNum)
     {
         case 1: // token = "123519"
            // Maybe do something
            break;
         case 2: // token = "A"
            // maybe do something
            break;
         // More case statements
     }
     token = strtok(NULL, ",");
  }
}

mjaredwilson

Thanks Paul!  It works great now.  I used this code:

Code: [Select]

if(bien==6){               // If yes, continue and process the data        
         char *token;
         int tokNum;
         char delims[] = ",";
         char *time_char = NULL;
         char *fix_char = NULL;
         char *lat_char = NULL;
         char *latdir_char = NULL;
         char *long_char = NULL;
         char *longdir_char = NULL;
         char *date_char = NULL;

         token = strtok(linea, delims);
           tokNum = 0;
           while(token){
           // Decide whether to save or convert the token, or not
           switch(tokNum){
               case 1:                     // token = time
              time_char = token;
              break;
             case 2:                     // token = fix
              fix_char = token;
              break;
               case 3:                     // token = latitude
              lat_char = token;
              break;
               case 4:                     // token = latitude direction
              latdir_char = token;
              break;
               case 5:                     // token = longitude
              long_char = token;
              break;
               case 6:                     // token = longitude direction
              longdir_char = token;
              break;                
               case 9:                     // token = fix
              date_char = token;
              break;    
           }
           token = strtok(NULL, delims);
             tokNum++;
           }  
         time = atof(time_char);
         latitude = atof(lat_char);
         latitude = latitude/100;
         longitude = atof(long_char);
         longitude = longitude/100;
         date = atof(date_char);
}


I was also wondering the best way to truncate the latitude and longitude floats.  The values have 8 numbers such as 4807.0385 and I want to multiply by 1000 to give 4807038.5 and round the number to 4807039.

Using:
Code: [Select]

latitude = atof(lat_char);
longitude = atof(long_char);
latitude = latitude*1000;
longitude = longitude*1000;  
int_lat = (int)latitude;
int_long = (int)longitude;
         
         Serial.print("latitude: ");
         Serial.println(latitude);
         Serial.print("longitude: ");
         Serial.println(longitude);
         Serial.print("INT LAT: ");
         Serial.println(int_lat);
         Serial.print("INT LONG: ");
         Serial.println(int_long);


I see:

latitude: 3037100.25
longitude: 9620388.00
INT LAT: 22444
INT LONG: -13404

Thanks!

Go Up