Pages: [1] 2 3 4   Go Down
Author Topic: GPS parsing problem  (Read 3632 times)
0 Members and 1 Guest are viewing this topic.
Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

G'day all,

I'm sure I don't need to tell you I'm a "Newb" because I'm here asking a question!

I've been trying to parse GPS data from a 3G phone module but only when called.  The output from the module is formatted as GPSACP and not the generic GPRMC sentence as would be the case with dedicated free running GPS.  I have no trouble getting the data from the module as required but without re-inventing the wheel and writing the parsing code myself I can't figure out how to use for example Tiny GPS to simplify the task.  Is there a way to get this Library to recognise the GPSACP: sentence from the 3G module?  The code below is based on the work of others so I'm confident that with a valid GPRMC sentence output it would work fine.

Any assitance would be greatly appreciated.

Cheers
Greg.

// In order for this sketch to work, you will need to download
//TinyGPS libraries from arduiniana.org and put them
// into the hardware->libraries folder in your ardiuno directory.
// Here are the lines of code that point to those libraries.

#include <TinyGPS.h>

TinyGPS gps;

//void getgps(TinyGPS &gps);


void setup()
{
  // This is the serial rate for your terminal program. It must be this
  // fast because we need to print everything before a new sentence
  // comes in. If you slow it down, the messages might not be valid and
  // you will likely get checksum errors.
  Serial.begin(115200);

  
  Serial.println("");
  Serial.println("GPS Test Example Sketch");
  Serial.println("");
  Serial.println("ATE0"); //turn echo off
  delay(5000); //wait for 3G module
  Serial.println("AT$GPSP=1");
  delay(5000); //wait for 3G module
}

// This is the main loop of the code. All it does is check for data on
// the RX pin of the ardiuno, makes sure the data is valid NMEA sentences,
// then jumps to the getgps() function.
void loop()
{
  Serial.println ("AT$GPSACP");  // Call for GPS data
  while(Serial.available())     // While there is data on the RX pin...
  {
      int c = Serial.read();    // load the data into a variable...
      if(gps.encode(c))      // if there is a new valid sentence...
      {
        getgps(gps);         // then grab the data.
      }
  }
  
  delay(10000); //delay before next loop
}

// The getgps function will get and print the values we want.

void getgps(TinyGPS &gps)

{
  // To get all of the data into varialbes that you can use in your code,
  // all you need to do is define variables and query the object for the
  // data. To see the complete list of functions see keywords.txt file in
  // the TinyGPS and NewSoftSerial libs.
  
  // Define the variables that will be used
  float latitude, longitude;
  // Then call this function
  gps.f_get_position(&latitude, &longitude);
  // You can now print variables latitude and longitude
  Serial.print("Lat/Long: ");
  Serial.print(latitude,5);
  Serial.print(", ");
  Serial.println(longitude,5);
  
  // Same goes for date and time
  /*int year;
  byte month, day, hour, minute, second, hundredths;
  gps.crack_datetime(&year,&month,&day,&hour,&minute,&second,&hundredths);
  // Print data and time
  Serial.print("Date: "); Serial.print(month, DEC); Serial.print("/");
  Serial.print(day, DEC); Serial.print("/"); Serial.print(year);
  Serial.print("  Time: "); Serial.print(hour, DEC); Serial.print(":");
  Serial.print(minute, DEC); Serial.print(":"); Serial.print(second, DEC);
  Serial.print("."); Serial.println(hundredths, DEC);
  //Since month, day, hour, minute, second, and hundr
  */
  // Here you can print the altitude and course values directly since
  // there is only one value for the function
  //Serial.print("Altitude (meters): "); Serial.println(gps.f_altitude());  
  // Same goes for course
  Serial.print("Course (degrees): "); Serial.println(gps.f_course());
  // And same goes for speed
  Serial.print("Speed(knots): "); Serial.println(gps.f_speed_knots());
  Serial.println();
  
  // Here you can print statistics on the sentences.
  //unsigned long chars;
  //unsigned short sentences, failed_checksum;
  //gps.stats(&chars, &sentences, &failed_checksum);
  //Serial.print("Failed Checksums: ");Serial.print(failed_checksum);
  //Serial.println(); Serial.println();
}
Logged

