Serial Monitor Issue after uploading code

I am very new in coding and this project of mine is for determining the position of a mobile robot using the GY521(MPU6050) and a GPS module (NEO-6M). After uploading my code the output cannot be seen and instead the only thing showing up on my serial monitor are dots that are increasing in number slowly.

Here is my code just in case the problem is from my code and not anything else.

#include <Wire.h>
#include <MPU6050.h>
#include <TinyGPS++.h>
//#include <MPU6050_6Axis_MotionApps20.h>
//#include <MPU6050_tockn.h>

// MPU6050 object
MPU6050 mpu;

// GPS object
TinyGPSPlus gps;

// Kalman filter variables
float dt = 0.02;  // Time step (adjust as needed)
float accAngleX, accAngleY;
float gyroAngleX, gyroAngleY, gyroAngleZ;
float gyroX, gyroY, gyroZ;
float angleX, angleY, angleZ;
float gyroXangle, gyroYangle, gyroZangle;
float kalAngleX, kalAngleY;

// Variables for position tracking
float positionXYZ[3] = {0.0, 0.0, 0.0};  // Initial position
float trueXYZ[3] = {0.0, 0.0, 0.0};      // Initial true position

void setup() {
  Serial.begin(115200);
  
  // Initialize MPU6050
  Wire.begin();
  mpu.initialize();
  
  // Calibrate MPU6050
  mpu.CalibrateGyro();
  mpu.CalibrateAccel();
}

void loop() {
  // Read accelerometer and gyroscope data from MPU6050
  //mpu.update();
  
  // Get accelerometer angles
  accAngleX = atan2(mpu.getAccelerationY(), mpu.getAccelerationZ()) * RAD_TO_DEG;
  accAngleY = atan2(-mpu.getAccelerationX(), mpu.getAccelerationZ()) * RAD_TO_DEG;
  
  // Get gyroscope angles
  gyroX = mpu.getXGyroOffset() / 131.0;
  gyroY = mpu.getYGyroOffset() / 131.0;
  gyroZ = mpu.getZGyroOffset() / 131.0;
  
  // Calculate gyro angle using integration
  gyroXangle += gyroX * dt;
  gyroYangle += gyroY * dt;
  gyroZangle += gyroZ * dt;
  
  // Complementary filter for angle calculation
  angleX = 0.98 * (gyroXangle + gyroX * dt) + 0.02 * accAngleX;
  angleY = 0.98 * (gyroYangle + gyroY * dt) + 0.02 * accAngleY;
  angleZ = gyroZangle;
  
  // Kalman filter
  kalAngleX = kalmanFilterX(angleX, gyroX);
  kalAngleY = kalmanFilterY(angleY, gyroY);
  
  // Read GPS data and update true position
  while (Serial2.available() > 0) {
    if (gps.encode(Serial2.read())) {
      trueXYZ[0] = gps.location.lat();
      trueXYZ[1] = gps.location.lng();
      trueXYZ[2] = gps.altitude.meters();
    }
  }
  
  // Update position using sensor fusion (combining accelerometer, gyro, and GPS)
  positionXYZ[0] = kalAngleX;
  positionXYZ[1] = kalAngleY;
  positionXYZ[2] = trueXYZ[2];  // Z-axis position from GPS
  
  // Print positionXYZ and trueXYZ
  Serial.print("positionXYZ = ");
  Serial.print(positionXYZ[0]);
  Serial.print(", ");
  Serial.print(positionXYZ[1]);
  Serial.print(", ");
  Serial.println(positionXYZ[2]);
  
  Serial.print("trueXYZ = ");
  Serial.print(trueXYZ[0]);
  Serial.print(", ");
  Serial.print(trueXYZ[1]);
  Serial.print(", ");
  Serial.println(trueXYZ[2]);
}

// Kalman filter for X-axis angle
float kalmanFilterX(float angle, float gyroRate) {
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;
  
  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;
  
  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;
  
  y = angle - kalAngleX;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;
  
  angle += K[0] * y;
  kalAngleX += K[1] * y;
  
  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];
  
  return angle;
}

// Kalman filter for Y-axis angle
float kalmanFilterY(float angle, float gyroRate) {
  // Similar to kalmanFilterX, implement the filter for Y-axis angle here
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;
  
  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;
  
  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;
  
  y = angle - kalAngleY;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;
  
  angle += K[0] * y;
  kalAngleY += K[1] * y;
  
  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];
  
  return angle;
}

