Getting weird output from NEO6m GPS

Hi!

I am trying to fuse my NEO6m GPS code with my working drone code, but it is not working as planned. I am getting a weird output that I cannot manage to understand, the output in the fused program looks like this:


GGA,,,,09.9G,14⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9A90⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9$9,6⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9S90⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9,9*⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9A90
GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9S90⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9S,0⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9,9*⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9A,7⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9,91N⸮GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.89SF⸮$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,,$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,A9*$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9P$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99$,,4$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9$$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9G$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,A97$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9L$GRC,,,,,,N5
$PT,,,,,*0
GGA,,,,09.9G9,
$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9G$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99*,PV$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,A90,$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,S9*$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,S.,$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,99$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9
$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,9
$PM,V,,,,,*3
GVG,,,,N3
$PG,,,00,99,,3L$PM,V,,,,,*3

And my output looks like this in my working gps tester:


Neo6M GPS module test code
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,4,1,14,02,,,09,03,,,09,04,,,09,05,,,09*79
$GPGSV,4,2,14,06,,,22,07,,,19,09,,,21,11,,,22*79
$GPGSV,4,3,14,12,,,23,13,,,09,14,,,10,16,,,23*70
$GPGSV,4,4,14,17,,,21,23,,,21*7B
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,04,06,,,18,07,,,17,12,,,20,23,,,19*7B
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,01,23,,,12*7A
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,01,23,,,10*78
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,01,23,,,08*71
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30

I am missing the $GPGGA and the other ones in the fuesd program. What does that mean?

Thanks in advance
Best regards Max

No satellite fix. Take it outside to where you have a clear view of the sky. You may have to wait several minutes for a valid fix.

1 Like

Cloud you reveal exactly what you are using to read the GPS ?

The output appears to be missing characters some how.

1 Like

Here is the code that I am trying to fuse into my drone code:

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

SoftwareSerial ss(3, 2); // RX, TX

TinyGPSPlus gps;

void setup()
{
   // Open serial communications
   Serial.begin(115200);
   Serial.println("Neo6M GPS module test code");
   // set the data rate for the SoftwareSerial port
   ss.begin(9600);
}

void loop()
{
   if (s.available())
   {
      Serial.print(char(ss.read()));
   }
}

And here is my drone code:

#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <Servo.h>
#include <nRF24L01.h>
#include <SPI.h>
#include <RF24.h>
#include <printf.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

#define CE_PIN   9
#define CSN_PIN 10

//Create GPS Reader
SoftwareSerial ss(3, 2); // RX, TX

//GPS encoder
TinyGPSPlus gps;

// Create Radio and define pins
RF24 radio(CE_PIN, CSN_PIN);

// Create Radio channels
const uint64_t pAddress = 0xB00B1E5000LL;

// Create a boolean for connection lost
bool lostConnection = false;

//Radio recived array
float recivedDataArray[4];
bool temp = true;

// Create timer
float elapsedTime, time, timePrev;
long loop_timer;
float previousMessageMillis;

Servo motor_LF;
Servo motor_RF;
Servo motor_LB;
Servo motor_RB;

Adafruit_BNO055 bno = Adafruit_BNO055(-1, 0x28);

bool setZeroBool = true;
float pitchOffset = 0, rollOffset = 0;
float input_throttle = 1000;
float input_yaw = 0;
float input_pitch = 0;
float input_roll = 0;

/* Roll PID */
float roll_PID, pid_throttle_L_F, pid_throttle_L_B, pid_throttle_R_F, pid_throttle_R_B, roll_error, roll_previous_error;
float roll_pid_p = 0;
float roll_pid_i = 0;
float roll_pid_d = 0;
/* Roll PID Constants */
double roll_kp = 0.5;
double roll_ki = 0.03;
double roll_kd = 20;
float roll_desired_angle = 0;

/* Pitch PID */
float pitch_PID, pitch_error, pitch_previous_error;
float pitch_pid_p = 0;
float pitch_pid_i = 0;
float pitch_pid_d = 0;
/* Pitch PID Constants */
double pitch_kp = roll_kp;
double pitch_ki = roll_ki;
double pitch_kd = roll_kd;
float pitch_desired_angle = 0;


/* Yaw PID */
float yaw_PID, yaw_error, yaw_previous_error;
float yaw_pid_p = 0;
float yaw_pid_i = 0;
float yaw_pid_d = 0;
/* Pitch PID Constants */
double yaw_kp = 0.5;
double yaw_ki = 0;
double yaw_kd = 5;
float yaw_desired_angle = 0;