0
Offline Offline
Tesla Member
***
Karma: 143
Posts: 9600
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do you have a sample string sent from the device?
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have no trouble getting the data from the module as required but without re-inventing the wheel and writing the parsing code myself I can't figure out how to use for example Tiny GPS to simplify the task.
You can't. TinyGPS doesn't know about GPSACP mode.

Quote
Is there a way to get this Library to recognise the GPSACP: sentence
Yes. You can add code to TinyGPS to make it parse GPSACP sentences, IF you know what all the values mean.
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3019
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If it is a text string in the same manner as the other NMEA GPS sentences,   then there isn't much
difficulty in adding it as a type of sentence to be processed by the parser.

You basically count the commas,  and identify what is between each pair of commas as an integer or
floating point number or character code or whatever it is.

On the other hand, it might be something completely different.    I don't know.
Logged

Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Gents,

Below is the response from the GPS Module.  The string contents are as follows:-

UTC Time , Latitude, Longitude, HDOP, Altitude, Fix, COG, Speed(Km), Speed (Knots), Date, NSAT

I'm interested to know if the changes to Tiny GPS would need to be made in the .h file, or the .cpp file... Or both? (Never edited a library before)...  Also, I would expect that simply adding the string definition to those that already exist in the Library would be the best option.

Again, any help greatly appreciated.

Cheers
Greg.

$GPSACP:012647.000,2728.3033S,15302.3369E,1.50,-52.0,3,156.66,0.00,0.00,240113,04                                                                       
 
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm interested to know if the changes to Tiny GPS would need to be made in the .h file, or the .cpp file... Or both?
The source (cpp) file.

Look at the source code. It should be fairly simple (and obvious) how to parse a different kind of record.
Logged

0
Offline Offline
Tesla Member
***
Karma: 143
Posts: 9600
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In what form do you want the data and what do you plan to do with it? As a simple parsing start, load the below code into the arduino, copy the sample string you posted, paste the string in the serial monitor (ctrl-v), then send it to the arduino.



Code:
//zoomkat 3-5-12 simple delimited ',' string parce
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,
 
  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      //do stuff
      Serial.println(readString); //prints string to serial port out
      readString=""; //clears variable for new input     
     } 
    else {     
      readString += c; //makes the string readString
    }
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Offline Offline
Edison Member
*
Karma: 48
Posts: 1631
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This PDF describes the format of the GPSACP sentence:
http://www.gatetel.com/PDF/GPSgprs/GPRS_Protocol_description.pdf

Pete
Logged

Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

Sorry for the delay in getting back to this... after studying all your input I've been trying different solutions and have come up with one that seems quite elegant at first glance...  Trouble is once incorporated into my complete code it doesn't work.  Everything appears fine but in the "real world" situation the variables areeither not being populated, or the results are not being printed to the serial bus.  For bothe the simulator and serial monitor run I manually enter the GPS response ($GPSACP: 234423.31,2728.3913S,15302.3418E,1.00,38.81,3,0,00,0.01,0.02,180313,07) into the serial monitor input and the correctly formatted output appears on the output.


The Parsing/printing code which works both on an arduino using the serial monitor, and in the simulator is here.

  
Code:
#include <avr/pgmspace.h>
  #define maxLength 80                                 // Set incoming string max length

  
 
  String readString;
  String Lat;
  String Lon;
  String COG;
  String Speed;
  int ComCount = 0;
  
void setup() {
  
  Serial.begin(9600);
  delay (5000);
  Serial.println("GPS Test");
  Serial.println ("AT$GPSACP");
  delay(1000);
}

