diff --git a/examples/Example16_AutoPVT_ExplicitUpdate/Example16_AutoPVT_ExplicitUpdate.ino b/examples/Example16_AutoPVT_ExplicitUpdate/Example16_AutoPVT_ExplicitUpdate.ino new file mode 100644 index 0000000..3919959 --- /dev/null +++ b/examples/Example16_AutoPVT_ExplicitUpdate/Example16_AutoPVT_ExplicitUpdate.ino @@ -0,0 +1,98 @@ +/* + Configuring the GPS to automatically send position reports over I2C, with explicit data parsing calls + By: Nathan Seidle Thorsten von Eicken and Felix Jirka + SparkFun Electronics + Date: July 1st, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to configure the U-Blox GPS the send navigation reports automatically + and retrieving the latest one via checkUblox when available. + This eliminates the implicit update in getPVT when accessing data fields twice. + Also this reduces the memory overhead of a separate buffer while introducing a slight error by inconsistencies because of the unsynchronized updates (on a multi core system). + + This can be used over serial or over I2C, this example shows the I2C use. With serial the GPS + simply outputs the UBX_NAV_PVT packet. With I2C it queues it into its internal I2C buffer (4KB in + size?) where it can be retrieved in the next I2C poll. + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + myGPS.setNavigationFrequency(2); //Produce two solutions per second + myGPS.setAutoPVT(true, false); //Tell the GPS to "send" each solution and the lib not to update stale data implicitly + myGPS.saveConfiguration(); //Save the current settings to flash and BBR +} + +/* + Calling getPVT would return false now (compare to Example 13 where it would return true), so we just use the data provided + If you are using a threaded OS eg. FreeRTOS on an ESP32, the explicit mode of autoPVT allows you to use the data provided on both cores and inside multiple threads + The data update in background creates an inconsistent state, but that should not cause issues for most applications as they usually won't change the GPS location significantly within a 2Hz - 5Hz update rate. + Also you could oversample (10Hz - 20Hz) the data to smooth out such issues... +*/ +void loop() +{ + static uint16_t counter = 0; + + if (counter % 10 == 0) { + // update your AHRS filter here for a ~100Hz update rate + // GPS data will be quasi static but data from your IMU will be changing + } + // debug output each half second + if (counter % 500 == 0) { + Serial.println(); + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGPS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + Serial.println(); + } + // call checkUblox all 50ms to capture the gps data + if (counter % 50 == 0) { + myGPS.checkUblox(); + } + delay(1); + counter++; +} diff --git a/examples/Example17_AssumeAutoPVTviaUart/Example17_AssumeAutoPVTviaUart.ino b/examples/Example17_AssumeAutoPVTviaUart/Example17_AssumeAutoPVTviaUart.ino new file mode 100644 index 0000000..ce9a74b --- /dev/null +++ b/examples/Example17_AssumeAutoPVTviaUart/Example17_AssumeAutoPVTviaUart.ino @@ -0,0 +1,79 @@ +/* + Reading lat and long via UBX binary commands using an RX-only UART + By: Nathan Seidle, Adapted from Example11 by Felix Jirka + SparkFun Electronics + Date: July 2nd, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to configure the library for serial port use with a single wire connection using the assumeAutoPVT method. + Saving your pins for other stuff :-) + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Preconditions: + U-Blox module is configured to send cyclical PVT message + Hardware Connections: + Connect the U-Blox serial TX pin to Rx of Serial2 (default: GPIO16) on your ESP32 + Open the serial monitor at 115200 baud to see the output +*/ + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example 17"); + + //Use any Serial port with at least a Rx Pin connected or a receive only version of SoftwareSerial here + //Assume that the U-Blox GPS is running at 9600 baud (the default) + Serial2.begin(9600); + // no need to check return value as internal call to isConnected() will not succeed + myGPS.begin(Serial2); + + // tell lib, 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) + myGPS.assumeAutoPVT(true, true); + +} + +void loop() +{ + // if implicit updates are allowed, this will trigger parsing the incoming messages + // and be true once a PVT message has been parsed + // In case you want to use explicit updates, wrap this in a timer and call checkUblox as often as needed, not to overflow your UART buffers + if (myGPS.getPVT()) + { + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGPS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + Serial.println(); + } + else { + Serial.println(F("Wait for GPS data")); + delay(500); + } +} diff --git a/keywords.txt b/keywords.txt index 5c7b301..2a0a833 100644 --- a/keywords.txt +++ b/keywords.txt @@ -88,6 +88,7 @@ debugPrintln KEYWORD2 factoryReset KEYWORD2 setAutoPVT KEYWORD2 +assumeAutoPVT KEYWORD2 getYear KEYWORD2 getMonth KEYWORD2 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index d05b0a2..6a75db2 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1308,9 +1308,29 @@ uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait) return (measurementRate); } +//In case no config access to the GPS is possible and PVT is send cyclically already +//set config to suitable parameters +boolean SFE_UBLOX_GPS::assumeAutoPVT(boolean enabled, boolean implicitUpdate) +{ + boolean changes = autoPVT != enabled || autoPVTImplicitUpdate != implicitUpdate; + if(changes) + { + autoPVT = enabled; + autoPVTImplicitUpdate = implicitUpdate; + } + return changes; +} + //Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT //works. boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, uint16_t maxWait) +{ + return setAutoPVT(enable, true, maxWait); +} + +//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT +//works. +boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16_t maxWait) { packetCfg.cls = UBX_CLASS_CFG; packetCfg.id = UBX_CFG_MSG; @@ -1322,7 +1342,10 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, uint16_t maxWait) bool ok = sendCommand(packetCfg, maxWait); if (ok) + { autoPVT = enable; + autoPVTImplicitUpdate = implicitUpdate; + } moduleQueried.all = false; return ok; } @@ -1428,12 +1451,17 @@ int32_t SFE_UBLOX_GPS::getNanosecond(uint16_t maxWait) //Get the latest Position/Velocity/Time solution and fill all global variables boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) { - if (autoPVT) + if (autoPVT && autoPVTImplicitUpdate) { //The GPS is automatically reporting, we just check whether we got unread data checkUblox(); return moduleQueried.all; } + else if(autoPVT && !autoPVTImplicitUpdate) + { + //Someone else has to call checkUblox for us... + return (false); + } else { //The GPS is not automatically reporting navigation position so we have to poll explicitly @@ -1543,6 +1571,7 @@ uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) return (tempAccuracy); } + //Get the current latitude in degrees //Returns a long representing the number of degrees *10^-7 int32_t SFE_UBLOX_GPS::getLatitude(uint16_t maxWait) diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index c2dbd34..d9205ef 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -234,8 +234,10 @@ class SFE_UBLOX_GPS boolean waitForResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = 250); //Poll the module until and ack is received + boolean assumeAutoPVT(boolean enabled, boolean implicitUpdate = true); //In case no config access to the GPS is possible and PVT is send cyclically already boolean setAutoPVT(boolean enabled, uint16_t maxWait = 250); //Enable/disable automatic PVT reports at the navigation frequency boolean getPVT(uint16_t maxWait = 1000); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. + boolean setAutoPVT(boolean enabled, boolean implicitUpdate, uint16_t maxWait = 250); //Enable/disable automatic PVT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update boolean getHPPOSLLH(uint16_t maxWait = 1000); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. int32_t getLatitude(uint16_t maxWait = 250); //Returns the current latitude in degrees * 10^-7. Auto selects between HighPrecision and Regular depending on ability of module. @@ -435,6 +437,7 @@ class SFE_UBLOX_GPS unsigned long lastCheck = 0; boolean autoPVT = false; //Whether autoPVT is enabled or not + boolean autoPVTImplicitUpdate = true; // Whether autoPVT is triggered by accessing stale data (=true) or by a call to checkUblox (=false) boolean commandAck = false; //This goes true after we send a command and it's ack'd uint8_t ubxFrameCounter;