Problem reading Ubx GPS and Altumu 10

Hello,

When trying to read a GPS using UBX with software serial and sensor data from an altimu 10 I'm noticing that sometimes it takes considerably more time to print to the serial port, does anyone know why this happens.

21	0	0	-4	-172	-36	-5	-79	-224	0
20	1	11	1	-167	-36	-4	-79	-2251	-92467000	387034642	103446	55171	-9	50	-124	2
20	0	0	-3	-171	-35	-4	-79	-223	0
20	1	0	3	-169	-39	-4	-80	-221	0
20	0	0	0	-165	-35	-4	-79	-223	13
41	0	0	-1	-168	-35	-5	-79	-223	14
37	0	0	1	-163	-35	-4	-79	-223	1
20	1	0	-1	-171	-35	-3	-80	-225	0
20	0	0	-1	-180	-38	-3	-79	-223	0
20	0	0	-3	-165	-35	-4	-79	-222	0
20	0	0	-4	-166	-33	-4	-80	-224	0
20	0	0	0	-170	-36	-2	-80	-222	0
20	0	11	-1	-173	-36	-5	-79	-2211	-92466994	387034637	103383	55108	-63	83	-120	4
20	0	0	-2	-170	-36	-4	-79	-221	0
20	1	0	-5	-173	-38	-4	-79	-221	0
20	0	0	-1	-176	-36	-4	-79	-222	0
20	0	0	-1	-166	-35	-4	-80	-222	13
39	0	0	1	-169	-35	-4	-79	-225	13
40	0	0	0	-166	-33	-4	-79	-222	1
20	2	0	-1	-174	-40	-4	-79	-222	0
20	0	0	-4	-175	-37	-5	-79	-222	0
20	0	0	0	-165	-36	-4	-78	-223	0
20	0	0	0	-169	-35	-4	-79	-223	0
20	0	12	-1	-168	-36	-3	-79	-2221	-92466993	387034637	103247	54972	-120	149	-101	3
20	0	0	-4	-172	-35	-3	-79	-224	0
20	1	0	0	-155	-35	-4	-79	-223	0
20	0	0	-2	-175	-37	-4	-79	-221	0
20	0	0	-1	-166	-39	-4	-79	-224	0
20	0	0	-1	-173	-37	-4	-79	-223	0
20	0	0	-1	-172	-35	-3	-79	-223	13
40	0	0	-1	-171	-37	-4	-79	-222	13
39	1	0	1	-166	-33	-5	-79	-221	0
20	0	0	4	-166	-39	-5	-79	-221	0
20	0	0	-1	-168	-35	-5	-79	-222	0
20	0	11	2	-167	-35	-3	-78	-2201	-92467001	387034646	103162	54887	-92	68	-87	3
20	0	0	-1	-167	-35	-5	-79	-225	0

You can see in the code above that in some cases it takes longer to print, the first number on the left is the las loop time, the number on its right is the time it took to read the magnetic data in the current looop and on its right the time it took to read the GPS on the loop, the last number on the right is the time it took to print the data, as you can see this number is sometimes significantly larger.

The full code:

////////////////////////////////////////////////////////////////////////////GPS
#include <SoftwareSerial1.h>

////////////////////////////////////////////////////////////////////////////ALTIMU
#include <Wire.h>
#include <L3G.h>
#include <LSM303.h>
#include <LPS.h>


////////////////////////////////////////////////////////////////////////////ALTIMU
L3G gyro;
LSM303 compass;
LPS ps;

unsigned long timer;
uint8_t counter = 0;
int pres;
int temp;

long a[3];
long g[3];
long m[3];

////////////////////////////////////////////////////////////////////////////GPS
SoftwareSerial1 GPS(3, 2); //rx|tx
uint8_t cc = 2;
uint8_t RATE[14] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0x64, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7A, 0x12};
//38200
uint8_t UART[28] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x84};
//9600
//uint8_t UART[28] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xA9};

//uint8_t PVT[100];
uint8_t RQPVT[8] = { 0xB5, 0x62, 0x01, 0x07, 0x00, 0x00, 0x08, 0x19 };
long dtgps[8];





void setup()
{
  Serial.begin(115200);

  ////////////////////////////////////////////////////////////////////////////ALTIMU
  Wire.begin();

  gyro.init();
  gyro.enableDefault();
  gyro.writeReg(L3G::CTRL_REG4, 0x20); // 2000 dps full scale
  gyro.writeReg(L3G::CTRL_REG1, 0x0F); // normal power mode, all axes enabled, 100 Hz

  compass.init();
  compass.enableDefault();
  switch (compass.getDeviceType())
  {
    case LSM303::device_D:
      compass.writeReg(LSM303::CTRL2, 0x18); // 8 g full scale: AFS = 011
      break;
    case LSM303::device_DLHC:
      compass.writeReg(LSM303::CTRL_REG4_A, 0x28); // 8 g full scale: FS = 10; high resolution output mode
      break;
    default: // DLM, DLH
      compass.writeReg(LSM303::CTRL_REG4_A, 0x30); // 8 g full scale: FS = 11
  }

  

  ////////////////////////////////////////////////////////////////////////////GPS
  GPS.begin(9600);

  GPS.write(RATE, 14);
  delay(100);
  GPS.write(UART, 28);
  delay(100);
  GPS.begin(38400);
  timer = millis();
}