void loop()  {

  
  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c ==':')  {
      readString="";
    }
    
    //delay(1000);
    
    if (c == ',') {
      ComCount++;

      if (ComCount == 1)  {
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 2)  {
        Lat = readString;
        
        readString=""; //clears variable for new input
      }
    
    //delay(1000);
    
      

      if (ComCount == 3)  {
        Lon = readString;
        
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 4)  {
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 5)  {
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 6)  {
        /*if (c += '1')  {
         Fix = 0;
         }
         else Fix = 1;
         */      
        
      readString=""; //clears variable for new input
      }
    
    //delay(1000);
    
    

      if (ComCount == 7)  {
       COG = readString;
        
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 8)  {
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 9)  {
        Speed = readString;
        
        readString=""; //clears variable for new input      
      }
    
    //delay(1000);
    
    

      if (ComCount == 10)  {
        readString=""; //clears variable for new input
       Serial.println ("Lat " + Lat);
   Serial.println ("Lon " + Lon);
   Serial.println ("Speed " + Speed + " Knots");
   Serial.println ("COG " + COG);
        ComCount = 0;    
      }
    
  
  

    
    
    }
    else {    
      readString += c; //makes the string readString
    }  
  }

}
-----------------------------------------------------------------------------------------------------------
The subroutines I'm actually calling are here... (first section calls the GPS subroutine then should print the data stored in the appropriate variables???)

 
Code:
if (inString.indexOf("Locate") >=0) {                        // look for a command in the string      

      inString = "";                                         // Clear the string
      GPS();

      Serial.println ("AT+CMGS=0430340511");             //Send SMS to this number
  
      showString(PSTR("Current Location, Course, & Speed\r\n"));
      Serial.println("");
      Serial.println ("Lat " + Lat);
      Serial.println ("Lon " + Lon);
      Serial.println ("COG " + COG);
      Serial.println ("Speed " + Speed + " Knots");
      Serial.println ("\x1A");                           //Delay to accomodate message send.
      delay(2000);                                       //Delay to accomodate message send.

      inString = "";                                               // Clear the string

    }
------------------------------------------------------------------------------------------------

Code:
void GPS()  {

  delay(1000);
  Serial.println ("AT$GPSACP");
  delay(2000);
  
  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c ==':')  {
      readString="";
      ComCount = 0;
    }
    if (c == ',') {
      ComCount++;

      if (ComCount == 1)  {
        readString=""; //clears variable for new input      
      }

      if (ComCount == 2)  {
        Lat = readString;
        readString=""; //clears variable for new input
      }  

      if (ComCount == 3)  {
        Lon = readString;
        readString=""; //clears variable for new input      
      }

      if (ComCount == 4)  {
        readString=""; //clears variable for new input      
      }

      if (ComCount == 5)  {
        readString=""; //clears variable for new input      
      }

      if (ComCount == 6)  {      
        readString=""; //clears variable for new input
      }

      if (ComCount == 7)  {
        COG = readString;
        readString=""; //clears variable for new input      
      }

      if (ComCount == 8)  {
        readString=""; //clears variable for new input      
      }

      if (ComCount == 9)  {
        Speed = readString;
        readString=""; //clears variable for new input      
      }

      if (ComCount == 10)  {
        readString=""; //clears variable for new input
        ComCount = 0;    
      }
    }
    else {    
      readString += c; //makes the string readString
      
      delay(1000);
    }  
  }
}
----------------------------------------------------------------------

The delays are simply for stability.  The GPS/3G module responses are fairly quick but I want reliability over absolute speed.

It seems to me that from my testing with the first block of code I've included that perhaps the issue is with the response from the GPS not actually being available on the serial bus???  Other comands that come in via text message are recognised, and in fact the entire sequence is called in this manner.  I can also confirm that watching the serial data output from both the arduino and the GPS/3G module the correct calls and responses are present.

Cheers
Greg.
« Last Edit: March 18, 2013, 07:58:37 pm by gregcan » Logged

0
Offline Offline
Tesla Member
***
Karma: 143
Posts: 9600
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

#7 below might help alot.

http://arduino.cc/forum/index.php/topic,148850.0.html
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the tip... modified post as suggested.

Cheers
Greg
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There is the TinyGPS library that handles parsing GPS data without using crutches (otherwise known as the String class). Why not use it?

Or, at least refer to it to see how parsing is done.
Logged

Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks PaulS,

This was discussed at the beginning of the topic. TinyGPS doesn't recognise or handle GPSACP strings natively and I figured it was just as easy (and far more educational) to attack the problem head on.

Cheers
Greg.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I figured it was just as easy (and far more educational) to attack the problem head on.
But, at least the TinyGPS library provides a skeleton. Why not add the ability to parse GPSACP sentences to that library?

All those Strings coming and going are trashing the limited memory that you have.
Logged

Brisbane Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks PaulS,

So you think the issue could be related to memory?... OK, I'll relook at TinyGPS and see if I can figure out how to add a sentence type to it...

Cheers
Greg
Logged

Pages: [1] 2 3 4   Go Up
Jump to: