TinyGSM icon indicating copy to clipboard operation
TinyGSM copied to clipboard

.getGPS Inverts Latitude (SIM7600)

Open wjcloudy opened this issue 3 years ago • 8 comments

I am in northern hemisphere and westerly longitude, (51.8,-0.72) however using .getGPS gives both a negative latitude (incorrect) and negative longitude (correct) - The included example does the same.

The values are correct when using .getGPSraw (xxxxx,N,xxxxxW) (SIM7600 on TinyGSM v0.11.3)

wjcloudy avatar Jul 20 '21 08:07 wjcloudy

I was exactly checking this issue on my SIM7600. There's a problem in getGPSImpl() :

Apparently north = stream.read() fails most of the times returning '' instead of N or E even if other parameters are correctly parsed.

17:16:01.955 -> AT+CGNSSINFO
17:16:01.955 -> AT+CGNSSINFO

17:16:01.955 -> +CGNSSINFO: 2,08,00,00,4430.812577,N,01119.128956,E,210721,151601.0,50.9,0.0,34.1,1.5,1.2,0.9
17:16:01.955 -> 
17:16:01.955 -> OK
17:16:04.975 -> ⸮ <-----------------  Serial.println(north);
17:16:04.975 -> 0 <-----------------  Serial.println(north == 'N');
17:16:05.972 -> [4808978] Latitude: -44.51354218 	Longitude: -11.31881523
17:16:05.972 -> [4808978] Speed: 0.00 	Altitude: 50.90
17:16:05.972 -> [4808978] Visible Satellites: 0 	Used Satellites: 0
17:16:05.972 -> [4808978] Accuracy: 1.20
17:16:05.972 -> [4808978] Year: 2021 	Month: 7 	Day: 21
17:16:05.972 -> [4808979] Hour: 15 	Minute: 16 	Second: 1
17:16:05.972 -> [4808979] Retrieving GPS/GNSS/GLONASS location again as a string
17:16:05.972 -> AT+CGNSSINFO
17:16:05.972 -> AT+CGNSSINFO

17:16:05.972 -> +CGNSSINFO: 2,08,00,00,4430.812575,N,01119.128959,E,210721,151605.0,50.9,0.0,34.1,1.5,1.2,0.9
17:16:05.972 -> 
17:16:05.972 -> OK
17:16:05.972 -> [4808992] GPS/GNSS Based Location String: 2,08,00,00,4430.812575,N,01119.128959,E,210721,151605.0,50.9,0.0,34.1,1.5,1.2,0.9



gorghino avatar Jul 21 '21 15:07 gorghino

I see your longitude is also inverted when it shouldn't. What does your print statements give for longitude? (Guess that's doing the same)

wjcloudy avatar Jul 21 '21 16:07 wjcloudy

Yes it's the same. The formula to get the lat/lon is correct:

*lat = (floor(ilat / 100) + fmod(ilat, 100.) / 60) * (north == 'N' ? 1 : -1);
*lon = (floor(ilon / 100) + fmod(ilon, 100.) / 60) * (east == 'E' ? 1 : -1);

but apparently north and east often have read by stream instead of 'N' or 'E' @SRGDamia1 any idea why this happens?

gorghino avatar Jul 22 '21 08:07 gorghino

Ok I think i fixed it. It seems that stream.read() is not ready yet to be read while the CGNSSINFO stream is arriving.

In getGPSImpl(), add a small delay(10) after if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; }. This helps.

gorghino avatar Jul 22 '21 10:07 gorghino

That does appear to work for me too. Only issue now is that command seems to block for several seconds, whereas get raw returns instantly...

wjcloudy avatar Jul 29 '21 21:07 wjcloudy

I can confirm, the same goes for me on my side with a Lilygo SIM7600G-H. When running :

  • getGPSraw() : it results instantly
  • getGPSTime(xxxxx) : it take approx ~4s to output

Any update on this problem ?

simkard69 avatar Oct 27 '21 16:10 simkard69

Hello Guys,

I modified a little bit file "TinyGsmClientSIM7600.h" to change the way "getGPSImpl()" is working. As "getGPSrawImpl()" was returning results quite instantly by querying "+CGNSSINFO", which "getGPSImpl()" was doing the same but was timing out in most cases, here is my code for file "TinyGsmClientSIM7600.h".

Frustrating things with the SIM7600 module regarding GPS output using "+CGNSSINFO" are 2 things :

  • GPS FIX always shows "2" for a 2D FIX and never gets a "3" for 3D FIX (even when it is the case) >>> This is due to module firmware
  • Available SATS are never shown, we only get valid SATS (I added some variables in the return ones to get all the valid SATS which can be GPS, GLONASS or BEIDOU) >>> This can be enhanced but I didn't had time to do so.

Please report if it is working on your side. NB : I modified v0.11.3 library sources for that and my module is SIM7600G-H R2 NB2 : I removed "stream" and used a string parsing way instead ... probably using more CPU sycles at some point, anyway what is better between // up to you to decide :

  • Consuming less CPU but not working
  • Consuming a little bit more CPU but working 100%