void readgps(long *dtgps)
{
  GPS.write(RQPVT, 8);
  uint8_t PVT[92];
  int i = 0;
  uint8_t cka;
  uint8_t ckb;

  while (GPS.available() > 0 || i < 91 )
  {
    PVT[i] = GPS.read();
    i++;
  }

  Serial.println(i);

  dtgps[1] = (long)PVT[24 + 9] << 24 | (long)PVT[24 + 8] << 16 | (long)PVT[24 + 7] << 8 | (long)PVT[24 + 6];
  dtgps[2] = (long)PVT[28 + 9] << 24 | (long)PVT[28 + 8] << 16 | (long)PVT[28 + 7] << 8 | (long)PVT[28 + 6];
  dtgps[3] = (long)PVT[32 + 9] << 24 | (long)PVT[32 + 8] << 16 | (long)PVT[32 + 7] << 8 | (long)PVT[32 + 6];
  dtgps[4] = (long)PVT[36 + 9] << 24 | (long)PVT[36 + 8] << 16 | (long)PVT[36 + 7] << 8 | (long)PVT[36 + 6];
  //hac=(uint32_t)PVT[40+9]<<24|(uint32_t)PVT[40+8]<<16|PVT[40+7]<<8|PVT[40+6];
  //vac=(uint32_t)PVT[44+9]<<24|(uint32_t)PVT[44+8]<<16|PVT[44+7]<<8|PVT[44+6];
  dtgps[5] = (long)PVT[48 + 9] << 24 | (long)PVT[48 + 8] << 16 | (long)PVT[48 + 7] << 8 | (long)PVT[48 + 6];
  dtgps[6] = (long)PVT[52 + 9] << 24 | (long)PVT[52 + 8] << 16 | (long)PVT[52 + 7] << 8 | (long)PVT[52 + 6];
  dtgps[7] = (long)PVT[56 + 9] << 24 | (long)PVT[56 + 8] << 16 | (long)PVT[56 + 7] << 8 | (long)PVT[56 + 6];
  // velac=(uint32_t)PVT[68+9]<<24|(uint32_t)PVT[68+8]<<16|PVT[68+7]<<8|PVT[68+6];



  //////////////////////////////////////////////////////////////////////CHKSM
  cka = ckb = 0;
  for (int a = 2; a < i - 2; a++) {
    cka = cka + PVT[a];
    ckb = ckb + cka;
  }
  if (cka == PVT[90] && ckb == PVT[91]) {
    dtgps[0] = 1;
  } else {
    dtgps[0] = 0;
  }
}




void loop()                     // run over and over again
{
  if ((millis() - timer) >= 20) // Main loop runs at 50Hz
  {
    Serial.print(millis() - timer);
    Serial.print('\t');

    timer = millis();


    //gyro.read();
    //compass.readAcc();
    a[0] = compass.a.x;
    a[1] = compass.a.y;
    a[2] = compass.a.z;
    g[0] = gyro.g.x;
    g[1] = gyro.g.y;
    g[2] = gyro.g.z;

    counter++;
    cc++;
    unsigned long t1 = millis();
    if (counter > 10)  // Read compass data at 10Hz... (5 loop runs)
    {
      //      Serial.println(F("MAG"));
      counter = 0;
      compass.readMag();
      m[0] = compass.m.x;
      m[1] = compass.m.y;
      m[2] = compass.m.z;

      pres = ps.readPressureMillibars();
      temp = ps.readTemperatureC();

    }

    Serial.print(millis() - t1);
    Serial.print('\t');
    ////////////////////////////////////////////////////////////////////////////GPS

    t1 = millis();
    if (cc > 10) {
      //      Serial.println(F("GPS"));
      readgps(dtgps);
      cc = 0;
    }
    Serial.print(millis() - t1);
    Serial.print('\t');



    t1 = millis();
    Serial.print(a[0]);
    Serial.print('\t');
    Serial.print(a[1]);
    Serial.print('\t');
    Serial.print(a[2]);
    Serial.print('\t');
    Serial.print(g[0]);
    Serial.print('\t');
    Serial.print(g[1]);
    Serial.print('\t');
    Serial.print(g[2]);

    Serial.print('\t');
    Serial.print(m[0]);
    Serial.print('\t');
    Serial.print(m[1]);
    Serial.print('\t');
    Serial.print(m[2]);
    Serial.print('\t');
    Serial.print(pres);
    Serial.print('\t');
    Serial.print(temp);
    Serial.print('\t');

    if (cc == 0) {
      Serial.print(dtgps[0]);
      Serial.print('\t');
      Serial.print(dtgps[1]);
      Serial.print('\t');
      Serial.print(dtgps[2]);
      Serial.print('\t');
      Serial.print(dtgps[3]);
      Serial.print('\t');
      Serial.print(dtgps[4]);
      Serial.print('\t');
      Serial.print(dtgps[5]);
      Serial.print('\t');
      Serial.print(dtgps[6]);
      Serial.print('\t');
      Serial.print(dtgps[7]);
    }

    Serial.print('\t');

    Serial.flush();
    Serial.println(millis() - t1);



  }
}

I have changed the Softserial library to have a 100 Byte Rx buffer as i'm trying to read 92 byte sentences.

Does anyone know any cause that can explain this behavior?

thank you in advance!

There several problems. You might want to revisit your previous posts and our previous answers. They still apply.

Regarding your specific question about a specific symptom, it is caused by combination of SoftwareSerial, Serial printing and other things.

Cheers,
/dev

I'm sorry if I'm missing something, but most of the help I was given on the other thread was about parsing NMEA and using strings.
I am now using a Ublox GPS using Ubx protocol in poling fashion, I know the sentence I'm receiving is 92 bytes long, the problem I'm experiencing (and why I don't simply read right after poling) is that there seems to be a delay between poling and the response.
To solve this I decided to increase the SoftwareSerial buffer to 100 Bytes enough to store a full sentence, then process the sentence once the buffer has 92 bytes.
This works fine if I don't read any sensors between the request and the processing, if I do I sometimes miss bytes.
To deal whith this issue (while not waiting for the delay between poling and receiving) I am calling serial.available() at the beginning of each loop and reading it then, this still causes me to wait about 40ms while reading and sometimes i loose a character and have to discard the sentence.

Is there any way of avoiding this?

tot_04_05.ino (7.89 KB)

I'm sorry if I'm missing something

Ok, here are the good bits:

Previous thread:
There is no guarantee that the entire line will be in the serial input buffer when you start in that while loop. The characters from one line might come in several separate chunks until you see the linefeed. You need to change the code so that it accumulates the characters in the string but does not process the line until it sees the \n.

You could improve the way that the NMEA sentence is read by only starting to read the sentence when you see $ which always starts an NMEA sentence.

"The writes are in between NMEA sentences, those come at 5Hz..."
Can you reduce the rate at which GPS reports? How useful is coordinates 5 times a second?
I suspect the garbled characters are results of writing to SD card too often.

I think your loop isn't very well designed

If you do the write during the GPS quiet time, it won't matter.

"...NeoGPS..."
I'll give it a try!

These are from various responders. I'll express a little frustration here because these are still relevant. And crucial, given your current state. Most are about how you receive the GPS data (not just NMEA format data). The next to last one is about coordinating when you do things. And the last one has examples of correct loop structure.

And that is the fundamental problem: loop structure. This is a common problem in the Arduino world, and a frequent stumbling block for those coming from non-embedded environments. But when you also use SoftwareSerial (an interrupt hog!) and high loop rates (50Hz), the odds of it working reliably are very low.

I believe it could work, but you'll have to approach this with a more rigorous, embedded mindset:

1) What is the final system hardware? Do you also want an SD card? Adding it later will not work, as it will mess up any timing you may have achieved without it. Or, are you using some other medium? Xbee? Is that why you're using Serial now? Will you expect to receive/read anything from that medium?

