Gps neo 6m problem

Hi!
i am working with an arduino mega2560 board and several sensors (gps, pm10, microphone, accelerometer..).

This is the code that manages all the sensors, which have to work at the same time and have to write to a csv file on a sd card:

#include <Wire.h>
#include <MPU6050_tockn.h>
#include <SoftwareSerial.h>
#include <SdsDustSensor.h>
#include <SPI.h>
#include <SD.h>
#include <TinyGPS.h>

//variabili per sensore CO2,NH3,NO2
const int S_analog = 1023.0;
int co, nh3;
float no2;

//variabili per sensore accelerometro/giroscopio
const int MPU = 0x68; // I2C address of the MPU-6050
float AccX, AccY, AccZ, Tmp, AngX, AngY, AngZ;
MPU6050 mpu6050(Wire);
unsigned long t1, dt;

//variabili per senosre GPS
float lat,lon;
TinyGPS gps; // create gps object

//variabili per sensore PM10 PM2.5
int rxPin = 16;
int txPin = 17;
SdsDustSensor sds(Serial2);

//variabili per SD Card
File file;
const int chipSelect = 53;
int i = 0;

void setup() {
  Serial.begin(9600);  // comune a tutti

  // acc/giroscopio
  Wire.begin();
  mpu6050.begin();
  //fase di calibrazione per il giroscopio
  mpu6050.calcGyroOffsets(true);

  // gps
  Serial.println("The GPS Received Signal:");
  Serial1.begin(9600); // connect gps sensor

  // pm10 pm2.5
  sds.begin();
  Serial2.begin(9600);
  
  // sd card

}

void loop() {
  MICS6814();
  Accelerometro_Giroscopio();
  GPS();
  PM10_PM25();
  SD_Card();
}

void MICS6814() {
  co = map (analogRead(A2), 0, S_analog, 1, 1000);          //monossido di carbonio
  nh3 = map (analogRead(A1), 0, S_analog, 1, 500);          //ammoniaca
  no2 = map (analogRead(A0), 0, S_analog, 5, 1000) / 100.0; //diossido di azoto

  //stampo i dati sul monossido di carbonio registrato
  //Serial.print("CO: ");
  Serial.print(co);
  Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sull'ammoniaca registrata
  //Serial.print("NH3: ");
  Serial.print(nh3);
  Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sul diossido di azoto registrato
  //Serial.print("NO2: ");
  Serial.print(no2);
  //Serial.print(",");
  Serial.println("");
  //Serial.print(" ppm\n");

  delay(1000);
}


void Accelerometro_Giroscopio() {
  
  mpu6050.update();
  dt = millis() - t1;
  if(dt > 200){
    t1= millis();
    AccX = mpu6050.getAccX();
    AccY = mpu6050.getAccY();
    AccZ = mpu6050.getAccZ();
    // angoli calcolati dal sw interno del sensore, non sono direttamente quelli misurati dal sensore
    AngX = mpu6050.getAngleX();
    //Serial.println(AngX);
    AngY = mpu6050.getAngleY();
    //Serial.println(AngY);
    AngZ = mpu6050.getAngleZ();
    //Serial.println(AngZ);
  }
  delay(333);
}

void GPS() {

  Serial.println(Serial1.read());
  
  while(Serial1.available()){ // check for gps data
    //Serial.print("A");
    if(gps.encode(Serial1.read()))// encode gps data
    { 
      //Serial.print("B");
      gps.f_get_position(&lat,&lon); // get latitude and longitude
    
      //Latitude
      Serial.print("Latitude: ");
      Serial.print(lat,6);
    
      Serial.print(",");
    
      //Longitude
      Serial.print("Longitude: ");
      Serial.println(lon,6); 
   }
  }
  //delay(500);
}


void PM10_PM25() {
  PmResult pm = sds.readPm();

  if (pm.isOk()) {
    // stampo PM2.5
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);

  //stampo PM10
    Serial.print(" PM10 = \n");
    Serial.print(pm.pm10);
    Serial.print("\n");
  }

  delay(500);
}


