NEO6M GPS Data Loss

Hi, I am working on a flight computer program of a model rocket and I have some trouble with GPS data. I need some information (acceleration, angle, altitude, location etc.) to take some actions during the flight. The problem is that when I run the program, the first sentence of the GPS data comes up once and nothing follows it after that. The picture I attached and the code below will explain the problem better. The GPS module's data pins are connected to the pins 10 and 11 of my Arduino UNO and I am using SoftwareSerial for the GPS module because the HardwareSerial is being used by XBee modules to transmit the data. I used while(ss.available){...} command to get all the data the GPS module sends in a certain interval. May this be the reason -I do not think so though-? If not, what am I doing wrong? Thank you.

#include <Adafruit_BMP085.h> 
#include <MPU6050_tockn.h> 
#include <Wire.h>
#include <Servo.h> 
Servo servo1; 
Servo servo2;
Adafruit_BMP085 bmp; 
MPU6050 mpu6050(Wire); 
float base;
int alti, xangle, zangle, yacc, gpslat, gpslon;
#define rx 11 
#define tx  10 
#define gpsbaud 9600 
#define BuzzerPin  11 
#define buzzerdelay 100 //ms
#define buzzererrordelay 100 //ms
#define buzzerbeeptime 2 //times
#define startingaltitude 600 //m
#define delaytime 2000 //ms
#define thresholdangle 30 //degree
#define thresholdacc 0 //m/s^2
#define servoangle 180 //degree
#define seconderaltitude1 1000 //m
#define seconderaltitude2 700 //m
#define seconderaltitude3 600 //m
#define afterdeploytime 3000 //ms
#define safeacc -3 //m/s^2
#define groundaltitude 3 //m
#define servo1pin 9 
#define servo2pin 6 
#define servoinitialposition 90 //degree
#include <TinyGPS++.h> 
TinyGPSPlus gps; 
#include <SoftwareSerial.h> 
SoftwareSerial ss(rx, tx); 

void setup() {

  Serial.begin(9600); 
  ss.begin(gpsbaud); 
  Wire.begin(); 
  mpu6050.begin(); 
  mpu6050.calcGyroOffsets(true);
  servo1.write(servoinitialposition);
  servo2.write(servoinitialposition);
  servo1.attach(servo1pin); 
  servo2.attach(servo2pin);
  pinMode(BuzzerPin, OUTPUT); 
  digitalWrite(BuzzerPin, LOW); 
  if (bmp.begin()) { 
    Serial.println(); 
    Serial.println("BMP180 initialization successful"); 
    for (int i = 0; i <= buzzerbeeptime; i++) { 
      digitalWrite(BuzzerPin, HIGH); 
      delay(buzzerdelay); 
      digitalWrite(BuzzerPin, LOW); 
      delay(buzzerdelay); 
    }
  }

  else { 
    Serial.println(); 
    Serial.println(" --- Could not find a valid BMP180 sensor, check wiring! --- "); 
    digitalWrite(BuzzerPin, HIGH); 
    delay(buzzererrordelay); 
    digitalWrite(BuzzerPin, LOW);
  }
  base = bmp.readPressure(); 
  flight(); 
}

void loop() {} 

int getAltitude() {
  alti = round(bmp.readAltitude(base));
  Serial.print(F("MAIN: ")); 
  Serial.print(alti); 
  Serial.println(F("m")); 
  return alti; 
}

void getNMEA() {
  Serial.println(); 
  while (ss.available() > 0) {
    Serial.write(ss.read()); 
  }
  Serial.println(); 
}
int mpux() {
  mpu6050.update(); 
  xangle = abs(mpu6050.getAngleX()); 
  return xangle; 
}
int mpuz() { 
  mpu6050.update();
  zangle = abs(mpu6050.getAngleZ()); 
  return zangle; 
}
int mpuaccy() { 
  mpu6050.update(); 
  yacc = mpu6050.getAccY(); 
  return yacc; 
}