2) What pins are available after the required pins have been allocated? For example, the AltiMu must go on A4/A5. If other pins are available, you can avoid the dreaded SoftwareSerial.

3) Nothing, absolutely nothing can block. readgps is blocking. SoftwareSerial is blocking. Serial can be blocking. Ain't nobody got time for blocking at 50Hz. Did you realize that readgps blocks for almost 100ms, or 5 update cycles of 50Hz?

4) How will you verify timing? Using Serial prints isn't going to work, as they will begin to block after 64 characters have been queued for printing. You should consider getting a Logic Analyzer and using a pin or two for debug signals (instead of a Serial Print). You can get them as little as 10$, and those are ready for the 3.3V Fio. Using these cheapies with 5V systems requires a few resistors per channel. Just from looking at it, I have a pretty good guess about what's happening, but there's nothing like seeing the trace on your screen.

You asked. :slight_smile:
/dev

/dev:
Ok, here are the good bits:
These are from various responders. I'll express a little frustration here because these are still relevant. And crucial, given your current state. Most are about how you receive the GPS data (not just NMEA format data). The next to last one is about coordinating when you do things. And the last one has examples of correct loop structure.

And that is the fundamental problem: loop structure. This is a common problem in the Arduino world, and a frequent stumbling block for those coming from non-embedded environments. But when you also use SoftwareSerial (an interrupt hog!) and high loop rates (50Hz), the odds of it working reliably are very low.

I believe it could work, but you'll have to approach this with a more rigorous, embedded mindset:

1) What is the final system hardware? Do you also want an SD card? Adding it later will not work, as it will mess up any timing you may have achieved without it. Or, are you using some other medium? Xbee? Is that why you're using Serial now? Will you expect to receive/read anything from that medium?

2) What pins are available after the required pins have been allocated? For example, the AltiMu must go on A4/A5. If other pins are available, you can avoid the dreaded SoftwareSerial.

3) Nothing, absolutely nothing can block. readgps is blocking. SoftwareSerial is blocking. Serial can be blocking. Ain't nobody got time for blocking at 50Hz. Did you realize that readgps blocks for almost 100ms, or 5 update cycles of 50Hz?

4) How will you verify timing? Using Serial prints isn't going to work, as they will begin to block after 64 characters have been queued for printing. You should consider getting a Logic Analyzer and using a pin or two for debug signals (instead of a Serial Print). You can get them as little as 10$, and those are ready for the 3.3V Fio. Using these cheapies with 5V systems requires a few resistors per channel. Just from looking at it, I have a pretty good guess about what's happening, but there's nothing like seeing the trace on your screen.

You asked. :slight_smile:
/dev

Thank you for the reply, I'm sorry for the frustration, I will try neoGPS again. Regarding your points:

  1. and 2) I will be using both an xbee and a sd card, both for recording/telemetry only, which is why I cannot use hardware serial for the GPS, I tried to connect the ublox gps to sda and running it that way, but it's not recognized and so I'm again using SoftwareSerial, I will try a second Ublox to see if it was a problem with the unit.
    3)I didn't realize this, is there any way around it?
  2. I'll look into getting one of those, for timing I was counting on printing out to file and Serial, thought serial would mostly be for tracking and the SD would be for data analysis.

Is there any way not to use loops then? as it's obvious and you mentioned I'm fairly new to all of this and so any tips where to start are welcomed.