void SD_Card() {
  
   if(!SD.begin(chipSelect)){
     Serial.println("Errore");
     return;
   }

   /*if(SD.exists("example1.txt")){
     SD.remove("example1.txt");
   }*/
  PmResult pm = sds.readPm();
  String dataString = "";
  file = SD.open("datalog.csv", FILE_WRITE);

  //dataString = "";

  dataString += no2;
  dataString += ";";
  dataString += nh3;
  dataString += ";";
  dataString += co;
  dataString += ";";
  dataString += pm.pm10;
  dataString += ";";
  dataString += pm.pm25;
  dataString += ";";
  dataString += lat;
  dataString += ";";
  dataString += lon;
  dataString += ";";
  dataString += AccX;
  dataString += ";";
  dataString += AccY;
  dataString += ";";
  dataString += AccZ;
  dataString += ";";
  dataString += AngX;
  dataString += ";";
  dataString += AngY;
  dataString += ";";
  dataString += AngZ;
  //dataString += ";";

  if (file) {
    file.println(dataString);
    file.close();
    // print to the serial port too:
    Serial.println(dataString);
    //dataString = "";
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
  
}

my problem is that when all the sensors go, the gps doesn't write anything neither to the csv file, nor to the console. If instead I try to run only the gps, it writes without any problems.

can you help me?
thank you very much.

Your running a lot of code for each and every GPS sentence received, reading all the sensors, writing a heap of stuff to SD, printing stuff etc.

You should add some code to time using millis() how long each iteration of loop() takes.

thank you for your reply
sorry, but I don't quite understand what you mean..

If the loop function takes too much time, you will never receive a complete GPS sentence, and never have valid coordinates.

You are spending a lot of time printing at a very slow Baud rate. Change this:

  Serial.begin(9600);  // comune a tutti

to this, and change the serial monitor setting accordingly.

  Serial.begin(115200);  // comune a tutti

Delete lines like this:

  delay(333);

so I have to remove ALL 'delay(..)' ???

ok thanks

delay(333) means DO NOTHING for 1/3 of a second. That means don't read the GPS, etc.

Try this;

void loop() {
  uint32_t StartmS = millis();
  MICS6814();
  Accelerometro_Giroscopio();
  GPS();
  PM10_PM25();
  SD_Card();
  Serial.print("loop() takes ");
  Serial.print(millis() - StartmS);
  Serial.println("mS");
}

Because of how long loop() might take its possible you will not get a fix from the GPS ........................

In addition to all the useless delay() statements, which are preventing the program from reading the GPS, the following program lines will cause the Arduino to crash after a while.

You cannot use Strings objects with the Mega2560. Replace all of the "dataString +=" lines with file.print() statements.

And unless you have modified the configuration of the GPS, the way you are reading it is fundamentally flawed, but unfortunatly very few library examples read the GPS in a sensible fashion.

So tell us how long loop() takes, and I will explain.

I did as you said, but nothing changes

Post the revised code, using code tags.

Also, conduct the experiment suggested by @srnet and tell us what is printed out for loop time.

the time I am aware of is 1000ms or so (1007 for example).

#include <Wire.h>
#include <MPU6050_tockn.h>
#include <SoftwareSerial.h>
#include <SdsDustSensor.h>
#include <SPI.h>
#include <SD.h>
#include <TinyGPS.h>

//variabili per sensore CO2,NH3,NO2
const int S_analog = 1023.0;
int co, nh3;
float no2;

//variabili per sensore accelerometro/giroscopio
const int MPU = 0x68; // I2C address of the MPU-6050
float AccX, AccY, AccZ, Tmp, AngX, AngY, AngZ;
MPU6050 mpu6050(Wire);
unsigned long t1, dt;

//variabili per senosre GPS
float lat,lon;
TinyGPS gps; // create gps object

//variabili per sensore PM10 PM2.5
int rxPin = 16;
int txPin = 17;
SdsDustSensor sds(Serial2);

//variabili per SD Card
File file;
const int chipSelect = 53;
int i = 0;

void setup() {
  //Serial.begin(9600);  // comune a tutti
  Serial.begin(115200);

  // acc/giroscopio
  Wire.begin();
  mpu6050.begin();
  //fase di calibrazione per il giroscopio
  mpu6050.calcGyroOffsets(true);

  // gps
  Serial.println("The GPS Received Signal:");
  Serial1.begin(9600); // connect gps sensor

  // pm10 pm2.5
  sds.begin();
  Serial2.begin(9600);
  
  // sd card
  //dataString += "NO2;NH3;CO;PM10;PM2.5;AcX;AcY;AcZ;GyX;GyY;GyZ";
  // file = SD.open("datalog.csv", FILE_WRITE);
  // String title = "";

}

void loop() {
  uint32_t StartmS = millis();
  MICS6814();
  Accelerometro_Giroscopio();
  GPS();
  PM10_PM25();
  SD_Card();
  Serial.print("loop() takes ");
  Serial.print(millis() - StartmS);
  Serial.println("mS");
}

void MICS6814() {
  co = map (analogRead(A2), 0, S_analog, 1, 1000);          //monossido di carbonio
  nh3 = map (analogRead(A1), 0, S_analog, 1, 500);          //ammoniaca
  no2 = map (analogRead(A0), 0, S_analog, 5, 1000) / 100.0; //diossido di azoto

  //stampo i dati sul monossido di carbonio registrato
  //Serial.print("CO: ");
  Serial.print(co);
  Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sull'ammoniaca registrata
  //Serial.print("NH3: ");
  Serial.print(nh3);
  Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sul diossido di azoto registrato
  //Serial.print("NO2: ");
  Serial.print(no2);
  //Serial.print(",");
  Serial.println("");
  //Serial.print(" ppm\n");

  //delay(1000);
}

void Accelerometro_Giroscopio() {
  
  mpu6050.update();
  dt = millis() - t1;
  if(dt > 200){
    t1= millis();
    AccX = mpu6050.getAccX();
    AccY = mpu6050.getAccY();
    AccZ = mpu6050.getAccZ();
    // angoli calcolati dal sw interno del sensore, non sono direttamente quelli misurati dal sensore
    AngX = mpu6050.getAngleX();
    //Serial.println(AngX);
    AngY = mpu6050.getAngleY();
    //Serial.println(AngY);
    AngZ = mpu6050.getAngleZ();
    //Serial.println(AngZ);
  }
  //delay(333);
}

void GPS() {

  while(Serial1.available()){ // check for gps data
    //Serial.print("A");
    if(gps.encode(Serial1.read()))// encode gps data
    { 
      //Serial.print("B");
      gps.f_get_position(&lat,&lon); // get latitude and longitude
    
      //Latitude
      Serial.print("Latitude: ");
      Serial.print(lat,6);
    
      Serial.print(",");
    
      //Longitude
      Serial.print("Longitude: ");
      Serial.println(lon,6); 
   }
  }
  //delay(500);
}


void PM10_PM25() {
  PmResult pm = sds.readPm();

  if (pm.isOk()) {
    // stampo PM2.5
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);

  //stampo PM10
    Serial.print(" PM10 = \n");
    Serial.print(pm.pm10);
    Serial.print("\n");
  }

  //delay(500);
}