void flight () { 
s1: delay(delaytime); getAltitude(); getNMEA();
  Serial.print(F("MAIN: <=")); Serial.print(startingaltitude); Serial.print(F("m ")); Serial.print(F("(")); Serial.print(alti); Serial.println(F("m)"));
  if (alti > startingaltitude) { 
    Serial.print(F("MAIN: THRESHOLD ALTITUDE EXCEEDED ")); Serial.print(F("(>")); Serial.print(startingaltitude); Serial.print(F("m)"));
s2: delay(delaytime); mpuaccy(); getAltitude(); getNMEA(); 
    if ( yacc < thresholdacc) { 
      Serial.println(F("MAIN: ACCELERATION THRESHOLD EXCEEDED, SLOWING DOWN"));
s3: delay(delaytime); mpux(); mpuz(); getAltitude(); getNMEA(); 
      if ( xangle > thresholdangle || zangle > thresholdangle) { 
        Serial.print(F("MAIN: ")); Serial.print(thresholdangle); Serial.println(F(" DEGREE DETECTED, MAIN 1 EJECTING"));
        servo1.write(servoangle); 
        delay(afterdeploytime); 
s4: delay(delaytime); getAltitude(); getNMEA(); 
        if (alti < seconderaltitude1) { 
          Serial.print(F("MAIN: ALTITUDE <=")); Serial.print(seconderaltitude1); Serial.print(F("m"));
s5: delay(delaytime); getAltitude(); getNMEA(); 
          if (alti < seconderaltitude2) { 
            Serial.print(F("MAIN: ALTITUDE <=")); Serial.print(seconderaltitude2); Serial.print(F("m"));
s6: delay(delaytime); getAltitude(); getNMEA(); 
            if (alti < seconderaltitude3) { 
              Serial.print(F("MAIN: ALTITUDE <=")); Serial.print(seconderaltitude3); Serial.print(F("m, MAIN 2 EJECTING"));
              servo2.write(servoangle); 
              delay(afterdeploytime); 
s7: delay(delaytime); mpuaccy(); getAltitude(); getNMEA(); 
              if (yacc > safeacc) { 
                Serial.print(F("MAIN: ACCELERATION ")); Serial.print(yacc); Serial.println(F("m/s^2, SAFE"));
s8: delay(delaytime); getAltitude(); getNMEA();  
                if (alti < groundaltitude) { 
                  getAltitude(); getNMEA(); 
                  Serial.println(F("MAIN: LANDED"));
                }
                else { 
                  goto s8; 
                }
              }
              else { 
                Serial.print(F("MAIN: ACCELERATION "));
                Serial.print(yacc);
                Serial.println(F("m/s^2, HIGH ACCELERATION"));
                goto s7; 
              }
            }
            else { 
              goto s6; 
            }
          }
          else {
            goto s5;
          }
        }
        else {
          goto s4; 
        }
      }
      else { 
        goto s3; 
      }
    }
    else { 
      goto s2; 
    }
  }
  else { 
    goto s1; 
  }
}

Reduce the program to a minimum, get rid of 95% (or more) of the code and prove to yourself you can read the characters from the GPS, encode them, and print out the location and altitude etc.

The code you posted is very difficult to read and understand, did you write it all yourself ?

srnet:
Reduce the program to a minimum, get rid of 95% (or more) of the code and prove to yourself you can read the characters from the GPS, encode them, and print out the location and altitude etc.

The code you posted is very difficult to read and understand, did you write it all yourself ?

Hi, thanks for the reply! How can I prove that I can read the character from the GPS? And I actually do not want to encode the GPS data, I want to get the GPS data in NMEA format so that I can use Earth Bridge software to get a location on a map. But if things go so hard, I may consider getting and using latitude and longitude data only.

The code was all written by me, with help of some example codes. I think it is not difficult to understand, I would like to shorten it but all the rows are connected to each other somehow. So, I think I should not remove any row to keep it logical.

You can look into the getNMEA() and flight() only if it will be better to extract the problem. Thank you very much for your interest :slight_smile:

How can I prove that I can read the character from the GPS?

To verify that intact, valid NMEA sentences are read, validate the checksum on each sentence.

  1. Use of delay() as shown below guarantees that you will miss GPS characters and have invalid sentences.
s2: delay(delaytime); mpuaccy(); getAltitude(); getNMEA();
  1. It is bad programming practice to use goto statements. Learn to use control structures instead.

  2. Add comments. Six months from now you won't remember what you did.

jremington:
To verify that intact, valid NMEA sentences are read, validate the checksum on each sentence.

Thanks for your reply, I will check it.

jremington:

  1. Use of delay() as shown below guarantees that you will miss GPS characters and have invalid sentences.
s2: delay(delaytime); mpuaccy(); getAltitude(); getNMEA();