I am very sorry if this post is very rough and if it lacks certain etiquette I am only 3 months into this project and am struggling to find any breaktrough or find any progress.

Just a quick peek..
Don't see a Serial2.begin(baud rate); in your setup()??

sorry.. ~q

Sounds like the baudrate in the serial monitor does not match the value in the code
Your code adjusts the baudrate to 115200

  Serial.begin(115200);

and you have to adjust the baudrate of the serial monitor to this value.

Sounds a little odd to me. What did you do in this three months?
OK let's assume you did reading a lot about what components to use, how calman filters work
etc.

maybe now it is time to learn the basics of the Arduino-IDE.
Especially learning how to use the serial monitor as a debug-tool

Here is your code where I added my standard debug-macros I use all the time

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

#include <Wire.h>
#include <MPU6050.h>
#include <TinyGPS++.h>
//#include <MPU6050_6Axis_MotionApps20.h>
//#include <MPU6050_tockn.h>

// MPU6050 object
MPU6050 mpu;

// GPS object
TinyGPSPlus gps;

// Kalman filter variables
float dt = 0.02;  // Time step (adjust as needed)
float accAngleX, accAngleY;
float gyroAngleX, gyroAngleY, gyroAngleZ;
float gyroX, gyroY, gyroZ;
float angleX, angleY, angleZ;
float gyroXangle, gyroYangle, gyroZangle;
float kalAngleX, kalAngleY;

// Variables for position tracking
float positionXYZ[3] = {0.0, 0.0, 0.0};  // Initial position
float trueXYZ[3] = {0.0, 0.0, 0.0};      // Initial true position

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  // Initialize MPU6050
  Wire.begin();
  Serial.println("Wire.begin() done");
  mpu.initialize();
  Serial.println("mpu.initialize() done");

  // Calibrate MPU6050
  mpu.CalibrateGyro();
  mpu.CalibrateAccel();
  Serial.println("Calibrate MPU6050 done");
}

void loop() {
  // Read accelerometer and gyroscope data from MPU6050
  //mpu.update();

  // Get accelerometer angles
  accAngleX = atan2(mpu.getAccelerationY(), mpu.getAccelerationZ()) * RAD_TO_DEG;
  accAngleY = atan2(-mpu.getAccelerationX(), mpu.getAccelerationZ()) * RAD_TO_DEG;

  // Get gyroscope angles
  gyroX = mpu.getXGyroOffset() / 131.0;
  gyroY = mpu.getYGyroOffset() / 131.0;
  gyroZ = mpu.getZGyroOffset() / 131.0;

  // Calculate gyro angle using integration
  gyroXangle += gyroX * dt;
  gyroYangle += gyroY * dt;
  gyroZangle += gyroZ * dt;

  // Complementary filter for angle calculation
  angleX = 0.98 * (gyroXangle + gyroX * dt) + 0.02 * accAngleX;
  angleY = 0.98 * (gyroYangle + gyroY * dt) + 0.02 * accAngleY;
  angleZ = gyroZangle;

  // Kalman filter
  kalAngleX = kalmanFilterX(angleX, gyroX);
  kalAngleY = kalmanFilterY(angleY, gyroY);

  // once every 1005 milliseconds print 
  dbgi("01:",Serial2.available(),1005);
  
  // Read GPS data and update true position
  while (Serial2.available() > 0) {
    if (gps.encode(Serial2.read())) {
      trueXYZ[0] = gps.location.lat();
      trueXYZ[1] = gps.location.lng();
      trueXYZ[2] = gps.altitude.meters();
    }
  }

  // Update position using sensor fusion (combining accelerometer, gyro, and GPS)
  positionXYZ[0] = kalAngleX;
  positionXYZ[1] = kalAngleY;
  positionXYZ[2] = trueXYZ[2];  // Z-axis position from GPS

  // Print positionXYZ and trueXYZ
  Serial.print("positionXYZ = ");
  Serial.print(positionXYZ[0]);
  Serial.print(", ");
  Serial.print(positionXYZ[1]);
  Serial.print(", ");
  Serial.println(positionXYZ[2]);

  Serial.print("trueXYZ = ");
  Serial.print(trueXYZ[0]);
  Serial.print(", ");
  Serial.print(trueXYZ[1]);
  Serial.print(", ");
  Serial.println(trueXYZ[2]);
}

