Go Down

Topic: 10Hz GPS data with TinyGPSPlus library (Read 2214 times) previous topic - next topic

mudassir9999

Feb 17, 2017, 04:47 pm Last Edit: Feb 17, 2017, 04:48 pm by mudassir9999
Hello everybody,
I am working on a home made project which will log GPS data into a SD card, I am able to log data with 1Hz which is default by TinyGPSPlus and also with the Quectel L80 module, I sent Baudrate(115200) and update rate (10Hz) of Quectel L80 receiver! and logged data.

The data shows each second in the time second consists of 10 data like below :


Quote
Date              Time             Latitude         Longitude

17:2:2017       9:05:01         17.355995      78.441528
17:2:2017       9:05:01         17.355995      78.441528
17:2:2017       9:05:01         17.355994      78.441535
17:2:2017       9:05:01         17.355999      78.441522
17:2:2017       9:05:01         17.355985      78.441562
17:2:2017       9:05:01         17.355994      78.441523
17:2:2017       9:05:01         17.355999      78.441511
17:2:2017       9:05:01         17.355990      78.441510
17:2:2017       9:05:01         17.355995      78.441528
17:2:2017       9:05:01         17.355996      78.441512
as can be seen, 9:05:01 only one second have 10 coordinates...


Is there any way so that i can get in this way!

Quote
Date              Time                    Latitude        Longitude

17:2:2017       9:05:01:000         17.355996      78.441512
17:2:2017       9:05:01:100         17.355995      78.441528
17:2:2017       9:05:01:200         17.355995      78.441528
17:2:2017       9:05:01:300         17.355994      78.441535
17:2:2017       9:05:01:400         17.355999      78.441522
17:2:2017       9:05:01:500         17.355985      78.441562
17:2:2017       9:05:01:600         17.355994      78.441523
17:2:2017       9:05:01:700         17.355999      78.441511
17:2:2017       9:05:01:800         17.355990      78.441510
17:2:2017       9:05:01:900         17.355995      78.441528
Thank you

-dev

Is there any way so that i can get in this way!
My NeoGPS library parses the fractional seconds.  Here is a NeoGPS sketch that produces the output you are asking for:

Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>

NMEAGPS  gps; // This parses the GPS characters

#define gps_port Serial1

//------------------------------------

void doSomeWork( const gps_fix & fix )
{
  if (fix.valid.date & fix.valid.time & fix.valid.location) {

    // Date
    Serial.print( fix.dateTime.date );
    Serial.print( ':' );
    Serial.print( fix.dateTime.month );
    Serial.print( ':' );
    Serial.print( fix.dateTime.full_year() );
    Serial.print( F("      ") );

    // Time
    if ( fix.dateTime.hours < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.hours );
    Serial.print( ':' );
    if ( fix.dateTime.minutes < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.minutes );
    Serial.print( ':' );
    if ( fix.dateTime.seconds < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.seconds );
    Serial.print( '.' );
    if ( fix.dateTime_cs < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime_cs );
    Serial.print( F("         ") );

    // Location
    Serial.print( fix.latitude(), 5 );
    Serial.print( F("      ") );
    Serial.print( fix.longitude(), 5 );

  } else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();

} // doSomeWork

//------------------------------------

void GPSloop()
{
  while (gps.available( gps_port ))
    doSomeWork( gps.read() );

} // GPSloop
 
//------------------------------------

void setup()
{
  Serial.begin(9600);
  Serial.println( F("Date              Time             Latitude         Longitude\n") );
  Serial.flush();
 
  gps_port.begin( 9600 );
}

//------------------------------------

void loop()
{
  GPSloop();
}

If you'd like to try it, NeoGPS is available from the Arduino IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries.  NeoGPS is also faster, smaller and more accurate than all other libraries.  You'll have to add the baud rate and update rate commands, of course.

Depending on your SD card, you may be losing a record when the card takes longer than 100ms to perform a write.  You may need to use the Interrupt processing style of NeoGPS.

And if you need more accurate locations, NeoGPS can be used to log up to 10 significant digits, not just the typical 7 digits you get from other libraries (via float).  NeoGPS has been used to reliably log 20Hz GPS to an SD card (no data loss!).

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

Thank very muvh /Dev for replying.

I am now using NEOGps library as you have suggested, I have also tested the code you supplied (Thank you very much for that).

But i came across with another issue regarding obtaining 10Hz Gps data, I have to use PowerGPS to send two commands which is
Quote
"$PMTK251,115200*27<CR><LF>"
and
Quote
"$PMTK220,100*1F<CR><LF>"
, then i connect that to Arduino, whenever i power down the Quectel L80 (receiver) it's coming back to defualt 1Hz update rate mode.

I have learned from the quectel tech support person where he said : For getting 10Hz data, i need to update the default baudrate (9600) to more than that like 115200.

So i want to send that command to set the receiver on that baudrate

I want to send these two commands while the recevier is connected to Serial1, how will be the syntax for it.?

Here i am getting the output with the above supplied code
Quote
Date              Time             Latitude         Longitude