I have read it many times. So, should we catch the GPS data when the GPS module sends them? How can I get the last GPS data whenever I want? Can I buffer them for a while?

jremington:
2. It is bad programming practice to use goto statements. Learn to use control structures instead.

I know. I would like to do that but I have a really limited time and I should let well enough alone.

jremington:
3. Add comments. Six months from now you won't remember what you did.

I have done it in my original code. I translated the code into English so that you can understand it better and removed the command lines :slight_smile:

So, should we catch the GPS data when the GPS module sends them?

Yes. There is a small buffer built in to the serial routines, but if you allow it to overflow, data are lost forever.

You need to expunge this nonsense:

            else {
              goto s6;
            }
          }
          else {
            goto s5;
          }
        }
        else {
          goto s4;
        }
      }
      else {
        goto s3;
      }
    }
    else {
      goto s2;
    }
  }
  else {
    goto s1;
  }
}

yusufbudakli:
I think it is not difficult to understand.

Well you wrote it, so know what the structure of the should be and what it is supposed to be doing. And if it works then thats fine.

But now you want help, which means the code has to be clear and easy to understand so that the volunteers on this forum can quickly give you assistance.

aarg:
You need to expunge this nonsense:

            else {

goto s6;
            }
          }
          else {
            goto s5;
          }
        }
        else {
          goto s4;
        }
      }
      else {
        goto s3;
      }
    }
    else {
      goto s2;
    }
  }
  else {
    goto s1;
  }
}

Aaa, will the code work the same when I expunge these?

srnet:
Well you wrote it, so know what the structure of the should be and what it is supposed to be doing. And if it works then thats fine.

But now you want help, which means the code has to be clear and easy to understand so that the volunteers on this forum can quickly give you assistance.

Okay, sorry for making things hard for you. Hope this is better:

#include <Adafruit_BMP085.h> 
#include <Wire.h>
Adafruit_BMP085 bmp; 
float base;
int alti;
#define rx 11 
#define tx  10 
#define gpsbaud 9600
#define startingaltitude 600 //m
#define delaytime 2000 //ms
#include <TinyGPS++.h> 
TinyGPSPlus gps; 
#include <SoftwareSerial.h> 
SoftwareSerial ss(rx, tx); 

void setup() {

  Serial.begin(9600); 
  ss.begin(gpsbaud);
  base = bmp.readPressure(); 
  flight(); 
}

void loop() {} 

int getAltitude() {
  alti = round(bmp.readAltitude(base));
  Serial.print(F("MAIN: ")); 
  Serial.print(alti); 
  Serial.println(F("m")); 
  return alti; 
}

void getNMEA() {
  Serial.println(); 
  while (ss.available() > 0) {
    Serial.write(ss.read()); 
  }
  Serial.println(); 
}

void flight () { 
s1: delay(delaytime); getNMEA();
  Serial.print(F("MAIN: <=")); Serial.print(startingaltitude); Serial.print(F("m ")); Serial.print(F("(")); Serial.print(alti); Serial.println(F("m)"));
  if (alti > startingaltitude) { 
    Serial.print(F("MAIN: THRESHOLD ALTITUDE EXCEEDED ")); Serial.print(F("(>")); Serial.print(startingaltitude); Serial.print(F("m)"));
s2: delay(delaytime); getNMEA();
  }
  else { 
    goto s1; 
  }
}

Thanks for deleting all those goto but I think you broke it.

For example getAltitude never gets called now.

What is this version supposed to do?

wildbill:
Thanks for deleting all those goto but I think you broke it.

For example getAltitude never gets called now.

What is this version supposed to do?

Hi, thanks for replying! The problem is actually about the getNMEA(). I did not delete the getAltitude() because it is kind of relevant to the problem. When the flight() is begun, I should get an altitude data, GPS data and another altitude data. When I run the code, these are done well for once, no more. I thought that the problem may be caused by the if statement which checks if alti is bigger than startingaltitude, by missing GPS data transmission or something else I could not consider. That is why I did not remove the getAltitude(), even though it is not used in the recent, cut code. I just want to make you understand that I need full GPS data during all the flight, and there are some conditions to take some actions during the flight. Even though the actions are taken in the relevant conditions, I need to continue getting full GPS data, from the beginning of the flight to the end of it. Since the flight parameters are continuously checked to be matched with the conditions, I could not set an appropriate interval allowing getting the GPS data on time. At least, that is what I understood from the problem.