// Kalman filter for X-axis angle
float kalmanFilterX(float angle, float gyroRate) {
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;

  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;

  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;

  y = angle - kalAngleX;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;

  angle += K[0] * y;
  kalAngleX += K[1] * y;

  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];

  return angle;
}

// Kalman filter for Y-axis angle
float kalmanFilterY(float angle, float gyroRate) {
  // Similar to kalmanFilterX, implement the filter for Y-axis angle here
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;

  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;

  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;

  y = angle - kalAngleY;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;

  angle += K[0] * y;
  kalAngleY += K[1] * y;

  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];

  return angle;
}

best regards Stefan

@StefanL38

His first image shows baud rate of SM is 115,200 just like in setup(). So unless there's a problem in SM, bauds are the same. It's puzzling, for sure, I had jumped to the same idea at first. I don't use V2.x, so I'm not up on any known deficiencies with SM.

only dots

increasing slowly remembers me of an ESP8266/ESP32 trying to connect to a WiFi
So @imnishhh what microcontroller are you using?
Could it be that you accidently uploaded a very different sketch?
At least you should run the code-version I have posted which does print to the serial monitor as the first action after

best regards Stefan

No, look to the very right hand side, it says 115200 in the image.

This project is actually my final year project where the mobile robot uses SLAM to move around and create a map of the environment and yes I have been reading and learning the basics of Arduino IDE and also on how to dead reckon or using sensor fusion and applying kalman filter. I'm a very slow learner and with other subjects to cover, my project ended up being left behind in terms of progress and now I am trying to atleast show some progress to my lecturer/supervisor by atleast having the positioning part which is the Localization part of the SLAM done.

I am currently using the ESP32 WROOM 32 for the mobile robot and coding it using the Arduino IDE for my project but currently my code does not have a wifi connecting code/function yet for it to exhibit the dot loading behaviour.

Thank you for giving me some pointers and from what I found is that in void setup() the mpu.CalibrateGyro() and mpu.CalibrateAccel() is the one making it show the dot loading behaviour and when I disabled it the output shows normally in the serial monitor but only shows 0 value for the trueXYZ output. I tried tweaking the parameters in the kalmanFilterX and Y but the data still shows up as 0 even when I move the mobile robot around.

I'm sorry if this ended up being too long.

Which is read from gps from Serial2 which has not been initialized..
Need a Serial2.begin() in your setup??

sorry.. ~q

Not sure what you mean by "beeing too long"
Your posting is well written.

You could even write pages long postings if you structure your postings into paragraphs and give each paragraph a titel for orientation. Then your postings would be even a "role-model" for all newcomers here.

If you haven't used serial printing in the past even in this situation where serial printing seems not to work as it should it is a good idea to use it.

At a certain point your posting was still a bit too short for giving detailed and good advice.
Did you test with the code where I added serial printing?
If yes
activate timestamps of the serial monitor and post what got printed to the serial monitor as a code-section

Why did you include the file "TinyGPS++.h

I mean the filename with the to plus-signs

++

the example-codes delivered with the TinyGPSPlus-library all use