18:2:2017      07:21:15.00         17.35709      78.44269
18:2:2017      07:21:16.00         17.35709      78.44269
18:2:2017      07:21:17.00         17.35709      78.44269
18:2:2017      07:21:18.00         17.35709      78.44269
18:2:2017      07:21:18.21         17.35709      78.44269
18:2:2017      07:21:20.00         17.35709      78.44269
18:2:2017      07:21:21.00         17.35709      78.44269
18:2:2017      07:21:22.00         17.35709      78.44269
18:2:2017      07:21:23.00         17.35709      78.44269
18:2:2017      07:21:24.00         17.35709      78.44269
18:2:2017      07:21:24.21         17.35709      78.44269
18:2:2017      07:21:26.00         17.35709      78.44269
18:2:2017      07:21:27.00         17.35709      78.44269
18:2:2017      07:21:28.00         17.35709      78.44269
18:2:2017      07:21:29.00         17.35709      78.44269
18:2:2017      07:21:30.00         17.35709      78.44269
18:2:2017      07:21:30.20         17.35709      78.44269
18:2:2017      07:21:32.00         17.35709      78.44269
18:2:2017      07:21:33.00         17.35709      78.44269
18:2:2017      07:21:34.00         17.35709      78.44269
18:2:2017      07:21:35.00         17.35709      78.44269
18:2:2017      07:21:36.00         17.35709      78.44269
18:2:2017      07:21:36.21         17.35709      78.44269
18:2:2017      07:21:38.00         17.35709      78.44269
18:2:2017      07:21:39.00         17.35709      78.44269
18:2:2017      07:21:40.00         17.35709      78.44269
18:2:2017      07:21:41.00         17.35709      78.44269
18:2:2017      07:21:42.00         17.35709      78.44269
18:2:2017      07:21:42.20         17.35709      78.44269
18:2:2017      07:21:44.00         17.35709      78.44269
18:2:2017      07:21:45.00         17.35709      78.44269
18:2:2017      07:21:46.00         17.35709      78.44269
18:2:2017      07:21:47.00         17.35709      78.44269
18:2:2017      07:21:48.00         17.35709      78.44269
18:2:2017      07:21:48.20         17.35709      78.44269
18:2:2017      07:21:50.00         17.35709      78.44269
18:2:2017      07:21:51.00         17.35709      78.44269
18:2:2017      07:21:52.00         17.35709      78.44269
18:2:2017      07:21:53.00         17.35709      78.44269
18:2:2017      07:21:54.00         17.35709      78.44269
18:2:2017      07:21:54.20         17.35709      78.44269
18:2:2017      07:21:56.00         17.35709      78.44269
18:2:2017      07:21:57.00         17.35709      78.44269
18:2:2017      07:21:58.00         17.35709      78.44269
18:2:2017      07:21:59.00         17.35709      78.44269
18:2:2017      07:22:00.00         17.35709      78.44269
18:2:2017      07:22:01.00         17.35709      78.44269
18:2:2017      07:22:02.00         17.35709      78.44269
Thank you

-dev

Quote
So i want to send that command
Ok, just send it in setup:

Code: [Select]
void setup()
{
  Serial.begin(9600);
  Serial.println( F("Date              Time             Latitude         Longitude\n") );
  Serial.flush();
 
  gps_port.begin( 9600 );
  gps_port.print( F("$PMTK251,115200*27\r\n") ); // set 115200 baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps_port.print( F("$PMTK220,100*1F\r\n") );    // set 10Hz update rate

}

Remember that at 9600, you can only print 100 characters to Serial for each GPS update.  You are currently printing 60 characters per GPS update.  If you want to print more, you'll have to increase the Serial baud rate.  (This is not a limit when writing to the SD card.)

If you haven't run NMEAorder.ino, now would be a good time to try it.  For each brand of GPS device, you need to confirm that NMEAGPS_cfg.h has the correct LAST_SENTENCE_IN_INTERVAL.  NMEAorder expects a 1Hz update rate, so be sure to try it before you have run a sketch that sets 10Hz.  You could also use PowerGPS to set the update rate back to 1Hz.  You only have to do this once.

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

Hello /Dev,
Thank you again for replying, I haved tested the above code and plugged that into the void setup () as you have said (Full code below), When i open Serial monitor in 9600 mode - It only shows
Quote
Date              Time             Latitude         Longitude
when switched to 115200 it doesn't show anything

below is the full code i have tried.
Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>


NMEAGPS  gps; // This parses the GPS characters

#define gps_port Serial1

//------------------------------------

void doSomeWork( const gps_fix & fix )
{
  if (fix.valid.date & fix.valid.time & fix.valid.location) {

    // Date
    Serial.print( fix.dateTime.date );
    Serial.print( ':' );
    Serial.print( fix.dateTime.month );
    Serial.print( ':' );
    Serial.print( fix.dateTime.full_year() );
    Serial.print( F("      ") );

    // Time
    if ( fix.dateTime.hours < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.hours );
    Serial.print( ':' );
    if ( fix.dateTime.minutes < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.minutes );
    Serial.print( ':' );
    if ( fix.dateTime.seconds < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.seconds );
    Serial.print( '.' );
    if ( fix.dateTime_cs < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime_cs );
    Serial.print( F("         ") );

    // Location
    Serial.print( fix.latitude(), 5 );
    Serial.print( F("      ") );
    Serial.print( fix.longitude(), 5 );

  } else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();

} // doSomeWork

//------------------------------------

void GPSloop()
{
  while (gps.available( gps_port ))
    doSomeWork( gps.read() );

} // GPSloop

//------------------------------------

void setup()
{
  Serial.begin(9600);
  Serial.println( F("Date              Time             Latitude         Longitude\n") );
  Serial.flush();
 
  gps_port.begin( 9600 );
  gps_port.print( F("$PMTK251,115200*27\r\n") ); // set 115200 baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps_port.print( F("$PMTK220,100*1F\r\n") );    // set 10Hz update rate

}

//------------------------------------

void loop()
{
  GPSloop();
}


also i have tested the GPS receiver wth the NEMAorder.ino from the NeoGPS Library, after trying the above full code. it shows me 1 second of interval.