In attachment I have the most recent code and an output (from a slightly earlier version as I can't pot the GPS outside now) can you recommend some changes or am I better off starting from scratch?

Thank you again, and sorry for the bother.

tot_04_05.ino (8.57 KB)

Data65.txt (304 KB)

I will try NeoGPS again.

Not that you have to try NeoGPS again... At a minimum, you should read the examples to see how and when they do things. Start with NMEAloc.ino, a simpler example, then look at NMEAfused.ino, and finally NMEAfused_isr.ino. If you only need to receive the PVT, you probably don't need a GPS library. But...

Did you plan on using GPS time for anything? Perhaps for a timestamp to be logged?

I will be using both an xbee and a sd card

Gah! The SD card must use pins 10,11,12 and 13. Will you be receiving from Xbee?

I didn't realize [SoftwareSerial is bad], is there any way around it?

Yes, but you must use pins 8 & 9.

I didn't realize [readgps is blocking], is there any way around it? Is there any way not to use loops then?

Yes, the NeoGPS examples are written this way, and so are the examples in the ever-popular Serial Input Basics. You should check out the endMarker example.

Cheers,
/dev

In attachment I have the most recent code... can you recommend some changes or am I better off starting from scratch?

You don't have to start from scratch, but there are several things that are broken. Mostly that you can't sit and wait for 92 characters. Check out the examples I (we!) mentioned, and ask some more questions.

Cheers,
/dev

Not that you have to try NeoGPS again... At a minimum, you should read the examples to see how and when they do things. Start with NMEAloc.ino, a simpler example, then look at NMEAfused.ino, and finally NMEAfused_isr.ino. If you only need to receive the PVT, you probably don't need a GPS library. But...

I will try it again, and try to learn how it works, I didn't spend much time on it before because it only provided GPS data at 1Hz which isn't enough for what I'm looking for.

Did you plan on using GPS time for anything? Perhaps for a timestamp to be logged?

I planed on logging 3D position and velocity and time (also for timestamps).

Gah! The SD card must use pins 10,11,12 and 13. Will you be receiving from Xbee?

No, just sending.

Yes, but you must use pins 8 & 9.

Can you elaborate? Is it much better?

Yes, the NeoGPS examples are written this way, and so are the examples in the ever-popular Serial Input Basics. You should check out the endMarker example.

I've looked at it and will continue to try the examples, however in this case I have no End Marker as the final bytes are checksums, I do know the Start Marker and the length, which is what I check for in the newer code.

What I'm trying to do in the newer code is to check GPS.available() at the start of every loop and reading all the data (until byte 92 or a timeout) if there is anything in the buffer.

void loop() {
   
  if (GPS.available() > 0)
  {
    rec = 1;
    GPS_Read();
  }

  if (millis() - timer >= 20) {
    dt = millis() - timer;
    timer = millis();
    cc++;
    counter++;

    if (cc > 4)
    {
      cc=0;
      Read_Compass();
      Read_Press();
    }

    if (rec == 1 && counter > 4) {
      counter=0;
      GPS_Cheksum();
      GPS_Parse();
      GPS_Rquest();
    }
    Prt_Fl();
    Prt_Sc();
  }
}

I have a question regarding the buffer, I have a Software serial buffer of 100 Bytes, shouldn't I be able to let it fill with characters in the background and only use GPS.read() when it has 92 Bytes? I've tried it (using if(GPS.available()==92)) but it doesn't work if I have other things going on in the loop.

Thank you for all the help! I will look at what you suggested.

it only provided GPS data at 1Hz

That's not a function of the library. You can preconfigure the GPS device with ucenter and store it permanently, or you can send configuration commands during setup. I assume you did the former.

Can you elaborate? Is [using pins 8 & 9] much better?

Yes, much better. AltSoftSerial plays nicer with other interrupts, too. However, because you are "just sending" to the Xbee, and "mostly receiving" from the GPS, you may not need a second serial port:

You could connect the Fio TX to the Xbee RX (just the USB-TTL serial adapter for now), and connect the Fio RX to the GPS Tx. And instead of transmitting a PVT poll request to the GPS, preconfigure it to run at 10Hz. The PVT will arrive regularly, and will be synchronized to the real GPS clock. Your current polling approach will drift because the millis() clock is not very accurate. Asking for it faster than the device's maximum update rate is useless.

This means your sketch could use just one HardwareSerial port (i.e., Serial); this solves many problems. The USART hardware can buffer 2 characters (about 2ms) while other interrupts are working. This a relatively long time, compared to other interrupts in the system. It's very good that it can wait that long for its interrupt to be dispatched. That is, it accommodates other interrupt sources. Woot.

When SoftwareSerial is running at 9600, it blocks all other interrupts for about 1ms for each character received. It's very bad to make other interrupts wait that long. And if another interrupt keeps the SoftwareSerial interrupt from being dispatched for 1 bit time, about 100us, the received character will be garbled. It cannot accommodate other interrupt sources for very long. It's really a mess. AltSoftSerial is about 10 times better.

Even if you still need to transmit to the GPS, I would use an AltSoftSerial object for that. There are just too many reasons to use HardwareSerial for GPS receive and Xbee transmit.

What I'm trying to do... is to check GPS.available()... and read all the data (until byte 92 or a timeout)

I really can't make this any plainer:

me:
...you can't sit and wait for 92 characters.

You have to do it like the EndMarker example. I understand your question, though:

I have no End Marker as the final bytes are checksums; I do know the Start Marker and the length

And that's the key. Instead of testing for a specific ending character, you will test for a specific ending count... and then verify the CS and use the PVT if it's ok.

It's a different test, but you must use the same approach of reading what characters are available now (incrementing the count), and then moving on if they aren't all there yet. Next time(s) through the main loop(), you might get the 92nd character, and then you use the PVT.

Cheers,
/dev

Hi again,
I tried to implement what you said before (I think), the problem is that this slows the loop to about 25ms per read and though sometimes i get good results, most times the time between receiving 92 byte sentences is high, and the checksums fail. I have the code and a output with this post, if you can look at it and see if I have some mistake or should do some improvement I would greatly appreciate it.

GPS
298095,25,16,-165,-12,24,122,-203,-3186,118,1933,1010.47,25.48,11,56,14,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298120,25,16,-165,-12,24,122,-203,-3186,118,1933,1010.47,25.48,11,56,14,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298143,23,16,-165,-12,24,122,-203,-3186,118,1933,1010.41,25.48,11,56,14,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298168,25,16,-165,-12,24,122,-203,-3186,118,1933,1010.41,25.48,11,56,14,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298192,24,16,-165,-12,24,122,-203,-3186,118,1933,1010.41,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298217,25,16,-165,-12,24,122,-203,-3181,110,1936,1010.41,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298241,24,16,-165,-12,24,122,-203,-3181,110,1936,1010.43,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298265,24,16,-165,-12,24,122,-203,-3181,110,1936,1010.43,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
GPS
298291,26,16,-165,-12,24,122,-203,-3181,110,1936,1010.43,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298314,23,16,-165,-12,24,122,-203,-3181,110,1936,1010.47,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298339,25,16,-165,-12,24,122,-203,-3181,110,1936,1010.47,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298363,24,16,-165,-12,24,122,-203,-3181,110,1936,1010.47,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298388,25,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298413,25,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298436,23,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298461,25,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
GPS
298486,25,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298510,24,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298534,24,16,-165,-12,24,122,-203,-3194,106,1935,1010.42,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298559,25,16,-165,-12,24,122,-203,-3194,114,1943,1010.45,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
298584,25,16,-165,-12,24,122,-203,-3194,114,1943,1010.45,25.48,11,56,15,599751748,-92467424,387037936,32,-44,55217,6942,110,11686,682,21118,3
GPS
OK
298609,25,16,-165,-12,24,122,-203,-3194,114,1943,1010.45,25.48,11,56,15,499753062,-92467417,387037857,14,-101,56675,8399,38,11755,536,21264,3
298633,24,16,-165,-12,24,122,-203,-3194,114,1943,1010.42,25.48,11,56,15,499753062,-92467417,387037857,14,-101,56675,8399,38,11755,536,21264,3
298657,24,16,-165,-12,24,122,-203,-3194,114,1943,1010.42,25.48,11,56,15,499753062,-92467417,387037857,14,-101,56675,8399,38,11755,536,21264,3
298682,25,16,-165,-12,24,122,-203,-3194,114,1943,1010.42,25.48,11,56,15,499753062,-92467417,387037857,14,-101,56675,8399,38,11755,536,21264,3
GPS
OK
298707,25,16,-165,-12,24,122,-203,-3192,116,1927,1010.41,25.48,11,56,15,599753207,-92467414,387037837,-27,-68,57085,8810,13,11761,466,21277,3
298732,25,16,-165,-12,24,122,-203,-3192,116,1927,1010.41,25.48,11,56,15,599753207,-92467414,387037837,-27,-68,57085,8810,13,11761,466,21277,3
298757,25,16,-165,-12,24,122,-203,-3192,116,1927,1010.41,25.48,11,56,15,599753207,-92467414,387037837,-27,-68,57085,8810,13,11761,466,21277,3
298781,24,16,-165,-12,24,122,-203,-3192,116,1927,1010.47,25.49,11,56,15,599753207,-92467414,387037837,-27,-68,57085,8810,13,11761,466,21277,3
GPS
OK
void loop() {
  // put your main code here, to run repeatedly:

  GPS_Read();

  if (millis() - timer >= 20) {
    dt = millis() - timer;
    timer = millis();
    counter++;

    if (rec) {
      //GPS_Cksm();
      GPS_Parse();
      rec = false;
    }

    if (counter > 5) {
      MAG_Read();
      PRS_Read();
    }

    File_Prt();
    Serial_Prt();
  }

  if (millis() > 300000) {
    File_Close();
    while (1) {}
  }
}




void GPS_Read() {
  while (Serial.available() > 0 && rec == false) {
    b = Serial.read();    //READ BYTE
    if (i > 0) {          //SEE IF WE ARE RECIEVING
      if (i == 91) {      //SEE IF WE ARE ENDING
        PVT[i] = b;
        i = 0;            //RESET BYTE COUNTER
        Serial.println("GPS");
        if (PVT[90] == cka && PVT[91] == ckb) {
          rec = true;       //SET RECIEVED FLAG IF CHECKSUM IS OK
          cka = 0;
          ckb = 0;
          Serial.println("OK");
        } else {
          cka = 0;
          ckb = 0;
        }
      } else {
        PVT[i] = b;       //ADD BYTE
        if (i != 90) {    //CALCULATE CHECKSUM
          cka = cka + b;
          ckb = ckb + cka;
        }
        i++;              //PROGRESS COUNTER
      }
    } else if (b == 0xB5) { //CHECK START BYTE
      PVT[i] = b;         //ADD BYTE
      i++;                //PROGRESS COUNTER
      b = Serial.read();  //READ SECOND BYTE
      if (b == 0x62) {    //CHECK SECOND BYTE
        PVT[i] = b;       //ADD BYTE
        i++;              //PROGRESS COUNTER
      } else {
        i = 0;            //RESET BYTE COUNTER
      }
    }
  }
}

Thank you again, and sorry for the bother.

new_try.ino (8.93 KB)

New Text Document.txt (1000 KB)

It looks like you're using Serial RX for the GPS and TX for the Serial Monitor (soon to be Xbee). I forgot to mention that they'd have to run at the same baud rate, but I guess you figured that out. :slight_smile:

Congrats on finally detecting the start-of-packet! In your previous code, if a byte was ever dropped, you would be "out-of-sync" with the packets. This would cause it to try to read the missing character from the next packet. But since you were asking for the next packet, the while loop would hang because another character will not arrive until another packet was requested.

You're still having trouble with blocking at the while loop in GPS_read.
Ah, yes! My mistake, that should be fine.

Cheers,
/dev


P.S. The PVT checksums are failing because you're printing too much info. Those Serial.print statements start blocking after queueing up the 64th character to print, which causes the GPS characters to overflow the input buffer. When a few bytes get dropped, the CS will fail. You have to print less. Comment most of it out for now, and we can revisit it later.

Hi,

I tried it with

while (Serial.available() > 0) {

it's the same,

while (Serial.available() > 0 && rec == false) {

should theoretically exit if either Serial available is 0 or rec is true, so it won't block there, will it?
I've commented out file printing and serial printing apart from a few things (timer, dt and type of fix, and GPS and OK), it's still the same (or worse for some reason):

274956,20,3
274976,20,3
274996,20,3
275016,20,3
275036,20,3
275056,20,3
275076,20,3
275096,20,3
275116,20,3
275136,20,3
275156,20,3
275176,20,3
275196,20,3
275216,20,3
275236,20,3
GPS
OK
275256,20,3
275276,20,3
275296,20,3
275316,20,3
275336,20,3
275356,20,3
275376,20,3
275396,20,3
275416,20,3
275436,20,3
275456,20,3
275476,20,3
275496,20,3
275516,20,3
275536,20,3
275556,20,3
275576,20,3
275596,20,3
275616,20,3
275636,20,3
GPS
OK
275656,20,3
275676,20,3
275696,20,3
275716,20,3
275736,20,3
275756,20,3
275776,20,3
275796,20,3
275816,20,3
275836,20,3
275856,20,3
275876,20,3
275896,20,3
275916,20,3
275936,20,3
275956,20,3
275976,20,3
275996,20,3
276016,20,3
276036,20,3
276056,20,3
276076,20,3
276096,20,3
276116,20,3

I've also tried it without reading any other sensors, it's much the same... I don't understand why it's so hard to get it syncing

Thank you

New Text Document (2).txt (282 Bytes)

DOH! Yes, that is non-blocking.

As you have noticed, the GPS PVT is not in sync with the other sensors. Right now, GPS_Read may have gotten a record, but the timer may not be up to 20ms yet.

The output shows 400ms between PVTs, which I don't understand. Did you configure it at 10Hz? There are some settings that will limit it to 5Hz... using NMEA protocol IIRC. Have you checked the configuration with ucenter? You might put a "dropped" counter in GPS_read that counts how many characters are dropped before it finds the 0xB5. Print it out once a second an reset the count? Maybe the wires are noisy? A Logic Analyzer would sure be nice about now... :wink:

Regarding printing: At 57600, each character takes 10 bit times, or 174us. In 20ms, you could write up to 57 characters. That's all. If you write any more than that (on average), the print will block. There is also the output buffer limit of 64 bytes, so bursts of more than 64 bytes would also block, even if you only did that once per second. :frowning: Your example is only writing 13 bytes/20ms, so I think that's ok for now.

You probably need to think about the sync issue. What do you want to happen when a PVT is dropped? Do the sensor records march on at 50Hz? Or, are you ok if there are 5 sensor records w/o GPS, then 1 record with GPS, and then 3 records w/o? You are expecting 4 w/o, 1 with, 4 w/o, 1 with... but is it ok to vary from that? Significantly?

The next step is to examine the file writing limitations. There may be times when the file write blocks in the same way that Serial was blocking. I don't see that in the output, but that could cause PVT corruption, too. SD has an internal buffer of 512 bytes, after which it blocks to write the buffer over the SPI. The blocking time for the cards varies quite a bit. You may have to take some measurements of its performance in order to know how to coordinate it with the rest of your sketch.

Having fun yet?

Cheers,
/dev

Hi,

Regarding the update rate I'm fairly sure that it is 10Hz as I'm disconnecting the Rx cable from u-center and connecting it to the GPS, while keeping everything else on the same place.

In an effort to improve the reception I've tried this:

void loop() {
  // put your main code here, to run repeatedly:

  GPS_Read();

  if (millis() - timer >= 20) {
    dt = millis() - timer;


    if (rec) {
      //GPS_Cksm();
      GPS_Parse();
      rec = false;
    }

    timer = millis();
    counter++;
    ACC_Read();
    GYR_Read();

    GPS_Read();

    if (counter > 5) {
      MAG_Read();
      PRS_Read();
    }

    GPS_Read();

    File_Prt();
    
    GPS_Read();

    Serial_Prt();
  }

  if (millis() > 300000) {
    File_Close();
    while (1) {}
  }
}

Which has improved the reception sometimes, though I still get some "blind" periods.

Would printing in HEX base instead of Dec save some time/bytes?

Regarding the sensors, I would like to keep them at or near 50Hz, i wouldn't mind however 40 Hz or the ocasional 40ms read time (as long as most loops are around 20-25ms), the gps is ok anywhere from 5-10Hz.

I'll look into the sd block issue

Thank you again!

New Text Document (3).txt (965 KB)

In 20ms, you could write up to 57 characters. That's all. If you write any more than that (on average), the print will block.

Um, your output text is way bigger than this at 150 characters. Lots of GPS data is getting lost. How about just writing dt for now. If you can get a steady stream of 20s, with GPS every 5, you can work back from there.

There's also some problems with GPS_Parse. Here's the specification for that message:

The header has 6 bytes, so to access fields of the message, you might try something like this:

      const uint8_t HDR = 6;

      uint8_t fixType = PVT[ HDR + 20];
      if ((2 <=fixType) && (fixType < 5)) {

        int32_t lat =  PVT[ HDR + 28]        +
                      (PVT[ HDR + 29] <<  8) +
                      (PVT[ HDR + 30] << 16) +
                      (PVT[ HDR + 31] << 24);

Now it's easy to see that you are accessing the fixType field at offset 20 and the lat field at offset 28 of the payload (i.e., the part past the header bytes). And that it's Little Endian format (see ublox M8 spec, section 21.3.5).

But even better than that, there is a memory-mapping technique that will eliminate all that shifting and adding. Because the Arduino is also Little-Endian, you can use a union of the PVT array and a struct that matches the field sizes in the spec. GPS_parse isn't actually needed, because the struct can get filled out by the received characters. Cool, no?

And yes, writing in base 16 takes fewer bytes than base 10. :slight_smile: In your final system, you could just write the binary values which takes half as many bytes as hex. It's messy for debugging, though.

Cheers,
/dev

Well thank you again, I will look into that memory mapping, and only printing GPS when I get new sentences (since it's just repeat info in the meantime).

I was aware of the header an was taking it into account (albeit in much less neat way).

The loops is currently

void loop() {
  // put your main code here, to run repeatedly:

  GPS_Read();

  if (millis() - timer >= 20) {
    dt = millis() - timer;


    if (rec) {
      //GPS_Cksm();
      GPS_Parse();
      rec = false;
      prt =true;
    }

    timer = millis();
    counter++;
    ACC_Read();
    GYR_Read();

    GPS_Read();

    if (counter > 5) {
      MAG_Read();
      PRS_Read();
    }

    GPS_Read();

    File_Prt();

        GPS_Read();
        
    if(prt){
      GPS_PrtSD();
    }else{
      file.println();
    }
    
    GPS_Read();

    Serial_Prt();
    
    if(prt){
      GPS_PrtSer();
      prt = false;
    }else{
      Serial.println();
    }
    
  }

  if (millis() > 300000) {
    File_Close();
    while (1) {}
  }
}

To print less, but next time I will try it with dt only as you said.

Right now I can't test the GPS but I will as soon as possible. I've tested it with no connection and it seems to work in burst, but I will check again with a connection.

Thanks for the help

Hi,
I figured out what (one of) the problem(s) was.

In the loop I was checking the second sync byte with serial.read without checking serial.available before, which is why it worked worse if I had nothing in the loop.

GPS_Read is now:

void GPS_Read() {
  while (Serial.available() > 0 && rec == false) {
    b = Serial.read();    //READ BYTE
    if (i > 1) {          //SEE IF WE ARE RECIEVING
      if (i == 91) {      //SEE IF WE ARE ENDING
        PVT[i] = b;
        i = 0;            //RESET BYTE COUNTER
        Serial.println("91");
        if (PVT[90] == cka && PVT[91] == ckb) {
          rec = true;       //SET RECIEVED FLAG IF CHECKSUM IS OK
          cka = 0;
          ckb = 0;
          Serial.println("OK");
        } else {
          cka = 0;
          ckb = 0;
        }
      } else {
        PVT[i] = b;       //ADD BYTE
        if (i != 90) {    //CALCULATE CHECKSUM
          cka = cka + b;
          ckb = ckb + cka;
        }
        i++;              //PROGRESS COUNTER
      }
    } else if (i == 0 && b == 0xB5) { //CHECK START BYTE
      Serial.println("GPS");
      PVT[i] = b;         //ADD BYTE
      i++;                //PROGRESS COUNTER

    } else if (i == 1 && b == 0x62) {    //CHECK SECOND BYTE
      Serial.println("GPS2");
      PVT[i] = b;       //ADD BYTE
      i++;              //PROGRESS COUNTER
    } else {
      i = 0;            //RESET BYTE COUNTER
    }
  }

  if (rec) {
    Serial.println("parse");
    rec = false;
  }
}

and the outputs:

20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
20
GPS
GPS2
91
OK
parse
20
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
91
OK
parse
20
20
20
20
20
GPS
GPS2
91
OK
parse
20
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
91
OK
parse
20
20
20
20
20
GPS
GPS2
20
91
OK
parse
20
20
20
20
GPS
GPS2
91
OK
parse
20
20
20
20
20
GPS
GPS2
91
OK

Now i'l look into getting it to work with the printing, and improving the parsing, you were talking about struct and unions can you point me to something about that?

Thanks again!

Hi,

Using the previous loop seen in the attached file I get good results, in 5 minutes recording I only have one "hole" of unknown origin, the average dt is 21 and there are only a few "spikes.

the hole:

39150,20,12,-169,-39,-16,-204,-128,-2117,-684,2967,1012.90,20.95,9,17,18,900151060,-92468545,387033230,-78,-431,140977,92702,-114,5615,420,6959,3
39176,26,1,-175,-41,-18,-203,-129,-2117,-684,2967,1012.90,20.95
39196,20,5,-164,-36,-18,-203,-127,-2117,-684,2967,1012.85,20.95
39216,20,2,-174,-40,-18,-203,-128,-2128,-679,2944,1012.85,20.95
39236,20,-3,-187,-41,-16,-204,-128,-2128,-679,2944,1012.85,20.95,9,17,19,151201,-92468562,387033229,-75,-453,140967,92692,-114,5622,421,6960,3
39261,25,4,-169,-34,-16,-203,-129,-2128,-679,2944,1012.85,20.95
39281,20,7,-191,-51,-16,-204,-128,-2128,-679,2944,1012.89,20.95
39301,20,0,-192,-43,-16,-203,-126,-2128,-679,2944,1012.89,20.95
[b]39360,59,5,-172,-40,-16,-204,-128,-2128,-679,2944,1012.91,20.96[/b]
39380,20,0,-182,-39,-18,-203,-129,-2114,-683,2946,1012.91,20.96
39400,20,1,-164,-37,-18,-204,-127,-2114,-683,2946,1012.91,20.96
39420,20,3,-170,-42,-17,-203,-128,-2114,-683,2946,1012.91,20.96
39440,20,-6,-174,-38,-17,-203,-127,-2114,-683,2946,1012.86,20.95
39460,20,10,-178,-46,-17,-204,-128,-2114,-683,2946,1012.86,20.95
39480,20,0,-191,-47,-16,-204,-127,-2114,-683,2946,1012.86,20.95
39500,20,-5,-173,-32,-17,-204,-130,-2114,-683,2946,1012.86,20.95
[b]39553,53,3,-175,-37,-16,-203,-128,-2110,-679,2947,1012.88,20.95[/b]
39573,20,11,-170,-46,-17,-203,-126,-2110,-679,2947,1012.88,20.95
39593,20,7,-193,-48,-17,-204,-128,-2110,-679,2947,1012.92,20.95
39613,20,-3,-192,-35,-18,-204,-128,-2110,-679,2947,1012.92,20.95
39633,20,-2,-169,-32,-17,-204,-128,-2110,-679,2947,1012.92,20.95
39653,20,-3,-185,-40,-15,-203,-127,-2110,-679,2947,1012.92,20.95
39673,20,12,-168,-42,-17,-205,-130,-2110,-679,2947,1012.92,20.96
39693,20,6,-181,-49,-17,-203,-127,-2110,-679,2947,1012.92,20.96
[b]39747,54,1,-174,-38,-17,-204,-128,-2117,-685,2952,1012.96,20.96[/b]
39767,20,10,-160,-45,-17,-204,-129,-2117,-685,2952,1012.96,20.96
39787,20,0,-174,-36,-17,-203,-129,-2117,-685,2952,1012.96,20.96
39808,21,0,-163,-34,-16,-203,-128,-2117,-685,2952,1012.96,20.96
39828,20,8,-163,-39,-17,-204,-127,-2117,-685,2952,1012.85,20.96
39848,20,-1,-178,-37,-17,-203,-130,-2117,-685,2952,1012.85,20.96
39868,20,-4,-177,-33,-16,-204,-127,-2125,-693,2958,1012.85,20.96
39888,20,2,-174,-41,-17,-205,-130,-2125,-693,2958,1012.85,20.96
39908,20,4,-170,-39,-16,-203,-129,-2125,-693,2958,1012.89,20.96
39928,20,0,-182,-42,-17,-203,-127,-2125,-693,2958,1012.89,20.96
39948,20,6,-174,-40,-17,-203,-129,-2125,-693,2958,1012.89,20.96,9,17,19,700152190,-92468593,387033217,-106,-438,141358,93083,-120,5684,422,6966,3
39972,24,3,-174,-38,-16,-203,-128,-2125,-693,2958,1012.89,20.96
39992,20,0,-176,-42,-17,-204,-131,-2125,-693,2958,1012.93,20.96
40012,20,1,-173,-39,-17,-204,-128,-2125,-693,2958,1012.93,20.96
40032,20,-5,-166,-29,-17,-203,-128,-2133,-695,2964,1012.93,20.96
40052,20,7,-172,-41,-15,-203,-128,-2133,-695,2964,1012.93,20.96,9,17,19,800152331,-92468590,387033217,-99,-427,141415,93140,-121,5693,423,6967,3
40077,25,1,-170,-37,-16,-203,-126,-2133,-695,2964,1012.93,20.96

In the would be bolded parts you can see the biggest "spikes" are in the "hole". Is this due to the serial or sd buffer overflow?

Regarding using a better timer is there a way to use an interrupt to read a time pulse signal from the gps?

Thank again!

sketch_apr06c.ino (9.44 KB)

Data05 - Copy.txt (1.09 MB)

I was checking the second sync byte with serial.read

LOL, totally missed that. I was glad that you were finally watching for the header. :slight_smile:

Is [the hole] due to the serial or sd buffer overflow?

It is almost certainly the SD writing the 512 buffer to the card. The bad news is that it took at least 40ms to do that (it missed two PVTs). The good news is that you have enough RAM that you will be able to double- or triple-buffer the incoming PVT records.

But first, you need to get the structure thang working.

Regarding using a better timer is there a way to use an interrupt to read a time pulse signal from the gps?

You don't really need the PPS signal, if that's what you're asking. There is a way to use an interrupt, but you need to get everything else working before stepping into that mess.

struct and unions can you point me to something about that?

Here's a good one. First, declare a struct that matches the PVT message spec. Then declare a union of (1) the 92-byte input buffer and (2) the struct. After all the bytes have been put into the buffer, you can simply access the struct members, without parsing.

This will also set the stage for the interrupt handling and triple-buffering.

Cheers,
/dev

Hi,

Something like this?

struct gps_t {
  
  uint8_t H1;
  uint8_t H2;
  uint8_t Class;
  uint8_t ID;
  uint16_t Length;
  uint32_t iTow;
  uint16_t Year;
  uint8_t Month;
  uint8_t Day;
  uint8_t Hour;
  uint8_t Min;
  uint8_t Sec;
  uint8_t valid;
  uint32_t tAcc;
  long nano;
  uint8_t fixType;
  uint8_t flags;
  uint8_t reserved1;
  uint8_t numSV;
  long lon;
  long lat;
  long height;
  long hMSL;
  uint32_t hAcc;
  uint32_t vAcc;
  long velN;
  long velE;
  long velD;
  long gSpeed;
  long headMot;
  uint32_t sAcc;
  uint32_t headAcc;
  uint16_t pDOP;
  uint8_t reserved2;
  uint8_t reserved2a;
  uint8_t reserved2b;
  uint8_t reserved2c;
  uint8_t reserved2d;
  uint8_t reserved2e;
  long headVeh;
  uint8_t reserved3;
  uint8_t reserved3a;
  uint8_t reserved3b;
  uint8_t reserved3c;
  uint8_t ck_a;
  uint8_t ck_b;  
};

union gps_u {
  uint8_t PVT[92];
  struct gps_t gps;
};

union gps_u GPS;

and then in the GPS_read()

void GPS_Read() {
  while (Serial.available() > 0 && rec == false) {
    b = Serial.read();    //READ BYTE
    if (i > 1) {          //SEE IF WE ARE RECIEVING
      if (i == 91) {      //SEE IF WE ARE ENDING
        PVT[i] = b;
        i = 0;            //RESET BYTE COUNTER
        if (PVT[90] == cka && PVT[91] == ckb) {
//          rec = true;       //SET RECIEVED FLAG IF CHECKSUM IS OK
          cka = 0;
          ckb = 0;
          for(i=0;i<91;i++){GPS.PVT[i]=PVT[i];}
          prt=true;
        } else {
          cka = 0;
          ckb = 0;
        }
      } else {
        PVT[i] = b;       //ADD BYTE
        if (i != 90) {    //CALCULATE CHECKSUM
          cka = cka + b;
          ckb = ckb + cka;
        }
        i++;              //PROGRESS COUNTER
      }
    } else if (i == 0 && b == 0xB5) { //CHECK START BYTE
      PVT[i] = b;         //ADD BYTE
      i++;                //PROGRESS COUNTER

    } else if (i == 1 && b == 0x62) {    //CHECK SECOND BYTE
      PVT[i] = b;       //ADD BYTE
      i++;              //PROGRESS COUNTER
    } else {
      i = 0;            //RESET BYTE COUNTER
    }
  }
}

and then print

void GPS_PrtSer() {
  Serial.print(",");
  Serial.print(GPS.gps.Hour);
  Serial.print(",");
  Serial.print(GPS.gps.Min);
  Serial.print(",");
  Serial.print(GPS.gps.Sec);
  Serial.print(",");
  Serial.print(GPS.gps.nano);
  Serial.print(",");
  Serial.print(GPS.gps.lon);
  Serial.print(",");
  Serial.print(GPS.gps.lat);
  Serial.print(",");
  Serial.print(GPS.gps.velN);
  Serial.print(",");
  Serial.print(GPS.gps.velE);
  Serial.print(",");
  Serial.print(GPS.gps.height);
  Serial.print(",");
  Serial.print(GPS.gps.hMSL);
  Serial.print(",");
  Serial.print(GPS.gps.velD);
  Serial.print(",");
  Serial.print(GPS.gps.hAcc);
  Serial.print(",");
  Serial.print(GPS.gps.sAcc);
  Serial.print(",");
  Serial.print(GPS.gps.vAcc);
  Serial.print(",");
  Serial.println(GPS.gps.fixType);
}

in

if (prt) {
      GPS_PrtSD();
      
    } else {
      file.println();
    }

    GPS_Read();

    Serial_Prt();

    if (prt) {
      GPS_PrtSer();
      prt = false;
    } else {
      Serial.println();
    }

I'll check if this works, won't the for loop take too long?

Edit: for some reason this makes me print only every two sentences...
Edit2: never mind i was using i in the for loop, i changed the for variable to ii and it solved the issue.

Thanks!

sketch_apr07a.ino (8.89 KB)