yusufbudakli:
Aaa, will the code work the same when I expunge these?

If you do it correctly, yes. Of course, you can't just remove them. You have to figure out what normal, built in feature of C would normally be used instead of that horror.

aarg:
If you do it correctly, yes. Of course, you can't just remove them. You have to figure out what normal, built in feature of C would normally be used instead of that horror.

But the code is in setup, not in loop. Are the functions repeated from the beginning while the if statement's condition is not matched? That is why I used goto functions. What built in feature of C is normally used instead of those?

Put code that is to run repeatedly in loop().

jremington:
Put code that is to run repeatedly in loop().

Okay, but, for example;

delay(delaytime); getAltitude(); getNMEA();
  Serial.print(F("MAIN: <=")); Serial.print(startingaltitude); Serial.print(F("m ")); Serial.print(F("(")); Serial.print(alti); Serial.println(F("m)"));
  if (alti > startingaltitude) { 
    Serial.print(F("MAIN: THRESHOLD ALTITUDE EXCEEDED ")); Serial.print(F("(>")); Serial.print(startingaltitude); Serial.print(F("m)"));

let's look at the text "MAIN: THRESHOLD ALTITUDE EXCEEDED". I want it to appear once when the threshold altitude is exceeded. And if I wrote the code in loop, it appears continuously while the altitude is bigger than the threshold altitude, doesn't it? I think I can manage this by adding a kind of switch which is set to 1 in the beginning, and will be changed to 0 when the function responsible for printing the text "MAIN: THRESHOLD ALTITUDE EXCEEDED" out runs once, the function will not print that text more than once since the switch will be set to 0 in the end of the first run. But is there any better and shorter way to do this?

The code with switches is below, can/should I improve it?

//aspan rocket team main flight program
#include <Adafruit_BMP085.h>
#include <MPU6050_tockn.h>
#include <Wire.h> 
#include <Servo.h> 
Servo servo1; 
Servo servo2; 
Adafruit_BMP085 bmp;
MPU6050 mpu6050(Wire); 
float base; 
bool altitudeswitch = 1;
bool accswitch = 1;
bool apogeeswitch = 1;
bool seconderswitch1 = 1;
bool seconderswitch2 = 1;
bool seconderswitch3 = 1;
int alti, xangle, zangle, yacc, gpslat, gpslon; 
#define rx 11 
#define tx  10 
#define gpsbaud 9600 
#define BuzzerPin  11 
#define buzzerdelay 100 
#define buzzererrordelay 100 
#define buzzerbeeptime 2 
#define startingaltitude 600 
#define delaytime 2000 
#define thresholdangle 30 
#define thresholdacc 0 
#define servoangle 180 
#define seconderaltitude1 1000 
#define seconderaltitude2 700
#define seconderaltitude3 600 
#define afterdeploytime 3000 
#define safeacc -3 
#define groundaltitude 3 
#define servo1pin 9 
#define servo2pin 6 
#define servoinitialposition 90 
#include <TinyGPS++.h> 
TinyGPSPlus gps; 
#include <SoftwareSerial.h> 
SoftwareSerial ss(rx, tx); 

void setup() {

  Serial.begin(9600);
  ss.begin(gpsbaud); 
  Wire.begin();
  mpu6050.begin(); 
  mpu6050.calcGyroOffsets(true);
  servo1.write(servoinitialposition); 
  servo2.write(servoinitialposition); 
  servo1.attach(servo1pin); 
  servo2.attach(servo2pin); 
  pinMode(BuzzerPin, OUTPUT); 
  digitalWrite(BuzzerPin, LOW); 
  if (bmp.begin()) { 
    Serial.println(); 
    Serial.println("BMP180 initialization successful"); 
    for (int i = 0; i <= buzzerbeeptime; i++) {
      digitalWrite(BuzzerPin, HIGH); 
      delay(buzzerdelay); 
      digitalWrite(BuzzerPin, LOW); 
      delay(buzzerdelay); 
    }
  }

  else { 
    Serial.println(); 
    Serial.println(" --- Could not find a valid BMP180 sensor, check wiring! --- "); 
    digitalWrite(BuzzerPin, HIGH); 
    delay(buzzererrordelay); 
    digitalWrite(BuzzerPin, LOW); 
  }
  base = bmp.readPressure(); 
}

void loop() {

  delay(delaytime); getAltitude(); getNMEA(); 
  Serial.print(F("MAIN: <=")); Serial.print(startingaltitude); Serial.print(F("m ")); Serial.print(F("(")); Serial.print(alti); Serial.println(F("m)"));
  if (alti > startingaltitude) { 
    if (altitudeswitch = 1) {
      Serial.print(F("MAIN: STARTING ALTITUDE EXCEEDED "));
      Serial.print(F("(>"));
      Serial.print(startingaltitude);
      Serial.println(F("m)"));
      altitudeswitch = 0;
    }
    delay(delaytime); mpuaccy(); getAltitude(); getNMEA(); 
    if ( yacc < thresholdacc) { 
      if (accswitch = 1) {
        Serial.println(F("MAIN: ACCELERATION THRESHOLD EXCEEDED, SLOWING DOWN"));
        accswitch = 0;
      }
      delay(delaytime); mpux(); mpuz(); getAltitude(); getNMEA(); 
      if ( xangle > thresholdangle || zangle > thresholdangle) { 
        if (apogeeswitch = 1) {
          Serial.print(F("MAIN: ")); Serial.print(thresholdangle); Serial.println(F(" DEGREE, MAIN 1 EJECTING"));
          servo1.write(servoangle); 
          delay(afterdeploytime); 
          apogeeswitch = 0;
        }
        delay(delaytime); getAltitude(); getNMEA();
        if (alti < seconderaltitude1) { 
          if (seconderswitch1 = 1) {
            Serial.print(F("MAIN: ALTITUDE <="));
            Serial.print(seconderaltitude1);
            Serial.println(F("m"));
            seconderswitch1 = 0;
          }
          delay(delaytime); getAltitude(); getNMEA(); 
          if (alti < seconderaltitude2) { 
            if (seconderswitch2 = 1) {
              Serial.print(F("MAIN: ALTITUDE <=")); Serial.print(seconderaltitude2); Serial.println(F("m")); seconderswitch2 = 0;
            }
            delay(delaytime); getAltitude(); getNMEA(); 
            if (alti < seconderaltitude3) {
              if (seconderswitch3 = 1) {
                Serial.print(F("MAIN: ALTITUDE <=")); Serial.print(seconderaltitude3); Serial.print(F("m, MAIN 2 EJECTING"));
                servo2.write(servoangle); 
                delay(afterdeploytime); 
                seconderswitch3 = 0;
              }
              delay(delaytime); mpuaccy(); getAltitude(); getNMEA();
              if (yacc > safeacc) { 
                Serial.print(F("MAIN: ACCELERATION ")); Serial.print(yacc); Serial.println(F("m/s^2, SAFE FLIGHT"));
                delay(delaytime); getAltitude(); getNMEA();  
                if (alti < groundaltitude) {
                  getAltitude(); getNMEA(); 
                  Serial.println(F("MAIN: LANDED"));
                  while(1){}
                }
              }
              else { 
                Serial.print(F("MAIN: ACCELERATION "));
                Serial.print(yacc);
                Serial.println(F("m/s^2, HIGH ACCELERATION"));
              }
            }
          }
        }
      }
    }
  }


}

int getAltitude() { 
  alti = round(bmp.readAltitude(base)); 
  Serial.print(F("MAIN: ")); 
  Serial.print(alti); 
  Serial.println(F("m")); 
  return alti; 
}

void getNMEA() { 
  Serial.println(); 
  while (ss.available() > 0) { 
    Serial.write(ss.read()); 
  }
  Serial.println();
}
int mpux() { 
  mpu6050.update(); 
  xangle = abs(mpu6050.getAngleX()); 
  return xangle; 
}
int mpuz() { 
  mpu6050.update(); 
  zangle = abs(mpu6050.getAngleZ()); 
  return zangle;
}
int mpuaccy() { 
  mpu6050.update();
  yacc = mpu6050.getAccY();
  return yacc;
}

Can I use SerialEvent with SoftwareSerial? Does it catch the GPS data when it comes and continue getting them until they are all sent? Or is there any command that listens to the serial port and starts another command when the data starts being sent?

So, is your help made up of pushing me to obey the forum rules 100% instead of giving advices about my problem? Am I in a Debian forum or an Arduino one?