Serial Monitor output for NMEAorder.ino
Quote
NMEAorder.INO: started
fix object size = 31
NMEAGPS object size = 84
Looking for GPS device on Serial1
................
Sentence order in each 1-second interval:
  RMC
  VTG
  GGA
  GSA
  GSV
  GSV
  GSV
  GLL

Quote
You could also use PowerGPS to set the update rate back to 1Hz.  You only have to do this once.
do i have to set 10Hz with my receiver only for one time.? This doesn't happen with me  :(  is it because i have plugged VBat pin to arduino 3.3V supply.? I have not connected RTC battery to GPS receiver.

Thanks

-dev

The PMTK commands you posted were not correct, and I just copied them into my sketch.  They do not have the correct checksum, so the GPS device will ignore them.  Change these 2 prints:

Code: [Select]
  gps_port.print( F("$PMTK251,115200*1F\r\n") ); // set 115200 baud rate
     ...
  gps_port.print( F("$PMTK220,100*2F\r\n") );    // set 10Hz update rate

The two hex digits after the '*' are different (calculator here).  This is one reason I added a "send" function to NeoGPS that would calculate the checksum for you.  You could do this instead:

Code: [Select]
  gps.send_P( &gps_port, F("PMTK251,115200") ); // set baud rate
     ...
  gps.send_P( &gps_port, F("PMTK220,100") );    // set 10Hz update rate

Notice how you don't need the '$', the '*', the checksum nor the CR/LF.  send_P takes care of all that for you.  Here's the complete sketch with the send_P:

Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>

NMEAGPS  gps; // This parses the GPS characters

#define gps_port Serial1

//------------------------------------

void doSomeWork( const gps_fix & fix )
{
  if (fix.valid.date & fix.valid.time & fix.valid.location) {

    // Date
    Serial.print( fix.dateTime.date );
    Serial.print( ':' );
    Serial.print( fix.dateTime.month );
    Serial.print( ':' );
    Serial.print( fix.dateTime.full_year() );
    Serial.print( F("      ") );

    // Time
    if ( fix.dateTime.hours < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.hours );
    Serial.print( ':' );
    if ( fix.dateTime.minutes < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.minutes );
    Serial.print( ':' );
    if ( fix.dateTime.seconds < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime.seconds );
    Serial.print( '.' );
    if ( fix.dateTime_cs < 10 )
      Serial.print( '0' );
    Serial.print( fix.dateTime_cs );
    Serial.print( F("         ") );

    // Location
    Serial.print( fix.latitude(), 5 );
    Serial.print( F("      ") );
    Serial.print( fix.longitude(), 5 );

  } else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();

} // doSomeWork

//------------------------------------

void GPSloop()
{
  while (gps.available( gps_port ))
    doSomeWork( gps.read() );

} // GPSloop
 
//------------------------------------

void setup()
{
  Serial.begin(9600);
  Serial.println( F("Date              Time             Latitude         Longitude\n") );
  Serial.flush();
 
  Serial.flush();
 
  gps_port.begin( 9600 );
  gps.send_P( &gps_port, F("PMTK251,115200") );  // set baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps.send_P( &gps_port, F("PMTK220,100") );     // set 10Hz update rate
}

//------------------------------------

void loop()
{
  GPSloop();
}

Also, you should not change the Serial Monitor window baud rate from 9600.  It should always match what you have in setup:

    Serial.begin( 9600 ); // Serial Monitor must match!

The PMTK command changes the baud rate of the GPS device, and then your sketch must change Serial1 (i.e., gps_port) to match it.  It has nothing to do with the Serial Monitor.

Quote
Serial Monitor output for NMEAorder.ino:

Code: [Select]
NMEAorder.INO: started
    ...
Sentence order in each 1-second interval:
  RMC
  VTG
  GGA
  GSA
  GSV
  GSV
  GSV
  GLL
Make sure that NMEAGPS_cfg.h specifies the last sentence that you have enabled.  The default NeoGPS configuration has RMC and GGA enabled, so you would choose GGA, according to the above output:

Code: (NMEAGPS_cfg.h line 31) [Select]
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GGA
Cheers,
/dev
Really, I used to be /dev.  :(

-dev

Quote
do i have to set 10Hz with my receiver only for one time.?
No, I would set it every time, in setup.
Quote
is it because i have plugged VBat pin to arduino 3.3V supply.? I have not connected RTC battery to GPS receiver.
No, you weren't getting any output because the "change baud rate" command was rejected, and your sketch changed baud rate anyway.  The GPS device was still running at 9600 and the Arduino gps_port changed to 115200.  No GPS characters will be received by the Arduino when the baud rates don't match.

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

#7
Feb 19, 2017, 11:34 am Last Edit: Feb 19, 2017, 11:37 am by mudassir9999
Thank you very much for the reply again /Dev, I have applied the code you provided and it's working flawlessly.

Code: [Select]
gps.send_P( &gps_port, F("PMTK251,115200") ); // set baud rate
     ...
  gps.send_P( &gps_port, F("PMTK220,100") );    // set 10Hz update rate


this is the better way! as I don't want to mess with the things again.

I have been logging the data into a class 4 micro SD card using the catalex module, and I am using the SDFAT.h library for data logging.

below is my full code
Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>
#include <SPI.h>
#include <SdFat.h>

NMEAGPS  gps; // This parses the GPS characters

#define gps_port Serial1
File dataFile;


char filename[] = "12345.tcx";


SdFat SD;

const int xpin = A0;                  // x-axis of the accelerometer
const int ypin = A1;                  // y-axis
const int zpin = A2;                  // z-axis
int x, y, z, total;

void setup()  {
  Serial.begin(9600);
  Serial.flush();

  gps_port.begin( 9600 );
  gps.send_P( &gps_port, F("PMTK251,115200") );  // set baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps.send_P( &gps_port, F("PMTK220,100") );     // set 10Hz update rate
  pinMode(37, INPUT_PULLUP);
  if (!SD.begin(4)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  Serial.println("Code Running");

}

void doSomeWork( const gps_fix & fix ) {

  if (fix.valid.date )
  {
    Serial.println("Co-ordinates Achived");
    dataFile = SD.open(filename , FILE_WRITE);
    Serial.println(filename);
    if (dataFile) {
      Serial.println("File created");
      Serial.println("LOGGING DATA!");
      dataFile.println(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"));
      dataFile.println(F("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\">"));
      dataFile.println(F("<Activities>"));
      dataFile.println(F("<Activity Sport=\"Other\">"));
      dataFile.println("<Id>");
      dataFile.print(fix.dateTime.full_year());
      dataFile.print("-");
      dataFile.print(fix.dateTime.month);
      dataFile.print("-");
      dataFile.print(fix.dateTime.date);
      dataFile.print("T");
      dataFile.print(fix.dateTime.hours);
      dataFile.print(":");
      dataFile.print(fix.dateTime.minutes);
      dataFile.print(":");
      dataFile.print(fix.dateTime.seconds);
      dataFile.print(":");
      dataFile.print(fix.dateTime_cs);
      dataFile.print(".000Z");
      dataFile.println("</Id>");
      dataFile.println("<Lap StartTime=\"");
      // dataFile.print(String(ddate));
      dataFile.print("T");
      //dataFile.print(String(ttime));
      dataFile.print(".000Z\">");
      dataFile.println("<Track>");
    }
    while (1)
    {
      if (digitalRead(37) == LOW) {
        endtask();
      }
      dataFile.println("<Trackpoint>");
      dataFile.println("<Time>");
      dataFile.print(fix.dateTime.full_year());
      dataFile.print("-");
      dataFile.print(fix.dateTime.month);
      dataFile.print("-");
      dataFile.print(fix.dateTime.date);
      dataFile.print("T");
      dataFile.print(fix.dateTime.hours);
      dataFile.print(":");
      dataFile.print(fix.dateTime.minutes);
      dataFile.print(":");
      dataFile.print(fix.dateTime.seconds);
      dataFile.print(":");
      dataFile.print(fix.dateTime_cs);
      dataFile.print(".000Z");
      dataFile.print("</Time>");
      dataFile.println("<Position>");
      dataFile.print("<LatitudeDegrees>");
      dataFile.print(fix.latitude(), 5 );
      dataFile.println("</LatitudeDegrees>");
      dataFile.print("<LongitudeDegrees>");
      dataFile.print(fix.longitude(), 5);
      dataFile.println("</LongitudeDegrees>");
      dataFile.println("</Position>");
      dataFile.println("<HeartRateBpm>");
      dataFile.print("<Value>");
      dataFile.print(String("0"));
      dataFile.println("</Value>");
      dataFile.println("</HeartRateBpm>");
      dataFile.print("<SensorState>");
      dataFile.print("Present");
      dataFile.println("</SensorState>");
      analogReference(EXTERNAL);
      x = analogRead(xpin);
      y = analogRead(ypin);
      z = analogRead(zpin);
      total = sqrt(x * x + y * y + z * z);
      dataFile.print("<impact>");
      dataFile.print("<gforce>");
      dataFile.print(total);
      dataFile.println("</gforce>");
      dataFile.print("<xaxis>");
      dataFile.print(x);
      dataFile.println("</xaxis>");
      dataFile.print("<yaxis>");
      dataFile.print(y);
      dataFile.println("</yaxis>");
      dataFile.print("<zaxis>");
      dataFile.print(z);
      dataFile.println("</zaxis>");
      dataFile.println("</impact>");
      dataFile.println("</Trackpoint>");
      //Serial.println();
    }
  }
  else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();
}
void GPSloop()
{
  while (gps.available( gps_port) )
    doSomeWork( gps.read() );

} // GPSloop
void loop()
{
  GPSloop();
}

void endtask()
{
  dataFile.println("</Track>");
  dataFile.println("</Lap>");
  dataFile.println("</Activity>");
  dataFile.println("</Activities>");
  dataFile.println("</TrainingCenterDatabase>");
  dataFile.close();
  Serial.print("file close");
}


there is an error with in the logged data, The timings are same in every field below is the logged SD data (I have attached the logged 000.txt file with this message

Please look for <Time>
2017-2-19T9:31:19:60.000Z</Time>


I was expecting time change something like this:
Quote
<Time>
2017-2-19T9:31:19:00.000Z</Time>
<Time>
2017-2-19T9:31:19:01.000Z</Time>
<Time>
2017-2-19T9:31:19:02.000Z</Time>
<Time>
2017-2-19T9:31:19:03.000Z</Time>
<Time>
2017-2-19T9:31:19:04.000Z</Time>
<Time>
2017-2-19T9:31:19:05.000Z</Time>
<Time>
2017-2-19T9:31:19:06.000Z</Time>
<Time>
2017-2-19T9:31:19:07.000Z</Time>
<Time>
2017-2-19T9:31:19:08.000Z</Time>
<Time>
2017-2-19T9:31:19:09.000Z</Time>
<Time>
2017-2-19T9:31:20:00.000Z</Time>
can you spot my mistake please
Thank you

-dev

The timings are same in every field...  can you spot my mistake
Yes, you are stuck in the "while (1)" loop (line 82) when you get a fix with a valid date.  You never let it get a new fix.  Your program call structure is basically

Code: [Select]
setup{}

loop() {
  GPSloop() {
    while (gps.available) {
      fix = gps.read();
      doSomeWork( fix ) {
        if (fix.valid.date) {
          if (datafile) {
            while (1) {
              ...print the same fix over and over...
            }
          }
        }
      }
    }
  }
}

(That's not the C++ code, it just shows how the calls are nested when it runs.)

You need to print the "current" fix and return from doSomeWork.  When another fix comes in, you can print it next.  Your program call structure should be something like this:

Code: [Select]
setup() { ... }

loop() {
  GPSloop() {
    while (gps.available) {
      fix = gps.read();
      doSomeWork( fix ) {
        if (fix.valid.date) {
          if (datafile) {
            ...print the fix (and return all the way to loop)...
          }
        }
      }
    }
  }
}

After returning, loop gets called thousands of times, but no GPS fixes will be ready.  100ms later, a new fix will be available, and doSomeWork gets called again to write the new fix.

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

#9
Feb 19, 2017, 06:30 pm Last Edit: Feb 19, 2017, 06:35 pm by mudassir9999
Hello /Dev,
thank you replying, I completely understand your explanation, but I am trying to achieve while (1) content in a loop and to be saved in the SD card until I press the button on pin 37.

My Aim is to log below content at 10Hz until I pressed the button.
Code: [Select]
{
      if (digitalRead(37) == LOW) {
        endtask();
      }
      dataFile.println("<Trackpoint>");
      dataFile.println("<Time>");
      dataFile.print(fix.dateTime.full_year());
      dataFile.print("-");
      dataFile.print(fix.dateTime.month);
      dataFile.print("-");
      dataFile.print(fix.dateTime.date);
      dataFile.print("T");
      dataFile.print(fix.dateTime.hours);
      dataFile.print(":");
      dataFile.print(fix.dateTime.minutes);
      dataFile.print(":");
      dataFile.print(fix.dateTime.seconds);
      dataFile.print(":");
      dataFile.print(fix.dateTime_cs);
      dataFile.print(".000Z");
      dataFile.print("</Time>");
      dataFile.println("<Position>");
      dataFile.print("<LatitudeDegrees>");
      dataFile.print(fix.latitude(), 5 );
      dataFile.println("</LatitudeDegrees>");
      dataFile.print("<LongitudeDegrees>");
      dataFile.print(fix.longitude(), 5);
      dataFile.println("</LongitudeDegrees>");
      dataFile.println("</Position>");
      dataFile.println("<HeartRateBpm>");
      dataFile.print("<Value>");
      dataFile.print(String("0"));
      dataFile.println("</Value>");
      dataFile.println("</HeartRateBpm>");
      dataFile.print("<SensorState>");
      dataFile.print("Present");
      dataFile.println("</SensorState>");
      analogReference(EXTERNAL);
      x = analogRead(xpin);
      y = analogRead(ypin);
      z = analogRead(zpin);
      total = sqrt(x * x + y * y + z * z);
      dataFile.print("<impact>");
      dataFile.print("<gforce>");
      dataFile.print(total);
      dataFile.println("</gforce>");
      dataFile.print("<xaxis>");
      dataFile.print(x);
      dataFile.println("</xaxis>");
      dataFile.print("<yaxis>");
      dataFile.print(y);
      dataFile.println("</yaxis>");
      dataFile.print("<zaxis>");
      dataFile.print(z);
      dataFile.println("</zaxis>");
      dataFile.println("</impact>");
      dataFile.println("</Trackpoint>");
      //Serial.println();
    }
  }
  else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();
}


The first part will be only for one time - initialization and will not be logged over and over again..

This will be logged only for one time INITIALIZATION
Code: [Select]
if (fix.valid.date )
  {
    Serial.println("Co-ordinates Achived");
    dataFile = SD.open(filename , FILE_WRITE);
    Serial.println(filename);
    if (dataFile) {
      Serial.println("File created");
      Serial.println("LOGGING DATA!");
      dataFile.println(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"));
      dataFile.println(F("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\">"));
      dataFile.println(F("<Activities>"));
      dataFile.println(F("<Activity Sport=\"Other\">"));
      dataFile.println("<Id>");
      dataFile.print(fix.dateTime.full_year());
      dataFile.print("-");
      dataFile.print(fix.dateTime.month);
      dataFile.print("-");
      dataFile.print(fix.dateTime.date);
      dataFile.print("T");
      dataFile.print(fix.dateTime.hours);
      dataFile.print(":");
      dataFile.print(fix.dateTime.minutes);
      dataFile.print(":");
      dataFile.print(fix.dateTime.seconds);
      dataFile.print(":");
      dataFile.print(fix.dateTime_cs);
      dataFile.print(".000Z");
      dataFile.println("</Id>");
      dataFile.println("<Lap StartTime=\"");
      // dataFile.print(String(ddate));
      dataFile.print("T");
      //dataFile.print(String(ttime));
      dataFile.print(".000Z\">");
      dataFile.println("<Track>");
    }


that's the reason I have used while(1) loop.

Is there any way to get that while(1) content only in loop.

Thank you

mudassir9999

#10
Feb 20, 2017, 09:50 am Last Edit: Feb 20, 2017, 10:02 am by mudassir9999
hello /Dev,
I made a below code where it should do as I am expecting but it's not at all creating a file in SD card.

Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>
#include <SPI.h>
#include <SdFat.h>

NMEAGPS  gps; // This parses the GPS characters

#define gps_port Serial1
File dataFile;


char filename[] = "12345.tcx";


SdFat SD;

const int xpin = A0;                  // x-axis of the accelerometer
const int ypin = A1;                  // y-axis
const int zpin = A2;                  // z-axis
int x, y, z, total;

void setup()  {
  Serial.begin(9600);
  Serial.flush();

  gps_port.begin( 9600 );
  gps.send_P( &gps_port, F("PMTK251,115200") );  // set baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps.send_P( &gps_port, F("PMTK220,100") );     // set 10Hz update rate
  pinMode(37, INPUT_PULLUP);
  if (!SD.begin(4)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  Serial.println("Code Running");

}
void GPSloop()
{
  while (gps.available( gps_port) )
  doSomeWork( gps.read() );
  logging (gps.read());

} // GPSloop
void loop()
{
  GPSloop();

}

void doSomeWork( const gps_fix & fix ) {

  if (fix.valid.date )
  {
    Serial.println("Co-ordinates Achived");
    dataFile = SD.open(filename , FILE_WRITE);
    Serial.println(filename);
    if (dataFile) {
      Serial.println("File created");
      Serial.println("LOGGING DATA!");
      dataFile.println(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"));
      dataFile.println(F("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\">"));
      dataFile.println(F("<Activities>"));
      dataFile.println(F("<Activity Sport=\"Other\">"));
      dataFile.println("<Id>");
      dataFile.print(fix.dateTime.full_year());
      dataFile.print("-");
      dataFile.print(fix.dateTime.month);
      dataFile.print("-");
      dataFile.print(fix.dateTime.date);
      dataFile.print("T");
      dataFile.print(fix.dateTime.hours);
      dataFile.print(":");
      dataFile.print(fix.dateTime.minutes);
      dataFile.print(":");
      dataFile.print(fix.dateTime.seconds);
      dataFile.print(":");
      dataFile.print(fix.dateTime_cs);
      dataFile.print(".000Z");
      dataFile.println("</Id>");
      dataFile.println("<Lap StartTime=\"");
      // dataFile.print(String(ddate));
      dataFile.print("T");
      //dataFile.print(String(ttime));
      dataFile.print(".000Z\">");
      dataFile.println("<Track>");
    }
  }
  else {
    // No valid location data yet!
    Serial.print( '?' );
  }

  Serial.println();
}
void logging  (const gps_fix & fix) {
  while (1)
  {
    if (digitalRead(37) == LOW) {
      endtask();
    }
    dataFile.println("<Trackpoint>");
    dataFile.println("<Time>");
    dataFile.print(fix.dateTime.full_year());
    dataFile.print("-");
    dataFile.print(fix.dateTime.month);
    dataFile.print("-");
    dataFile.print(fix.dateTime.date);
    dataFile.print("T");
    dataFile.print(fix.dateTime.hours);
    dataFile.print(":");
    dataFile.print(fix.dateTime.minutes);
    dataFile.print(":");
    dataFile.print(fix.dateTime.seconds);
    dataFile.print(":");
    dataFile.print(fix.dateTime_cs);
    dataFile.print(".000Z");
    dataFile.print("</Time>");
    dataFile.println("<Position>");
    dataFile.print("<LatitudeDegrees>");
    dataFile.print(fix.latitude(), 5 );
    dataFile.println("</LatitudeDegrees>");
    dataFile.print("<LongitudeDegrees>");
    dataFile.print(fix.longitude(), 5);
    dataFile.println("</LongitudeDegrees>");
    dataFile.println("</Position>");
    dataFile.println("<HeartRateBpm>");
    dataFile.print("<Value>");
    dataFile.print(String("0"));
    dataFile.println("</Value>");
    dataFile.println("</HeartRateBpm>");
    dataFile.print("<SensorState>");
    dataFile.print("Present");
    dataFile.println("</SensorState>");
    analogReference(EXTERNAL);
    x = analogRead(xpin);
    y = analogRead(ypin);
    z = analogRead(zpin);
    total = sqrt(x * x + y * y + z * z);
    dataFile.print("<impact>");
    dataFile.print("<gforce>");
    dataFile.print(total);
    dataFile.println("</gforce>");
    dataFile.print("<xaxis>");
    dataFile.print(x);
    dataFile.println("</xaxis>");
    dataFile.print("<yaxis>");
    dataFile.print(y);
    dataFile.println("</yaxis>");
    dataFile.print("<zaxis>");
    dataFile.print(z);
    dataFile.println("</zaxis>");
    dataFile.println("</impact>");
    dataFile.println("</Trackpoint>");
    //Serial.println();
  }
}


void endtask()
{
  dataFile.println("</Track>");
  dataFile.println("</Lap>");
  dataFile.println("</Activity>");
  dataFile.println("</Activities>");
  dataFile.println("</TrainingCenterDatabase>");
  dataFile.close();
  Serial.print("file close");
  while (1);
}


Look for
Code: [Select]
void GPSloop()
{
  while (gps.available( gps_port) )
  doSomeWork( gps.read() );
  logging (gps.read());

} // GPSloop


thank you

-dev

Yes, that's closer.  In doSomeWork, when you have a valid date/time/location, open the file if it's not open yet:

Code: [Select]
void doSomeWork( const gps_fix & fix ) {

  if (fix.valid.location && fix.valid.date && fix.valid.time) {

    if (!datafile.isOpen()) {
      ...open the datafile and write the first few lines...
    }

    if (datafile.isOpen()) {
      ...write a fix date/time/location to the SD file...
    }

Test the switch in loop and close datafile when it's LOW:

Code: [Select]
void loop()
{
  GPSloop();

  if (digitalRead(37) == LOW) {
    endtask();
  }
}

GPSloop still gets called all the time, and it calls doSomework when there's a new fix.  But if it never gets a valid date, time AND location, the datafile won't get opened, and it doesn't write anything.  If that's what you want to do...

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

thank you very much for your rapid replies /Dev

Quote
If that's what you want to do...
No! what I am trying to do here is writing GPS data in SD card into two stages : First stage is the Initialisation ,which will be logged only for one time.

The data inside
Code: [Select]
doSomeWork(); will be logged only for one time, in the beginning logging/writing.



Then the second stage is in the loop (over and over again until I press the button)

The data inside
Code: [Select]
logging(); will be logged for many times right after the initialisation - until I press the button to stop and close the file.

It's true that, I wanted to write data into a file when ever it gets a valid date, time and location but also want the above first stage and second stage things.

Thank you

-dev

Quote
what I am trying to do here is writing GPS data in SD card into two stages : First stage is the Initialisation ,which will be logged only for one time.  Then the second stage is in the loop... The data inside
logging() will be logged for many times right after the initialisation - until I press the button to stop and close the file.
Well, doSomeWork is where the logging (second stage) must take place.  If you do it in loop, you're trying to log the same fix thousands of times.  That's because doSomeWork is only called when a new fix is available.  The rest of the time, loop and GPSloop are just checking to see is a new fix is available.  Most of the time, there is no new fix.

The same is true for the first stage: you should only test for a valid date/time/location when a new fix is available.  You would not test this in loop, for the same reason: fix.valid.date won't change until there is a new fix.

Here is your sketch, modified to do the first stage and second stage in doSomeWork.

Code: [Select]
#include <Arduino.h>
#include <NMEAGPS.h>
#include <SPI.h>
#include <SdFat.h>


NMEAGPS  gps; // This parses the GPS characters
gps_fix  fix; // This contains all the GPS fields

#define gps_port Serial1


SdFat SD;
File  dataFile;
char filename[] = "12345.tcx";


const int xpin = A0;                  // x-axis of the accelerometer
const int ypin = A1;                  // y-axis
const int zpin = A2;                  // z-axis
int x, y, z, total;

void setup()  {
  Serial.begin(9600);
  Serial.flush();

  gps_port.begin( 9600 );
  gps.send_P( &gps_port, F("PMTK251,115200") );  // set baud rate
  gps_port.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gps_port.end();                                // empty the input buffer, too

  gps_port.begin( 115200 );                      // use the new baud rate
  gps.send_P( &gps_port, F("PMTK220,100") );     // set 10Hz update rate

  pinMode(37, INPUT_PULLUP);

  if (!SD.begin(4)) {
    Serial.println( F("Card failed, or not present") );
    // don't do anything more:
    return;
  }
  Serial.println( F("card initialized.") );
  Serial.println( F("Code Running") );

} // setup

void firstStage()
{
  Serial.println( F("Co-ordinates Achieved") );
  dataFile = SD.open(filename , FILE_WRITE);
  Serial.println(filename);

  if (dataFile) {
    Serial.println( F("File created\n"
                      "LOGGING DATA!\n") );

    dataFile.println( F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                        "<TrainingCenterDatabase xmlns=\""
                            "http://www.garmin.com/"
                                "xmlschemas/TrainingCenterDatabase/v2\">\n"
                        "<Activities>\n"
                        "<Activity Sport=\"Other\">") );
    dataFile.println( F("<Id>") );
    dataFile.print  ( fix.dateTime.full_year() );
    dataFile.print  ( '-' );
    dataFile.print  ( fix.dateTime.month );
    dataFile.print  ( '-' );
    dataFile.print  ( fix.dateTime.date );
    dataFile.print  ( 'T' );
    dataFile.print  ( fix.dateTime.hours );
    dataFile.print  ( ':' );
    dataFile.print  ( fix.dateTime.minutes );
    dataFile.print  ( ':' );
    dataFile.print  ( fix.dateTime.seconds );
    dataFile.print  ( ':' );
    dataFile.print  ( fix.dateTime_cs );
    dataFile.println( F(".000Z"
                        "</Id>\n"
                        "<Lap StartTime=\"") );
    dataFile.print  ( 'T' );
    dataFile.println( F(".000Z\">"
                        "<Track>") );
  }
} // firstStage

void secondStage()
{
  if (dataFile.isOpen()) {
    dataFile.println( F("<Trackpoint>\n"
                        "<Time>") );
    dataFile.print  (fix.dateTime.full_year());
    dataFile.print  ( '-' );
    dataFile.print  (fix.dateTime.month);
    dataFile.print  ( '-' );
    dataFile.print  (fix.dateTime.date);
    dataFile.print  ( 'T' );
    dataFile.print  (fix.dateTime.hours);
    dataFile.print  ( ':' );
    dataFile.print  (fix.dateTime.minutes);
    dataFile.print  ( ':' );
    dataFile.print  (fix.dateTime.seconds);
    dataFile.print  ( '.' );
    if (fix.dateTime_cs < 10)
      dataFile.print  ( '0' );
    dataFile.print  ( fix.dateTime_cs );
    dataFile.print  ( F("0Z"
                        "</Time>"
                        "<Position>\n"
                        "<LatitudeDegrees>") );
    dataFile.print  ( fix.latitude(), 5 );
    dataFile.print  ( F("</LatitudeDegrees>\n"
                        "<LongitudeDegrees>") );
    dataFile.print  ( fix.longitude(), 5 );
    dataFile.print  ( F("</LongitudeDegrees>\n"
                        "</Position>\n"
                        "<HeartRateBpm>\n"
                        "<Value>") );
    dataFile.print  ( '0' );
    dataFile.print  ( F("</Value>\n"
                        "</HeartRateBpm>\n"
                        "<SensorState>"
                        "Present"
                        "</SensorState>\n") );

    analogReference(EXTERNAL);
    x     = analogRead(xpin);
    y     = analogRead(ypin);
    z     = analogRead(zpin);
    total = sqrt( x * x + y * y + z * z );

    dataFile.print  ( F("<impact>"
                        "<gforce>") );
    dataFile.print  ( total );
    dataFile.print  ( F("</gforce>\n"
                        "<xaxis>") );
    dataFile.print  ( x );
    dataFile.print  ( F("</xaxis>\n"
                        "<yaxis>") );
    dataFile.print  ( y );
    dataFile.print  ( F("</yaxis>\n"
                        "<zaxis>") );
    dataFile.print  ( z );
    dataFile.println( F("</zaxis>\n"
                        "</impact>\n"
                        "</Trackpoint>") );
  }

} // secondStage

void doSomeWork() {

  if (fix.valid.date && fix.valid.time && fix.valid.location)
  {
    if (!dataFile.isOpen())
      firstStage();

    if (dataFile.isOpen())
      secondStage();
  }
  else {
    // No valid location data yet!
    Serial.print  ( '?' );
  }

  Serial.println();

} // doSomeWork

void GPSloop()
{
  while (gps.available( gps_port) ) {
    fix = gps.read();
    doSomeWork();
  }

} // GPSloop

void loop()
{
  GPSloop();

  // Testing the button could go almost anywhere.
  //    Putting it here will close dataFile the fastest,
  //    because it won't have to wait for the next
  //    GPS update.
  if (digitalRead(37) == LOW) {
    endtask();

    // stop here!
    while (1)
      ;
  }

} // loop

void endtask()
{
  if (dataFile.isOpen()) {
    dataFile.println( F("</Track>\n"
                        "</Lap>\n"
                        "</Activity>\n"
                        "</Activities>\n"
                        "</TrainingCenterDatabase>") );
    dataFile.close();
    Serial.println( F("file closed") );
  } else {
    Serial.println( F("(file never opened)") );
  }

} // endtask

I think this does what you described: when it gets a valid date/time/location, it opens the file and writes a few things.  Then it writes each fix until the button is pressed, and it stops there.  It never does anything else after pressing the button, right?

If you reset the Arduino, it will do it again, to the same file.

I also used the F macro on all "double-quoted strings", changed "A" single-character strings to 'A' single character, and merged sequential string prints into one print of a concatenated string.  That is, this:

    dataFile.println("</zaxis>");
    dataFile.println("</impact>");
    dataFile.println("</Trackpoint>");

...can change to this:

    dataFile.println( F("</zaxis>\n"
                        "</impact>\n"
                        "</Trackpoint>") );

 I added newline characters, '\n', when you did a println.

The original took 22712 bytes of program space and 1694 bytes of RAM.
This version takes 21198 bytes of program space and 1163 bytes of RAM.  The string changes saved more than 500 bytes of RAM, and the print changes saved 1600 bytes of program space.

Cheers,
/dev
Really, I used to be /dev.  :(

mudassir9999

Thank you very much for replying /Dev
Quote
Well, doSomeWork is where the logging (second stage) must take place.  If you do it in loop, you're trying to log the same fix thousands of times.  That's because doSomeWork is only called when a new fix is available.  The rest of the time, loop and GPSloop are just checking to see is a new fix is available.  Most of the time, there is no new fix.

The same is true for the first stage: you should only test for a valid date/time/location when a new fix is available.  You would not test this in loop, for the same reason: fix.valid.date won't change until there is a new fix.
Thank you for this excellent explanation :)

Quote
Here is your sketch, modified to do the first stage and second stage in doSomeWork.
thank you very much for the code, which is working as I wanted :) :) :)

Quote
I also used the F macro on all "double-quoted strings", changed "A" single-character strings to 'A' single character, and merged sequential string prints into one print of a concatenated string.  That is, this:
WOW! That saved lots of space, thank you again /Dev

I have few more questions..

Quote
If you reset the Arduino, it will do it again, to the same file.
1: I don't want to write data, My idea here is : Everytime when Arduino resets, it should create a new file considering time and date as a file name, This will allow me to create a new file every resets and writes data into it.

I have made a line
Code: [Select]
  sprintf(filename, "%02d-%02d-%02d-T-%02d-%02d-%02d.tcx", fix.dateTime.hours , fix.dateTime.minutes, fix.dateTime.hours, fix.dateTime.date , fix.dateTime.month , fix.dateTime.full_year());
and plugged it before
Code: [Select]
  dataFile = SD.open(filename , FILE_WRITE); and tested, It is not at all creating a file, How do I do it.?


2: What if replaced my Quectel L80 GPS module with Quectel L86 which is GNSS module.? I think GPRMC in NeoGPS library has to replaced with GNRMC.??

3: How do I get the 10 digit more precise latitude and longitude with the NeoGPS library.? I have referred to the Readme notes of NeoGPS GitHub page where it was mentioned this :
Quote
a location structure (i.e., latitude and longitude), accessed with
fix.latitudeL() and fix.longitudeL() for the higher-precision integer degrees, scaled by 10,000,000 (10 significant digits)
fix.latitude() and fix.longitude() for the lower-precision floating-point degrees (~7 significant digits)
is that means I just have to replace fix.latitude() and fix.longitude() TO fix.latitudeL() and fix.longitudeL() .??

Thank you

Go Up