/*void Sound() {

}*/

void SD_Card() {
  
  if(!SD.begin(chipSelect)){
    Serial.println("Errore");
    return;
  }

   /*if(SD.exists("example1.txt")){
     SD.remove("example1.txt");
   }*/
   PmResult pm = sds.readPm();
   String dataString = "";
   file = SD.open("datalog.csv", FILE_WRITE);

   //dataString = "";

  dataString += no2;
  dataString += ";";
  dataString += nh3;
  dataString += ";";
  dataString += co;
  dataString += ";";
  dataString += pm.pm10;
  dataString += ";";
  dataString += pm.pm25;
  dataString += ";";
  dataString += lat;
  dataString += ";";
  dataString += lon;
  dataString += ";";
  dataString += AccX;
  dataString += ";";
  dataString += AccY;
  dataString += ";";
  dataString += AccZ;
  dataString += ";";
  dataString += AngX;
  dataString += ";";
  dataString += AngY;
  dataString += ";";
  dataString += AngZ;
  //dataString += ";";
   /*
     aggiungere parte per il rumore acustico dB
     dataString += rumore;
   */

  if (file) {
    file.println(dataString);
    file.close();
     // print to the serial port too:
     Serial.println(dataString);
     //dataString = "";
   }
   // if the file isn't open, pop up an error:
   else {
     Serial.println("error opening datalog.txt");
   }
  
}