#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
/*
   This sample sketch demonstrates the normal use of a TinyGPSPlus (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

They include a filename with the letters

plus

#include <TinyGPSPlus.h>
instead of
TinyGPS++.h

and the TinygpsPlus-example-sketcheshave a note that you should use softwareserial

This sample sketch demonstrates the normal use of a TinyGPSPlus (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).

This gives the following up question: does it work the same way with an ESP32?
So I searched for it.
The search-strategy is really simple use

  • keyword "arduino"
  • keyword "name of the microcontroller"
  • keyword name of the library

Eh voilà like in 98% percent of all cases with searching useful things will be found.

There is a special version of tinyGPSplus for ESp32

So I recommend that you ask here in the forum how you can speed up learning
(See advice above for search-strategy)

I was asking myself if you are not a slow learner but maybe a person that procrastinates work he judges as "difficult. Or is it something different?

As another advice: you should not "slam" together too much code without testing.
In the end you will finish your project faster if you test one thing at a time.
The reason is: if you put together more than one thing at a time these multiple things can interfere with each other and then you need much more time to narrow down where the bug really is.

best regards Stefan

Thank you.

As for this I tried to use a modified code of the one you gave where I used the TinyGPSPlus.h instead of the TinyGPS++.h where the TinyGPSPlus.h is the one that is for ESP32. I ran the code for a bit and disconnected the ESP32 to stop the readings so I can copy what output got printed on the serial monitor. Here is what got printed to the serial monitor after using a modified version of your code:

14:51:08.524 -> .........>...............Calibrate MPU6050 done
14:51:15.875 -> "01:" Serial2.available()=0
14:51:15.875 -> positionXYZ = -0.84, 0.04, 0.00
14:51:15.875 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.875 -> positionXYZ = -0.56, 0.03, 0.00
14:51:15.875 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.875 -> positionXYZ = -0.97, 0.05, 0.00
14:51:15.875 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.875 -> positionXYZ = -1.11, 0.05, 0.00
14:51:15.875 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.875 -> positionXYZ = -1.33, 0.06, 0.00
14:51:15.875 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -1.54, 0.08, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -1.76, 0.09, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -1.97, 0.10, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -2.18, 0.11, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -2.40, 0.12, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -2.61, 0.14, 0.00
14:51:15.911 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.911 -> positionXYZ = -2.83, 0.14, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -3.04, 0.15, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -3.25, 0.17, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -3.47, 0.18, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -3.68, 0.18, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -3.90, 0.18, 0.00
14:51:15.945 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.945 -> positionXYZ = -4.12, 0.20, 0.00
14:51:15.976 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.976 -> positionXYZ = -4.33, 0.21, 0.00
14:51:15.976 -> trueXYZ = 0.00, 0.00, 0.00
14:51:15.976 -> positionXYZ = -4.55, 0.23, 0.00
14:51:15.976 -> trueXYZ = 0.00, 0.00, 0.00

I don't if this is too long or short to use for an example but here you can see the positionXYZ reading keeps on increasing non-stop meaning it is not tracking the position of the robot.

This is modified code mentioned I don't know if it affects anything or not but to me it is still the same where the trueXYZ value is still 0:

`// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

#include <Wire.h>
#include <MPU6050.h>
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
//#include <MPU6050_6Axis_MotionApps20.h>
//#include <MPU6050_tockn.h>

// MPU6050 object
MPU6050 mpu;

// GPS object
TinyGPSPlus gps;

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

// Kalman filter variables
float dt = 0.02;  // Time step (adjust as needed)
float accAngleX, accAngleY;
float gyroAngleX, gyroAngleY, gyroAngleZ;
float gyroX, gyroY, gyroZ;
float angleX, angleY, angleZ;
float gyroXangle, gyroYangle, gyroZangle;
float kalAngleX, kalAngleY;

// Variables for position tracking
float positionXYZ[3] = {0.0, 0.0, 0.0};  // Initial position
float trueXYZ[3] = {0.0, 0.0, 0.0};      // Initial true position

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  // Initialize MPU6050
  Wire.begin();
  Serial.println("Wire.begin() done");
  mpu.initialize();
  Serial.println("mpu.initialize() done");

  // Calibrate MPU6050
  mpu.CalibrateGyro();
  mpu.CalibrateAccel();
  Serial.println("Calibrate MPU6050 done");
}

void loop() {
  // Read accelerometer and gyroscope data from MPU6050
  //mpu.update();

  // Get accelerometer angles
  accAngleX = atan2(mpu.getAccelerationY(), mpu.getAccelerationZ()) * RAD_TO_DEG;
  accAngleY = atan2(-mpu.getAccelerationX(), mpu.getAccelerationZ()) * RAD_TO_DEG;

  // Get gyroscope angles
  gyroX = mpu.getXGyroOffset() / 131.0;
  gyroY = mpu.getYGyroOffset() / 131.0;
  gyroZ = mpu.getZGyroOffset() / 131.0;

  // Calculate gyro angle using integration
  gyroXangle += gyroX * dt;
  gyroYangle += gyroY * dt;
  gyroZangle += gyroZ * dt;

  // Complementary filter for angle calculation
  angleX = 0.98 * (gyroXangle + gyroX * dt) + 0.02 * accAngleX;
  angleY = 0.98 * (gyroYangle + gyroY * dt) + 0.02 * accAngleY;
  angleZ = gyroZangle;

  // Kalman filter
  kalAngleX = kalmanFilterX(angleX, gyroX);
  kalAngleY = kalmanFilterY(angleY, gyroY);

  // once every 1005 milliseconds print 
  dbgi("01:",Serial2.available(),1005);
  
  // Read GPS data and update true position
  while (Serial2.available() > 0) {
    if (gps.encode(Serial2.read())) {
      trueXYZ[0] = gps.location.lat();
      trueXYZ[1] = gps.location.lng();
      trueXYZ[2] = gps.altitude.meters();
    }
  }

  // Update position using sensor fusion (combining accelerometer, gyro, and GPS)
  positionXYZ[0] = kalAngleX;
  positionXYZ[1] = kalAngleY;
  positionXYZ[2] = trueXYZ[2];  // Z-axis position from GPS

  // Print positionXYZ and trueXYZ
  Serial.print("positionXYZ = ");
  Serial.print(positionXYZ[0]);
  Serial.print(", ");
  Serial.print(positionXYZ[1]);
  Serial.print(", ");
  Serial.println(positionXYZ[2]);

  Serial.print("trueXYZ = ");
  Serial.print(trueXYZ[0]);
  Serial.print(", ");
  Serial.print(trueXYZ[1]);
  Serial.print(", ");
  Serial.println(trueXYZ[2]);
}

// Kalman filter for X-axis angle
float kalmanFilterX(float angle, float gyroRate) {
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;

  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;

  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;

  y = angle - kalAngleX;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;

  angle += K[0] * y;
  kalAngleX += K[1] * y;

  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];

  return angle;
}

// Kalman filter for Y-axis angle
float kalmanFilterY(float angle, float gyroRate) {
  // Similar to kalmanFilterX, implement the filter for Y-axis angle here
  static float P[2][2] = {{1, 0}, {0, 1}};
  static float Pdot[4] = {0, 0, 0, 0};
  static float Q_angle = 0.001, Q_gyro = 0.003, R_angle = 0.03;
  float y, S;
  static float K[2] = {0, 0};
  float dt_c = 0.01;

  Pdot[0] = Q_angle - P[0][1] - P[1][0];
  Pdot[1] = -P[1][1];
  Pdot[2] = -P[1][1];
  Pdot[3] = Q_gyro;

  P[0][0] += Pdot[0] * dt_c;
  P[0][1] += Pdot[1] * dt_c;
  P[1][0] += Pdot[2] * dt_c;
  P[1][1] += Pdot[3] * dt_c;

  y = angle - kalAngleY;
  S = P[0][0] + R_angle;
  K[0] = P[0][0] / S;
  K[1] = P[1][0] / S;

  angle += K[0] * y;
  kalAngleY += K[1] * y;

  P[0][0] -= K[0] * P[0][0];
  P[0][1] -= K[0] * P[0][1];
  P[1][0] -= K[1] * P[0][0];
  P[1][1] -= K[1] * P[0][1];

  return angle;
}`

I see thank you so much for giving me advice on how to learn faster.

In truth, this is correct I push things that cannot be done within 2-3 hours back and do other things that can be settled quickly like other assignments but I am a slow learner too. I have two projects this semester which is a design project and this one. I really love designing and I always avoid coding whenever coding comes up in my previous semester, somehow during all my years studying there was no indivual coding assignments so I was able to avoid it and now all that avoiding has come to bite me back. Back to the projects, I tend to do designing one first because in my mind one component can be done in 2-3 hours so I end up finishing one thing and forgetting the other when it's supposed to be done in sync and progress equally among the project. I will try my best to finish this project in time I hope I can make it.

Thank you I will try to seperate everything out first so I can filter out everything that is working correctly and everything that is not working.

Sincerely, Nish

Hi Nish,

preferring to do things that get finished in 2 or 3 hours fits very good to the strategy of developping code in small steps by testing one thing at a time.

You should start with a demo-code that is delivered with the ESP32-TinyGPS-Plus-library.

I'm pretty sure that using IO-pins 3 and 4 here

are the wrong IO-pins for an ESP32

Did you really install the ESP32-tinyGPS-plus-library?

best regards Stefan

Thank you for the kind advice I will try to do it one step at a time and develop the code more in time by adding more to it slowly.

Apologies I have now changed the IO-pins according to the pinout of the ESP32 board that I am using which is shown below:

In my project the IO-pins that are being used are the RX2 and TX2 pins on the ESP32 pinout diagram which is the GPIO16 and GPIO17 respectively. The GPS module that I am using which is the GY-GPS6MV2 and connected the module to the ESP32 from a website I found on how to connect the GPS module to the ESP32 board.

From this I have now changed the code accordingly as shown:

static const int RXPin = 16, TXPin = 17;
static const uint32_t GPSBaud = 4800;

Is this the correct way to change the IO-pins or to match that of the number on the ESP32 board where it says RX2 and TX2 and change it to be like below instead?

static const int RXPin = 2, TXPin = 2;
static const uint32_t GPSBaud = 4800;

Anyways, after changing the code to use the RXPin = 16 and TXPin = 17 I ran the code again and this is the output on the serial monitor where everything is mostly the same as before the change.

This is the output after applying the changes.

16:39:34.827 -> ...............>...............Calibrate MPU6050 done
16:39:46.049 -> "01:" Serial2.available()=0
16:39:46.049 -> positionXYZ = -0.83, 0.04, 0.00
16:39:46.049 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -0.56, 0.02, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -0.96, 0.06, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -1.10, 0.05, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -1.34, 0.06, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -1.54, 0.07, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.083 -> positionXYZ = -1.76, 0.08, 0.00
16:39:46.083 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -1.97, 0.11, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -2.19, 0.11, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -2.41, 0.12, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -2.61, 0.12, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -2.83, 0.14, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -3.04, 0.15, 0.00
16:39:46.121 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.121 -> positionXYZ = -3.26, 0.16, 0.00
16:39:46.154 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.154 -> positionXYZ = -3.48, 0.17, 0.00
16:39:46.154 -> trueXYZ = 0.00, 0.00, 0.00
16:39:46.154 -> positionXYZ = -3.69, 0.19, 0.00
16:39:46.154 -> trueXYZ = 0.00, 0.00, 0.00

As for the library installed I think I have installed the proper library which is the TinyGPSPLus-ESP32 library as shown in the image below.

Sincerely, Nish

put your actual code aside.
There are too many parameters in your code that can cause not functioning:

  • Still wrong IO-pins.
  • wrong initalisation
  • wrong supply-voltage

Well done posting a picture of your GPS-receiver
On this picture you can read Supply-voltage 3. 7 V to 5V

This means supplying with 3.3V is not sufficient.

You should post a hand-drawn schematic how you are supplying the GPS-module.

You should really use the demo-code that is delivered with the ESP32-TinyGPSPlus-library and test this code
This example-code is well knwon for working properly. So you can exclude a software-bug if it is still not working.

About the TinyGPSPlus-ESP32 library:
In c++ there is a bad habit that every library on a topic has the same name. Since you have installed several TinyGPS libraries, it is possible that the wrong TinyGPS-Plus-ESP32-library was used despite the installation.

You should adjust the compiler to verbose output
like described here

This log will be very very long. Too long for a single posting (maximum 117 kB characters)

divide it into three parts and post them in different postings.
Then I can analyse which libraries were used

best regards Stefan

In your code, you are using Serial2 to communicate with the GPS module. However, I don't see where you have defined Serial2 and initialized it. Make sure you have the correct communication pins and that you have properly initialized the GPS module using the appropriate library.
I don't see any code where you initialize the MPU6050 sensor. Before calibrating the sensor, you need to call the mpu.initialize() function. Make sure to include the necessary Wire and MPU6050 library dependencies as well.
You should perform sensor calibration before using the sensor readings. It seems like you are attempting to calibrate the MPU6050 using the CalibrateGyro() and CalibrateAccel() functions. However, these functions are not part of the MPU6050 library. You may need to find an alternative method to calibrate your sensor or implement your own calibration routine.
You are using functions like mpu.getAccelerationX(), mpu.getAccelerationY(), mpu.getAccelerationZ(), mpu.getXGyroOffset(), mpu.getYGyroOffset(), and mpu.getZGyroOffset(). These functions are not part of the standard MPU6050 library. Make sure you are using the correct library and consult its documentation to obtain the appropriate sensor data.
Your code includes a basic implementation of a Kalman filter for angle estimation. While this can be useful for stabilizing angle measurements, it might not be necessary for position tracking. Consider whether a Kalman filter is needed for your specific application.
The dots you are seeing in the serial monitor indicate that the GPS data is not being received or parsed correctly. Ensure that you have a valid GPS fix and that the GPS module is sending valid NMEA data. You can also try printing the raw GPS data to check if it's being received properly before attempting to parse it with the TinyGPSPlus library.

Let me address this one by one firstly is the IO-pins. So according to chatGPT the TX and RX number is the GPIO number which in this case for the ESP32-WROOM-32 board the TX2 and the RX2 pin on the board is the GPIO17 and GPIO16 respectively. So this means the IO-pins for the code and the board matches correctly and I will show you proof later.

Next is the supply-voltage here is my circuit diagram (sorry that it's very scuffed) but I tried to use the exact parts of my current circuit up to the colour of the wires I'm using. Supposedly 6AA x 1.5V batteries connected in series should give me around 6V.

Next is the demo code, so I tried it and this is the code and output:

CODE

#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
/*
   This sample sketch demonstrates the normal use of a TinyGPSPlus (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 16, TXPin = 17;
static const uint32_t GPSBaud = 9600;

// The TinyGPSPlus object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

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

  Serial.println(F("DeviceExample.ino"));
  Serial.println(F("A simple demonstration of TinyGPSPlus with an attached GPS module"));
  Serial.print(F("Testing TinyGPSPlus library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
}

void loop()
{
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0)
    if (gps.encode(ss.read()))
      displayInfo();

  if (millis() > 5000 && gps.charsProcessed() < 10)
  {
    Serial.println(F("No GPS detected: check wiring."));
    while(true);
  }
}

void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (gps.location.isValid())
  {
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Date/Time: "));
  if (gps.date.isValid())
  {
    Serial.print(gps.date.month());
    Serial.print(F("/"));
    Serial.print(gps.date.day());
    Serial.print(F("/"));
    Serial.print(gps.date.year());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F(" "));
  if (gps.time.isValid())
  {
    if (gps.time.hour() < 10) Serial.print(F("0"));
    Serial.print(gps.time.hour());
    Serial.print(F(":"));
    if (gps.time.minute() < 10) Serial.print(F("0"));
    Serial.print(gps.time.minute());
    Serial.print(F(":"));
    if (gps.time.second() < 10) Serial.print(F("0"));
    Serial.print(gps.time.second());
    Serial.print(F("."));
    if (gps.time.centisecond() < 10) Serial.print(F("0"));
    Serial.print(gps.time.centisecond());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.println();
}

Here we can see that I already changed the TX and RX to the pin 17 and 16.

static const int RXPin = 16, TXPin = 17;

Also I changed the baud rate of the GPS to the one I am using which is 9600.

static const uint32_t GPSBaud = 9600;

OUTPUT

20:00:15.713 -> 
20:00:20.585 -> Location: INVALID  Date/Time: 6/12/2023 12:00:23.00
20:00:20.631 -> Location: INVALID  Date/Time: 6/12/2023 12:00:23.00
20:00:20.664 -> Location: INVALID  Date/Time: 6/12/2023 12:00:23.00
20:00:20.709 -> Location: INVALID  Date/Time: 6/12/2023 12:00:23.00
20:00:20.709 -> Location: INVALID  Date/Time: 6/12/2023 12:00:23.00
20:00:21.704 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:21.751 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:21.799 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:21.847 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:21.847 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:21.894 -> Location: INVALID  Date/Time: 6/12/2023 12:00:24.00
20:00:22.541 -> Location: INVALID  Date/Time: 6/12/2023 12:00:25.00
20:00:22.572 -> Location: INVALID  Date/Time: 6/12/2023 12:00:25.00
20:00:22.621 -> Location: INVALID  Date/Time: 6/12/2023 12:00:25.00
20:00:22.652 -> Location: INVALID  Date/Time: 6/12/2023 12:00:25.00

The date and time output is available and the date is correct meaning the GPS module can be detected but somehow the longitude and latitude cannot be read?

I uninstalled every GPS related library and only installed the TinyGPSPlus-ESP32 library for this demo-code.

Hope this clears up some questions.

Thank you for pointing it out.

Unfortunately, this is not true the CalibrateGyro() and CalibrateAccel() is a part of the library as shown here:
image
image

Even in the GitHub Repo the function is there:

Again I am only using this because its in the GitHub Repo and it is available when it shows the autofill when I type in the code.

I apologize if the way I am using this function is wrong and please do share some pointers on how to do this properly.

I am just following a youtube video that I saw on how to use acceleration, gyro and gps to get an accurate reading. I don't if there is any rules on sharing youtube links I apologize in advance but this is the youtube video I'm basing my code off. https://www.youtube.com/watch?v=6M6wSLD-8M8

Yes this is the issue currently and I already did the demo-code to test the GPS module and only got INVALID as an output meaning the module can be detected but either the parsing or the reading of the raw data is the one causing the problem. I have no way to check if this is a hardware issue due to only having one of this module on hand currently. I am trying my best to do tests etc to make sure that it really is not hardware issue and the only problematic one is me alone hahaha. This is the output that I get when I use the device example code:

21:28:29.641 -> Location: INVALID  Date/Time: 6/12/2023 13:28:35.00
21:28:29.641 -> Location: INVALID  Date/Time: 6/12/2023 13:28:35.00
21:28:29.688 -> Location: INVALID  Date/Time: 6/12/2023 13:28:35.00
21:28:30.532 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:30.532 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:30.564 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:30.644 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:30.644 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:30.676 -> Location: INVALID  Date/Time: 6/12/2023 13:28:36.00
21:28:31.533 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00
21:28:31.533 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00
21:28:31.579 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00
21:28:31.622 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00
21:28:31.655 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00
21:28:31.655 -> Location: INVALID  Date/Time: 6/12/2023 13:28:37.00

Thank you for the kind advice.

So apparently I went to eat and when I came back the reading for the GPS is available I have no idea what is the issue but now the output from the serial is this:

22:16:20.554 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.602 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.679 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.726 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.804 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.851 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.897 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:20.944 -> Location: 2.936543,101.779473  Date/Time: 6/12/2023 14:16:23.00
22:16:21.562 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.596 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.675 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.722 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.800 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.846 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00
22:16:21.893 -> Location: 2.936535,101.779473  Date/Time: 6/12/2023 14:16:24.00

as a general advice: you should post code

always

as code-section.
not as pictures
There is a keyboard-short-cut to do this

Shift-Ctrl-C

and then you simply use Ctrl-V to paste the clipboard-content into your posting. Very efficient.

To make visible what bytes were received I modified function loop from

void loop() {
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0)
    if (gps.encode(ss.read()))
      displayInfo();
//...

to

void loop() {
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0) {
    myGPS_Char = ss.read();
    myCharNr++;
    Serial.print(myCharNr);
    Serial.print("-");
    Serial.print(myGPS_Char);
    Serial.println();
     
    if ( gps.encode(myGPS_Char) ) {
      displayInfo();
      myCharNr = 0;
    }  
  }

ss.read()
reads a single byte.
The byte is then handed over to function
gps.encode()

Here is the complete sketch with this modifications

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
/*
   This sample sketch demonstrates the normal use of a TinyGPSPlus (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 16, TXPin = 17;
static const uint32_t GPSBaud = 9600;

char myGPS_Char;
int  myCharNr = 0; 

// The TinyGPSPlus object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

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

  Serial.println(F("DeviceExample.ino"));
  Serial.println(F("A simple demonstration of TinyGPSPlus with an attached GPS module"));
  Serial.print(F("Testing TinyGPSPlus library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
}


void loop() {
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0) {
    myGPS_Char = ss.read();
    myCharNr++;
    Serial.print(myCharNr);
    Serial.print("-");
    Serial.print(myGPS_Char);
    Serial.println();
     
    if ( gps.encode(myGPS_Char) ) {
      displayInfo();
      myCharNr = 0;
    }  
  }
  
  if (millis() > 5000 && gps.charsProcessed() < 10)
  {
    Serial.println(F("No GPS detected: check wiring."));
    while(true);
  }
}


void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (gps.location.isValid())
  {
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Date/Time: "));
  if (gps.date.isValid())
  {
    Serial.print(gps.date.month());
    Serial.print(F("/"));
    Serial.print(gps.date.day());
    Serial.print(F("/"));
    Serial.print(gps.date.year());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F(" "));
  if (gps.time.isValid())
  {
    if (gps.time.hour() < 10) Serial.print(F("0"));
    Serial.print(gps.time.hour());
    Serial.print(F(":"));
    if (gps.time.minute() < 10) Serial.print(F("0"));
    Serial.print(gps.time.minute());
    Serial.print(F(":"));
    if (gps.time.second() < 10) Serial.print(F("0"));
    Serial.print(gps.time.second());
    Serial.print(F("."));
    if (gps.time.centisecond() < 10) Serial.print(F("0"));
    Serial.print(gps.time.centisecond());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.println();
}

best regards Stefan

It is the same as with your smartphone:
A GPS-receiver needs some time which could be sometimes 3 minutes sometimes 10 minutes until the GPS-receiver received valid data from a minimum of three satellites.
The location is determined through runtimes of timing signal
The more satellites the GPS-module it receives valid data from the higher the precision

If you are indoor the signal is weakened by the walls and the roof of the building.
When you go into the basement of a building build of steel-concrete you will no longer receive a single satellite because the steel will be an effective shield against the electromagnetic waves coming from the satellites.

best regards Stefan

You can watch this process how determining the position proceeds with apps like
GPS-Test

or
GPS-test-plus