sparkfun / SparkFun_u-blox_GNSS_Arduino_Library

An Arduino library which allows you to communicate seamlessly with the full range of u-blox GNSS modules
Other
226 stars 100 forks source link

Automatic NMEA - VTG, RMC, ZDA #120

Closed TakiKroSmaN closed 2 years ago

TakiKroSmaN commented 2 years ago

Hello,

Could you create the same function for VTG, RMC and ZDA data? My data logger require that data in NMEA structure. Data logger: RaceChrono.

Thank you :) Regards Tomasz.

PaulZC commented 2 years ago

Hi Tomasz (@TakiKroSmaN ), There may be an easy way to do this using processNMEA or setOutputPort. It sounds like you are only using the library as an I2C to serial interface? Adding Auto support for all three messages is quite a lot of work. Please tell me more about your application first. Best wishes, Paul

TakiKroSmaN commented 2 years ago

Hi Paul,

GNSS: NEO-M9N Board: SparkFun Thing Plus - ESP32-S2 WROOM

I'm read over UART NMEA data (enabled only required VTG, RMC, GGA, ZDA) and send it to the TCP/IP client which is RaceChrono apllication on my phone. It's working but with 2-5sec. delay.

`

#include <WiFiClient.h>
#include <WiFi.h>

#include <Wire.h> //Needed for I2C to GNSS

#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;

int port = 80;  //Port number
WiFiServer server(port);

#define Hz 20 // navigation rate
#define Serial1Baud 9600 // 460800  //9600

boolean ledState = LOW;
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long currentMillis = millis();

//Server connect to WiFi Network
const char *ssid = "GNSS";  //Enter your wifi SSID
const char *password = "abcdefghijk";  //Enter your wifi Password

//=======================================================================
//                    Power on setup
//=======================================================================
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  Wire.begin();
  // Wire.setClock(100000);

  while (myGNSS.begin() == false)
  {
    currentMillis = millis();
    if (currentMillis - previousMillis >= 100) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED_BUILTIN, ledState);
    }
  }
  digitalWrite(LED_BUILTIN, LOW);

  Serial1.begin(Serial1Baud);
  myGNSS.setSerialRate(Serial1Baud);

  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password); //Connect to wifi

  IPAddress myIP = WiFi.softAPIP();
  server.begin();

  myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_UART1); //Several of these are on by default on ublox board so let's disable them
  myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_UART1);
  myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_UART1);
  myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_UART1); //Only leaving GGA & VTG enabled at current navigation rate
  myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_UART1);
  myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_UART1);
  myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_UART1);
  myGNSS.setUART1Output(COM_TYPE_NMEA);

  myGNSS.disableDebugging();

  myGNSS.setNavigationFrequency(Hz); //Set output to x times a second
  myGNSS.setMeasurementRate(1000 / Hz);
  myGNSS.setHNRNavigationRate(Hz);
  // Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
  // myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
  myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
  myGNSS.setDynamicModel(DYN_MODEL_AUTOMOTIVE);
  // Tell the library we are expecting the module to send PVT messages by itself to our Rx pin.
  // You can set second parameter to "false" if you want to control the parsing and eviction of the data (need to call checkUblox cyclically)
  myGNSS.assumeAutoPVT(true, true);

  //myGNSS.saveConfiguration();

  /*  Serial.print("Open Telnet and connect to IP:");
    Serial.print(myIP);
    Serial.print(" on port ");
    Serial.println(port);*/
}
//=======================================================================
//                    Loop
//=======================================================================

void loop()
{
  WiFiClient client = server.available();

  if (client) {
    digitalWrite(LED_BUILTIN, HIGH);
    //client.println("Connected");
    client.flush();
    Serial1.flush();
    previousMillis = currentMillis;

    while (client.connected())
    {
      currentMillis = millis();
      if (currentMillis - previousMillis >= 5) {
        previousMillis = currentMillis;
        if (myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false))
        {
          while (Serial1.available()) {
            client.write(Serial1.read());
          }
        }
      }
      else {
        client.flush();
        Serial1.flush();
      }

    }
    digitalWrite(LED_BUILTIN, LOW);
    client.stop();
  }

  else {
    currentMillis = millis();
    if (currentMillis - previousMillis >= 1000) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED_BUILTIN, ledState);
    }
  }
}
//=======================================================================

`