I see you are still using Strings, which is a recipe for failure.

Opening the SD file, writing one line of data and closing it again takes several hundred milliseconds. You will never be able to read a complete GPS sentence if you do this every pass through loop().

The solution is to open the file once in setup(), and close it only when you are finished collecting data.

but the gps coordinates do not even print on the serial monitor even with the corrections I have made

then I open the file in setup and close it at the end of the SD_CARD function?

OK, so a GPS as standard puts out about 8 different NMEA sentences but only two of these contains GPS fix information, GPGGA and GPRMC. TinyGPS needs to read both of these to get a full fix update.

GPGGA and GPRMC each go out about once per second.

The way you are reading every GPS sentence is with encode() and when it returns true, you go off and spend 1000mS+ reading sensors, printing stuff and writing to SD.

But hold on, the GPS fix data is not updated at each NMEA sentence recieved, so what is the point of taking a sensor reading and saving it an the unchanged location to SD ? None at all.

In addition, since you spend so long away from reading the GPS, the NMEA sentence that contains the fix information can have long since gone so when eventually you get back to reading the GPS you just pick up another NMEA sentence with no fix information.

What you need to do is keep reading characters from the GPS, pass them to encode() and keep doing this until the GPS location is updated.

ok thank you very much for the explanation, very clear!
but it's not quite clear to me what to do on a practical level... once I know this, what should I do?
sorry but it's my first time working with this equipment and I don't know much about it...

This is a function from a GPS checker program for a Seeed XIAO SAMD21, it should be OK on a Mega if the Serial port number matches, it uses the TinyGPSplus GPS library;

bool gpsWaitFix(uint16_t waitSecs)
{
  //waits a specified number of seconds for a fix, returns true for updated fix

  uint32_t startmS, waitmS;
  uint8_t GPSchar;

  Serial.print(F("Wait GPS Fix "));
  Serial.print(waitSecs);
  Serial.println(F(" seconds"));

  waitmS = waitSecs * 1000;                               //convert seconds wait into mS
  startmS = millis();

  while ( (uint32_t) (millis() - startmS) < waitmS)       //allows for millis() overflow
  {
    if (Serial1.available() > 0)
    {
      GPSchar = Serial1.read();
      gps.encode(GPSchar);
      Serial.write(GPSchar);
    }

    if (gps.location.isUpdated() && gps.altitude.isUpdated() && gps.date.isUpdated())
    {
      endFixmS = millis();                                //record the time when we got a GPS fix
      return true;
    }
  }
  return false;
}

Note the fuction keeps reading characters from the GPS until the fix data is actually updated, there seems little point in updating displays, serial prints or logging data to SD, untill there is actuallly new data to use or display.

You call the function like this, specifying how long you want the function to read the GPS waiting for a fix before timing out;

if (gpsWaitFix(5))
  {
    Serial.println();
    Serial.println();
    Serial.print(F("Fix time "));
    Serial.print(endFixmS - startGetFixmS);
    Serial.println(F("mS"));

    GPSLat = gps.location.lat();
    GPSLon = gps.location.lng();
    GPSAlt = gps.altitude.meters();
    printGPSfix();               //print GPS data to serial monitor
    startGetFixmS = millis();    //have a fix, next thing that happens is checking for a fix, so restart timer
  }
  else
  {
    Serial.println();
    Serial.println();
    Serial.print(F("Timeout - No GPS Fix "));
    Serial.print( (millis() - startGetFixmS) / 1000 );
    Serial.println(F("s"));
  }
}

You would need to define the variables used.

And if the function reports a timeout, in this case in 5 seconds of reading the GPS, you know the GPS does not have a fix.