int yaw_pid_max = 200;
int pid_max = 400;

//GPS Variables
float longitude = 0;
float latitude = 0;
void setup() {
  Serial.begin(115200);
  ss.begin(9600);
  Wire.begin();
  
  while (!Serial);
  printf_begin();

  if(!bno.begin())
  {
    Serial.print("Error, no BNO055 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }

  int8_t temp = bno.getTemp();
  bno.setExtCrystalUse(true);

  delay(1000);

  if (!radio.begin()) {
    Serial.println(F("radio hardware is not responding!!"));
    while (1) {}
  }
  radio.setPALevel(RF24_PA_MAX);
  radio.openReadingPipe(1, pAddress);

  //radio.printDetails();
  radio.startListening();

  delay(5000);

  motor_LF.attach(5);
  motor_RF.attach(6);
  motor_LB.attach(7);
  motor_RB.attach(8);

  motor_LF.writeMicroseconds(1000);
  motor_RF.writeMicroseconds(1000);
  motor_LB.writeMicroseconds(1000);
  motor_RB.writeMicroseconds(1000);

}
void loop() {
  if (ss.available()) {
    Serial.print(char(ss.read()));
    gps.encode(ss.read());
    
    if (gps.location.isUpdated()) {
      Serial.print("Latitude= ");
      Serial.print(gps.location.lat(), 6);
      Serial.print(" Longitude= ");
      Serial.println(gps.location.lng(), 6);
    }
  }

  imu::Vector<3> gyro = bno.getVector(Adafruit_BNO055::VECTOR_EULER);

  if (!lostConnection) {
    if (radio.available()) {
      radio.read( &recivedDataArray, sizeof(recivedDataArray) );
      //Serial.println("Recieved array:");
      previousMessageMillis = millis();
      for (byte i = 0; i < 4; i++) {
        //Serial.println(recivedDataArray[i]);
      }
      input_throttle = recivedDataArray[0];
      //yaw_desired_angle += recivedDataArray[1];
      pitch_desired_angle = -recivedDataArray[2] + pitchOffset;
      roll_desired_angle = -recivedDataArray[3] + rollOffset;
      //Serial.println();
    }

    if (input_throttle > 1600) {
      input_throttle = 1600;
    } else if (input_throttle < 1050) {
      input_throttle = 1000;
    }

    if (setZeroBool) {
      pitchOffset = gyro.y();
      rollOffset = gyro.z();
      yaw_desired_angle = gyro.x();

      setZeroBool = false;
    }

    PIDControl(gyro.x(), gyro.y(), gyro.z());

    /* Start Timer */
    timePrev = time;
    time = millis();
    elapsedTime = (time - timePrev) / 1000;

    if (millis() - previousMessageMillis >= 400) {
      lostConnection = false;
      PID_reset();
      motor_LF.writeMicroseconds(1000);
      motor_RF.writeMicroseconds(1000);
      motor_LB.writeMicroseconds(1000);
      motor_RB.writeMicroseconds(1000);
    } else {
      motor_LF.writeMicroseconds(pid_throttle_L_F);
      motor_RF.writeMicroseconds(pid_throttle_R_F);
      motor_LB.writeMicroseconds(pid_throttle_L_B);
      motor_RB.writeMicroseconds(pid_throttle_R_B);
    }

    //print_gps();
    //print_roll_pitch_yaw(gyro.x(), gyro.y(), gyro.z());
    //printDesiredAngles();
    //print_PID();
    //print_throttle();
    //print_detailed_PID();
  } else {
    PID_reset();
    Serial.println("LOST CONNECTION!");
    delay(2000);
  }

  delay(10);
}
void PIDControl(float x, float y, float z) {
  if (input_throttle > 1050) {
    /* PID */
    roll_error = roll_desired_angle - z;
    pitch_error = pitch_desired_angle - y;

    if (x > 0 && x < 180) {
      yaw_error = yaw_desired_angle - x;
    } else if (x > 180 && x < 360) {
      yaw_error = yaw_desired_angle - map(x, 180, 360, -180, 0);
    }

    /* Prospect */
    roll_pid_p = roll_kp * roll_error;
    pitch_pid_p = pitch_kp * pitch_error;
    yaw_pid_p = yaw_kp * yaw_error;

    // Integral
    roll_pid_i += roll_ki * roll_error;
    pitch_pid_i += pitch_ki * pitch_error;
    yaw_pid_i += yaw_ki * yaw_error;

    // Derivate
    roll_pid_d = roll_kd * (roll_error - roll_previous_error);
    pitch_pid_d = pitch_kd * (pitch_error - pitch_previous_error);
    yaw_pid_d = yaw_kd * (yaw_error - yaw_previous_error);

    //ROLL
    if (roll_pid_i > pid_max) roll_pid_i = pid_max;
    else if (roll_pid_i < pid_max * -1)
      roll_pid_i = pid_max * -1;

    roll_PID = roll_pid_p + roll_pid_i + roll_pid_d;
    if (roll_PID > pid_max) roll_PID = pid_max;
    else if (roll_PID < pid_max * -1)
      roll_PID = pid_max * -1;

    //PITCH
    if (pitch_pid_i > pid_max) pitch_pid_i = pid_max;
    else if (pitch_pid_i < pid_max * -1)
      pitch_pid_i = pid_max * -1;

    pitch_PID = pitch_pid_p + pitch_pid_i + pitch_pid_d;
    if (pitch_PID > pid_max) pitch_PID = pid_max;
    else if (pitch_PID < pid_max * -1)
      pitch_PID = pid_max * -1;


    //YAW
    if (yaw_pid_i > yaw_pid_max) yaw_pid_i = yaw_pid_max;
    else if (yaw_pid_i < yaw_pid_max * -1)
      yaw_pid_i = yaw_pid_max * -1;

    yaw_PID = yaw_pid_p + yaw_pid_i + yaw_pid_d;
    if (yaw_PID > yaw_pid_max) yaw_PID = yaw_pid_max;
    else if (yaw_PID < yaw_pid_max * -1)
      yaw_PID = yaw_pid_max * -1;

    /* Set the throttle PID for each motor */
    pid_throttle_L_F = input_throttle - roll_PID + pitch_PID - yaw_PID;
    pid_throttle_R_F = input_throttle + roll_PID + pitch_PID + yaw_PID;
    pid_throttle_L_B = input_throttle - roll_PID - pitch_PID + yaw_PID;
    pid_throttle_R_B = input_throttle + roll_PID - pitch_PID - yaw_PID;

    /* Save Previous Error */
    roll_previous_error = roll_error;
    pitch_previous_error = pitch_error;
    yaw_previous_error = yaw_error;

    /* Regulate throttle for ESCs */
    //Right front
    if (pid_throttle_R_F < 1100) {
      pid_throttle_R_F = 1100;
    }
    if (pid_throttle_R_F > 2000) {
      pid_throttle_R_F = 2000;
    }

    //Left front
    if (pid_throttle_L_F < 1100) {
      pid_throttle_L_F = 1100;
    }
    if (pid_throttle_L_F > 2000) {
      pid_throttle_L_F = 2000;
    }

    //Right back
    if (pid_throttle_R_B < 1100) {
      pid_throttle_R_B = 1100;
    }
    if (pid_throttle_R_B > 2000) {
      pid_throttle_R_B = 2000;
    }

    //Left back
    if (pid_throttle_L_B < 1100) {
      pid_throttle_L_B = 1100;
    }
    if (pid_throttle_L_B > 2000) {
      pid_throttle_L_B = 2000;
    }
  } else {
    PID_reset();
  }
}

void PID_reset() {
  pid_throttle_L_F = 1000;
  pid_throttle_L_B = 1000;
  pid_throttle_R_F = 1000;
  pid_throttle_R_B = 1000;

  pitch_PID = 0, roll_PID = 0, yaw_PID = 0;
  roll_error = 0, pitch_error = 0, yaw_error = 0;
 
  roll_previous_error = 0, pitch_previous_error = 0, yaw_previous_error = 0;
  
  roll_pid_p = 0, pitch_pid_p = 0;
  roll_pid_i = 0, pitch_pid_i = 0;
  roll_pid_d = 0, pitch_pid_d = 0;

  pitch_pid_p = 0, pitch_pid_p = 0;
  pitch_pid_i = 0, pitch_pid_i = 0;
  pitch_pid_d = 0, pitch_pid_d = 0;
}
void print_roll_pitch_yaw(float x, float y, float z) {
  Serial.print(z);
  Serial.print(", ");
  Serial.println(y);
}

void printDesiredAngles() {
  Serial.print(roll_desired_angle);
  Serial.print(", ");
  Serial.println(pitch_desired_angle);
}

void print_throttle() {
  Serial.print(pid_throttle_L_F);
  Serial.print("   ");
  Serial.println(pid_throttle_R_F);
  Serial.print(pid_throttle_L_B);
  Serial.print("   ");
  Serial.println(pid_throttle_R_B);
  Serial.println();
}

void print_PID() {
  Serial.print(roll_PID);
  Serial.print(", ");
  Serial.print(pitch_PID);
  Serial.print(", ");
  Serial.println(yaw_PID);
}

void print_detailed_PID() {
  Serial.print(pitch_pid_p);
  Serial.print(", ");
  Serial.print(pitch_pid_i);
  Serial.print(", ");
  Serial.print(pitch_pid_d);
  Serial.print(", ");
  Serial.println(pitch_PID);
}

void print_gps() {
  Serial.print("Longitude: ");
  Serial.print(longitude);
  Serial.print("  :   Latitude: ");
  Serial.println(latitude);
  }

I believe that SoftwareSerial and the servo library have a timer conflict and can't be used together.

To avoid that, ServoTimer2 was written.

Not very clear.

Where is the actual code that produced the corrupted output that you posted ?

It is this part, first if statement in the loop()

if (ss.available()) {

    Serial.print(char(ss.read()));

    gps.encode(ss.read());

    

    if (gps.location.isUpdated()) {

      Serial.print("Latitude= ");

      Serial.print(gps.location.lat(), 6);

      Serial.print(" Longitude= ");

      Serial.println(gps.location.lng(), 6);

    }

  }

I tried swapping when you said it but I get the same result...

So you read a character from the GPS, then print it out.

Read the next caracter from the GPS, then send it to gps.encode();

Read the next caracter from the GPS, then print it out.

See the problem ?

How do I solve this? Do the read after the encode?

Read a GPS character, if available, into a variable.
Print the varaible
Encode the variable
Etc.

I tried removing the gps.encode and now I am getting this output:

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99. ,P,$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.,,

L$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99. 9VV$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.

.,V$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

Its much better, but I still think that its a bit off fully working with two "$" symbols on the same line. Is that the timer perhaps? Tried this with ServoTimer2 but doesnt work....

  1. Post the revised code
  2. Define "doesn't work"
  3. Go outside to get a satellite fix

If you want to echo the 'ss' input to 'Serial' AND pass it to gps.encode() you have to read it into a variable and pass the variable to both. You can't call ss.read() twice and expect to get the same character.

  if (ss.available()) {
    char c = ss.read();
    Serial.print(c);
    gps.encode(c);

Every second character was missing. Not that I spotted it. Worth recording somehow in the Body of Knowledge of GPS practice.

I bet if you use the pass through approach the GPS sentences on the monitor will be intact and correct. That means using just read and print each available byte an do NOTHING else.

This is a comms problem rather than a satellite reception problem. Some of your sentences are being stitched together. The new line characters are being lost.

The question is where are they being lost? Between the GPS and the Arduino sketch, or between the Arduino sketch and the monitor?

I raised the same issue in a discussion about a month ago:

serial-communication-lost-data-gps-nano-serial-event

SoftwareSerial can drop characters when there is other intrrupt stuff going on, such as Serial.print() etc. Known problem.

Thanks for that, but I was using hardware serial.

On the face of it, it should not be difficult. The Arduino runs much faster than the serial and the data load from the GPS is not much.

Thank you, but I am still getting the "half" lines, the output loogs like this:

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,999,9P$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.,90 $GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.

.VN$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.89G,$GPRMC,,V,,,,,,,,,,N*53

$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,99.G.1,$GPRMC,,V,,,,,,,,,,N*53

I have experimented a bit and if I comment out everything in the loop function it works perfecly, but if I comment out everything except for a delay(10) in the end of the loop it doesnt work, or does it work just not the serial monitor thats falling behind?

$GPVTG,,,,,,,,,N*30
$GPVTG,,,,,,,,,N*30
$GPVTG,,,,,,,,,N*30
$GPVTG,,,,,,,,,N*30
$GPVTG,,,,,,,,,N*30

$GPGGA,,,,,,0,00,999,9P
$GPGGA,,,,,,0,00,99.,90 
$GPGGA,,,,,,0,00,99.\n.VN
$GPGGA,,,,,,0,00,99.89G,
$GPGGA,,,,,,0,00,99.G.1,

$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53
$GPRMC,,V,,,,,,,,,,N*53

My first guess is a buffer overrun: The receive buffer fills up and characters are thrown away. It looks like the $GPVTG and $GPRMC messages are fine but the $GPGGA messages are getting garbled after about 19 characters. Maybe the three messages arrive in a burst? The $GPRMC message is 23 characters (plus CR and LF). The $GPVTG is 19 (plus CR and LF). If the buffer is 64 characters, that leaves 18 characters for the $GPGGA message.

At 9600 baud you would receive about one character per millisecond. What could be delaying the processing for over 64 milliseconds?