PaulZC commented 2 years ago

Hi Tomasz (@TakiKroSmaN ),

OK. I think I understand what you are trying to do.

Please check that 9600 baud is fast enough to handle all the NMEA messages at 20Hz. I suspect you are trying to send too much data for 9600 baud. I think you need to use a higher baud rate? You can use setSerialRate to do that.

Instead of using serial, you could enable the NMEA messages on I2C. Then 'process' them (push then to WiFi) with processNMEA. Please see Example2. Delete everything to do with MicroNMEA. Do your client.write from inside processNMEA.

I can see how full "auto" support would help this, but, as I said, it is a lot of work - and you are the only person to have asked for it. ;-)

I am happy to leave this request open, but it will be a long time before I can implement it. If you have time, please add the required code yourself and send me a Pull Request.

Best wishes, Paul

PaulZC commented 2 years ago

Also, it is not clear if you have the PVT messages enabled? Instead of myGNSS.assumeAutoPVT(true, true);, please try myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution. Maybe that is what is causing your code to stall?

TakiKroSmaN commented 2 years ago

OK, I will check your tips and let you know. Thank you :)

TakiKroSmaN commented 2 years ago

So, if I use band higher than 9600 I get communication problem (char error or stall for 1 sec). PVT change doesn't help. When I tried with processNMEA and use serial monitor then it's works but output is around 6Hz.

void loop()
{
  myGNSS.checkUblox();
}
//=======================================================================

void SFE_UBLOX_GNSS::processNMEA(char incoming)
{
  Serial.print(incoming);
}

I have no idea how to put in client.print in to SFE_UBLOX_GNSS::processNMEA becouse if I use while (client.connected) incoming is not refreshing. If I use some other option then client after sent char is disconnected. Is there any other fuction which I can use to get data from I2C?

PaulZC commented 2 years ago

If we think about how much data you are trying to transfer:

GGA + VTG + RMC + ZDA

$GPGGA,002153.000,3342.6618,N,11751.3858,W,1,10,1.2,27.0,M,-34.2,M,,00005E $GPVTG,309.62,T, ,M,0.13,N,0.2,K,A23 $GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598, ,10 $GPZDA,181813,14,10,2003,00,004F

That is 223 characters. And that doesn't include the extra decimal places for the high resolution Lat and Lon.

At 20Hz, you are trying to transfer close to 4500 Bytes per second. For serial, that is 45000 bits per second.

So for serial, you need to use at least 57600 baud. Probably 115200 to be safe.

100kHz I2C should be OK.

But that does not include the PVT message. That adds another 100 Bytes per message.

At 20Hz, you're now trying to transfer 6500 Bytes per second. 65000 bits per second. 115200 baud serial is probably OK, but 100kHz I2C is not looking good - there are large overheads with the I2C bus data transfer.

Then you need to think about how large your buffers are. Is the serial receive buffer in the ESP32 large enough to hold the data while you transfer it to WiFi, or will it overflow?

Then there is the data rate the ESP32 to phone WiFi connection can actually support - with all the transfer and application overheads. I do not know what that figure is.

processNMEA is called each time a single character is processed. You may get better results if:

I hope this helps! Best wishes, Paul

PaulZC commented 2 years ago

Hi Tomasz (@TakiKroSmaN ),

It is your lucky day!

I was doing more work on the library and decided to add the auto support you requested. Please see the new auto-NMEA examples 3 and 4 for more details. v2.2.3 will be released in a few minutes.

Good luck with your project, Paul

TakiKroSmaN commented 2 years ago

Thank you very much! everything works perfect :)