Cheers !

TinyGsmClientSIM7600.zip

simkard69 avatar Oct 30 '21 08:10 simkard69

Couldn't get TinyGSM v0.10.9 SIM7600E GPS part working properly so did this. Not sure if later updates are any better, I haven't tried. Get the GPS raw data and process it outside the library. You have date and time also and ESP32 set time process is at the bottom. Works for me.

void getGPS(){
  char    GPSraw[128];                         //  raw gps data
  char    GPSdata[32][20];                     //  allow space for upto 32 GPS values, 20 bytes wide
  char    GPSdatedata[16], GPStimedata[16];
  char    GPSnorth, GPSeast;
  float   RAWlat = 0, RAWlon = 0;
  int     GPSfixmode = 0;
  int     GPSyear, GPSmonth, GPSdate;             //  GPS date data
  int     GPShours, GPSminutes, GPSseconds;       //  GPS time data
  int     GPSs = 0, GLONASSs = 0, BEIDOUs = 0 ;
  float   accuracy;
  float   GPSaltitude = 0, GPSspeed = 0; 
  int     GPSready = 0;
  int     vsat, usat;                             //  visable, using satelites
  int     t = 0, n = 0, i = 0;

  strcpy (GPSraw, (modem.getGPSraw().c_str()));   // get GPS raw data

  int len = strlen(GPSraw);
  for (i = 0; i <= len; i++) {
    if (GPSraw[i] != ',') {
      if (n <= 16) {
        GPSdata[n][t] = GPSraw[i];
        t++;
      }
    }
    else {
      GPSdata[n][t] = '\0';
      n++; t = 0;
    }
  }
  Serial.println(GPSraw);
  GPSfixmode = (int)GPSdata[0][0] - 48;
  if (GPSfixmode > 1) {
    GPSs        = atoi(GPSdata[1]);
    GLONASSs    = atoi(GPSdata[2]);
    BEIDOUs     = atoi(GPSdata[3]);
    RAWlat      = atof(GPSdata[4]);
    GPSnorth    = GPSdata[5][0];
    RAWlon      = atof(GPSdata[6]);
    GPSeast     = GPSdata[7][0];
    strcpy(GPSdatedata,  GPSdata[8]);
    strcpy(GPStimedata,  GPSdata[9]);
    GPSaltitude = atof(GPSdata[10]);
    GPSspeed    = atof(GPSdata[11]);  // Knots
    accuracy    = atof(GPSdata[13]);  // PDOP

    if (RAWlat && RAWlon)
    {
      GPSlat = (floor(RAWlat / 100) + fmod(RAWlat, 100.) / 60) *
               (GPSnorth == 'N' ? 1 : -1);
      GPSlong = (floor(RAWlon / 100) + fmod(RAWlon, 100.) / 60) *
                (GPSeast == 'E' ? 1 : -1);
      GPSspeed = GPSspeed * 1.852;  // convert to kph from knots
      sscanf(GPSdatedata, "%2d%2d%4d", &GPSdate, &GPSmonth, &GPSyear);
      sscanf(GPStimedata, "%2d%2d%2d", &GPShours, &GPSminutes, &GPSseconds);
      usat = GPSs + GLONASSs + BEIDOUs;
      vsat = usat; // no usat data available
      GPSready = 1;
    }
  }

 if(GPSready){
     Serial.printf("\n\nLat: %3.8f, Long: %3.8f\n", GPSlatitude, GPSlongitude);
     Serial.printf("Speed: %3.2fKph  Alti: %4.2fM\n", GPSspeed, GPSaltitude);
     Serial.printf("Visible Satellites: %d  Used Satellites: %d\n", vsat, usat);
     Serial.printf("Accuracy: %2.1f\n", accuracy);
     Serial.printf("Date: %d-%d-%d\n", GPSyear, GPSmonth, GPSdate);
     Serial.printf("Time: %d:%d:%d\n\n", GPShours, GPSminutes, GPSseconds);

  if (GPSyear < 2000) {
      GPSyear += 2000;
    }
    time_t  GPSUTCtime = 0;
    struct tm s;
    s.tm_sec    = (GPSseconds);
    s.tm_min    = (GPSminutes);
    s.tm_hour   = (GPShours);
    s.tm_mday   = (GPSdate);
    s.tm_mon    = (GPSmonth - 1);
    s.tm_year   = (GPSyear - 1900);
    GPSUTCtime  = (mktime(&s));
    
    Serial.printf("GPS Time:    %s",  ctime(&GPSUTCtime));
   
    if (GPSUTCtime > 1615155060) {        //  make sure time is not in the past
      setenv("TZ", "CET-1CET-2,M3.5.0/02:00:00,M10.5.0/03:00:00", 1);   //  set local DST settings
      tzset();
      struct timeval tv;
      memset(&tv, 0, sizeof(struct timeval));
      tv.tv_sec = GPSUTCtime;
      settimeofday(&tv, NULL);
    }
   }
 }

star297 avatar Nov 03 '21 19:11 star297