first commit

This commit is contained in:
Alejandro Guerrero 2026-09-27 17:21:39 +02:00
commit e6a42e28e9
4355 changed files with 4626605 additions and 0 deletions

View file

@ -0,0 +1,188 @@
/*
Monitor AssistNow Autonomous data collection
By: SparkFun Electronics / Paul Clark
Date: November 29th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to enable and monitor AssistNow Autonomous data collection by the module.
A callback is used to monitor AssistNow Autonomous data availability for each satellite.
A second callback is used to print the AOPSTATUS status.
If your GNSS board has battery-backup for the RAM - and all SparkFun boards do! - then you can:
wait until the module has AssistNow Autonomous data for a few satellites;
power-cycle the board;
watch how fast it gets its first fix!
Note: this example will only work on boards which have plenty of RAM available.
The UBX-NAV-SAT information occupies several kBytes.
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printSATdata will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("UBX-NAV-SAT contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
numAopAvail++; // Increment the number of SVs
}
Serial.print(F("AssistNow Autonomous data is available for "));
Serial.print(numAopAvail);
if (numAopAvail == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("AOPSTATUS status is "));
Serial.println(ubxDataStruct->status);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
Serial.println();
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte fixType = ubxDataStruct->fixType; // Print the fix type
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see the 'major' debug messages on Serial
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable AssistNow Autonomous data collection.
if (myGNSS.setAopCfg(1) == true)
{
Serial.println(F("aopCfg enabled"));
}
else
{
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
while (1);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,207 @@
/*
Read the AssistNow Autonomous database from the module
By: SparkFun Electronics / Paul Clark
Date: November 29th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to enable, check the status of, and read the AssistNow Autonomous data from the module.
Note: this example will only work on boards which have plenty of RAM available.
The database can be several kBytes in length.
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printSATdata will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("UBX-NAV-SAT contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
numAopAvail++; // Increment the number of SVs
}
Serial.print(F("AssistNow Autonomous data is available for "));
Serial.print(numAopAvail);
if (numAopAvail == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("AOPSTATUS status is "));
Serial.println(ubxDataStruct->status);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable AssistNow Autonomous data collection.
if (myGNSS.setAopCfg(1) == true)
{
Serial.println(F("aopCfg enabled"));
}
else
{
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
while (1);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Keep displaying NAV SAT and AOPSTATUS until the user presses a key
Serial.println(F("AssistNow Autonomous data collection is in progress. Press any key to quit and read the database."));
while (Serial.available()) Serial.read(); // Empty the serial buffer
while (!Serial.available()) // Wait for the arrival of a keypress
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}
Serial.println();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disable the automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages
myGNSS.setAutoNAVSAT(false);
myGNSS.setAutoAOPSTATUS(false);
delay(1100);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Read the AssistNow Autonomous database from the module and pretty-print it (so it can be copied and pasted into the next example)
#define MAX_DATABASE_LENGTH 32768 // Allocate 32kBytes to store the navigation database
size_t maxDatabaseLen = MAX_DATABASE_LENGTH;
uint8_t *database = new uint8_t[MAX_DATABASE_LENGTH]; // The database will be stored here
Serial.println(F("Storage has been allocated for the database.")); Serial.flush();
size_t actualDatabaseLen = myGNSS.readNavigationDatabase(database, maxDatabaseLen); // Read the database
Serial.print(F("The Navigation Database length was "));
Serial.println(actualDatabaseLen);
if (actualDatabaseLen == maxDatabaseLen)
Serial.println(F("There was not enough memory to store the entire database. Some data will have been lost!"));
// Pretty-print the database so it can be copied into the next example
Serial.println(F("Copy and paste the following into the next example, so you can write it back to the module:"));
Serial.println();
Serial.print(F("size_t databaseLen = "));
Serial.print(actualDatabaseLen);
Serial.println(F(";"));
Serial.print(F("const uint8_t database["));
Serial.print(actualDatabaseLen);
Serial.println(F("] = {"));
size_t i;
for(i = 0; i < actualDatabaseLen; i++)
{
if ((i % 32) == 0)
Serial.print(F(" 0x"));
if (*(database + i) < 0x10) // Print leading zero
Serial.print(F("0"));
Serial.print(*(database + i), HEX);
if (i == (actualDatabaseLen - 1))
Serial.println();
else if ((i % 32) == 31)
Serial.println(F(","));
else
Serial.print(F(", 0x"));
}
Serial.println(F("};"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Nothing to do here
}

View file

@ -0,0 +1,188 @@
/*
Write the AssistNow Autonomous database data to the module
By: SparkFun Electronics / Paul Clark
Date: December 1st, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to write the AssistNow Autonomous database date back to the module.
This example is written for the ESP32. A WiFi connection is used to get network time to pass to the module.
(You could use an RTC instead.)
Copy and paste the database data from the previous example into database.h.
Update secrets.h with your:
- WiFi credentials
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Note: this example works best if you have the GNSS RAM battery-backup disabled.
All SparkFun boards have battery-backup for the RAM which will means the database is retained if you disconnect the power.
The module will use the database data from the battery-backed RAM when you turn the power back on.
You will only see the improvement in the time-to-first-fix if you disable the battery first - or you are using a non-SparkFun
board that does not have the backup battery.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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 "database.h" // <- Copy and paste the database data from the previous example into database.h
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow Autonomous data to the module
size_t bytesPushed = myGNSS.pushAssistNowData(database, databaseLen);
Serial.print(F("Pushed "));
Serial.print(bytesPushed);
Serial.println(F(" bytes of AssistNow Autonomous data to the module"));
if (bytesPushed != databaseLen)
Serial.println(F("Warning: bytesPushed does not match databaseLen! Maybe the database contains bad data? Or there was a communication error?"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,177 @@
// Paste the AssistNow Autonomous database data from the previous example here:
size_t databaseLen = 5480;
const uint8_t database[5480] = {
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x08, 0xC4, 0x04, 0x26, 0xFE, 0x02, 0x54, 0xBA, 0xA9,
0xFF, 0xDA, 0x8C, 0x05, 0xA3, 0xC1, 0xCD, 0x85, 0x86, 0x0A, 0x14, 0x20, 0xAA, 0xE6, 0xB4, 0xD3, 0x4F, 0x27, 0x12, 0xE0, 0xE6, 0xC3, 0xE4, 0x79, 0x0E, 0xA1, 0xD3, 0x49, 0xF4, 0xFF, 0xAF, 0xF7,
0x67, 0x2E, 0x93, 0xF9, 0x6A, 0x1B, 0x2D, 0x10, 0xD3, 0x49, 0xBD, 0xFF, 0x26, 0x01, 0x00, 0x1E, 0x81, 0x22, 0xA1, 0xE4, 0x2A, 0x00, 0x10, 0x50, 0x04, 0x00, 0xB7, 0xBF, 0xB5, 0x62, 0x13, 0x80,
0x54, 0x00, 0x01, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x1E, 0xC4, 0x44, 0x72, 0x2F, 0x02, 0x71, 0xAD, 0xA4, 0xFF, 0xE8, 0xAE, 0xFA,
0x42, 0x25, 0xD1, 0x0F, 0x0D, 0x03, 0xCB, 0x71, 0xCF, 0x12, 0x6F, 0x89, 0x0F, 0x27, 0xF3, 0x49, 0x7B, 0x29, 0x4B, 0xF1, 0x0C, 0xA1, 0xD4, 0x49, 0xF5, 0xFF, 0xB6, 0x03, 0x98, 0x36, 0xA0, 0x03,
0xBB, 0x0F, 0x72, 0x1D, 0xD4, 0x49, 0xEE, 0xFF, 0x17, 0x00, 0x00, 0xC0, 0x85, 0x22, 0x2F, 0xF0, 0x3D, 0x00, 0x3C, 0x50, 0x04, 0x00, 0x1A, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00,
0x00, 0x07, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5B, 0xC4, 0x44, 0xD8, 0xEC, 0x02, 0x4E, 0x79, 0xAC, 0xFF, 0xE8, 0x8A, 0x1D, 0xBC, 0x9F, 0xE8, 0x86,
0xD9, 0x07, 0x45, 0xD0, 0x05, 0x6A, 0x05, 0x06, 0xC3, 0x26, 0xB5, 0x7D, 0x4A, 0xA2, 0x86, 0xCA, 0x0D, 0xA1, 0xD4, 0x49, 0x2B, 0x00, 0x62, 0x07, 0x63, 0x2F, 0xF5, 0x05, 0x1E, 0x1A, 0x98, 0x10,
0xD4, 0x49, 0x38, 0x00, 0xBA, 0xFF, 0x00, 0xCB, 0xBE, 0x22, 0xF4, 0x59, 0x09, 0x00, 0xB6, 0x50, 0x04, 0x00, 0x2E, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x09, 0x15, 0x0C,
0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E, 0xC4, 0x44, 0xFA, 0x7B, 0x02, 0x4E, 0x1B, 0xA5, 0xFF, 0x03, 0x6E, 0x07, 0xF5, 0x25, 0xF3, 0xB8, 0x36, 0x01, 0xDB, 0x4F,
0x56, 0x3E, 0x8D, 0xA6, 0xD7, 0x26, 0x82, 0xFE, 0xA8, 0x4A, 0x7A, 0x44, 0x0D, 0xA1, 0xD4, 0x49, 0x05, 0x00, 0x7A, 0xFA, 0x1C, 0x37, 0xDC, 0xFA, 0x33, 0x0E, 0x7E, 0x1E, 0xD4, 0x49, 0xE5, 0xFF,
0xFC, 0xFF, 0x00, 0xB7, 0xBA, 0x22, 0x87, 0x2A, 0x34, 0x00, 0xBC, 0x50, 0x04, 0x00, 0xDF, 0x11, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00,
0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x2F, 0xC4, 0x44, 0xC7, 0x68, 0x00, 0xF6, 0x09, 0xAA, 0xFF, 0xED, 0xB8, 0x38, 0x24, 0x1C, 0xE8, 0xC5, 0x30, 0x00, 0xD0, 0x23, 0x17, 0xEC, 0xF7, 0x92,
0x2D, 0x27, 0x7C, 0x39, 0x2C, 0x6B, 0x66, 0xF5, 0x0D, 0xA1, 0xD4, 0x49, 0xEA, 0xFF, 0x27, 0xF9, 0x09, 0x2F, 0x2B, 0xFA, 0x6A, 0x1B, 0xFB, 0x0F, 0xD4, 0x49, 0x01, 0x00, 0x0F, 0x00, 0x00, 0xC1,
0x82, 0x22, 0x2A, 0x8A, 0x80, 0xFF, 0x5E, 0x50, 0x04, 0x00, 0x52, 0xBB, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x0C, 0x96, 0xC4, 0x44, 0x8E, 0xBD, 0x02, 0xE4, 0x39, 0xA6, 0xFF, 0xE8, 0x7E, 0xBE, 0x5F, 0xFE, 0xF3, 0xCA, 0xF0, 0x02, 0x5D, 0x9F, 0x84, 0x44, 0x3A, 0xC9, 0x6F, 0x27, 0xFD, 0x1B,
0xDB, 0x27, 0x60, 0x63, 0x0D, 0xA1, 0xD4, 0x49, 0x32, 0x00, 0x4B, 0xFA, 0xA6, 0x33, 0x2C, 0xFB, 0x5C, 0x10, 0xB8, 0x1C, 0xD4, 0x49, 0x0E, 0x00, 0x1E, 0x00, 0x00, 0x0D, 0xB9, 0x22, 0x3A, 0x4D,
0x07, 0x00, 0x2C, 0x51, 0x04, 0x00, 0x76, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x22,
0xC4, 0x44, 0x47, 0xD2, 0x02, 0x47, 0xEA, 0xA3, 0xFF, 0xEA, 0x53, 0xBB, 0xBD, 0x37, 0xBE, 0x0A, 0x5B, 0x06, 0x85, 0x4F, 0x13, 0x98, 0x48, 0x33, 0x95, 0x27, 0xC8, 0x3B, 0xE7, 0x1B, 0x37, 0x8F,
0x0C, 0xA1, 0xD4, 0x49, 0xC9, 0xFF, 0x09, 0x0C, 0x98, 0x30, 0xB3, 0x0A, 0x16, 0x09, 0x14, 0x26, 0xD4, 0x49, 0xB3, 0xFF, 0x4E, 0x00, 0x00, 0xE0, 0x81, 0x22, 0x2D, 0xCD, 0x31, 0x00, 0x44, 0x50,
0x04, 0x00, 0x39, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x1B, 0xC4, 0x44, 0x6A, 0xD2,
0x02, 0xE9, 0x7C, 0xA3, 0xFF, 0xEE, 0xD1, 0x59, 0xEE, 0xE7, 0x56, 0x56, 0xCC, 0x02, 0xE4, 0x2C, 0x39, 0x0E, 0xB6, 0x13, 0x56, 0x26, 0xDF, 0xE5, 0x41, 0x7C, 0xDA, 0x86, 0x0D, 0xA1, 0xD4, 0x49,
0xFE, 0xFF, 0x81, 0x04, 0x73, 0x3A, 0x0F, 0x04, 0x54, 0x10, 0x59, 0x1B, 0xD4, 0x49, 0x37, 0x00, 0xDF, 0xFF, 0x00, 0x21, 0x87, 0x22, 0x0B, 0xF8, 0x10, 0x00, 0x36, 0x50, 0x04, 0x00, 0x75, 0x76,
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x31, 0xC4, 0xC4, 0x58, 0xF9, 0x02, 0xFC, 0xD0, 0xA5,
0xFF, 0xEA, 0x04, 0x79, 0x3B, 0x17, 0xD6, 0x48, 0xEF, 0x00, 0xB9, 0x34, 0x1C, 0xC2, 0x1E, 0x93, 0x05, 0x28, 0xA0, 0x7E, 0x9D, 0x60, 0x7C, 0x63, 0x0C, 0xA1, 0xD4, 0x49, 0xD2, 0xFF, 0x51, 0xF4,
0xD6, 0x2D, 0xD9, 0xF5, 0x45, 0x08, 0x41, 0x27, 0xD4, 0x49, 0x23, 0x00, 0xFE, 0xFF, 0x00, 0x7C, 0xBC, 0x22, 0x15, 0x51, 0x31, 0x00, 0x62, 0x50, 0x04, 0x00, 0xEC, 0xE1, 0xB5, 0x62, 0x13, 0x80,
0x54, 0x00, 0x01, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x22, 0xC4, 0x04, 0x53, 0x24, 0x02, 0xF4, 0x99, 0xA8, 0xFF, 0x08, 0x62, 0xE5,
0x6F, 0x9E, 0x9C, 0x48, 0xBC, 0x02, 0xB4, 0x07, 0x9B, 0x6A, 0x21, 0x82, 0x28, 0x26, 0x78, 0x77, 0x0C, 0x90, 0x2F, 0xF9, 0x0C, 0xA1, 0xD4, 0x49, 0xE5, 0xFF, 0x34, 0x08, 0x30, 0x33, 0xC0, 0x06,
0x34, 0x1B, 0x7C, 0x0E, 0xD4, 0x49, 0xF7, 0xFF, 0xEE, 0xFF, 0x00, 0x19, 0xBE, 0x22, 0x6F, 0xC0, 0x2F, 0x00, 0x44, 0x50, 0x04, 0x00, 0x93, 0x6D, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x07, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xA5, 0xB9, 0xC6, 0x04, 0x16, 0x44, 0x02, 0xC6, 0xE0, 0xD9, 0x21, 0x1C, 0xC0, 0xE0, 0xF8, 0xD5, 0x3D, 0x6E,
0x01, 0x56, 0x21, 0xC1, 0x0F, 0x39, 0xF8, 0x70, 0x2D, 0x10, 0x7F, 0xFF, 0x10, 0x38, 0xEE, 0xA5, 0x80, 0x00, 0x00, 0xE8, 0x55, 0x0C, 0x1C, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x0F, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAD, 0xB9, 0xC6, 0x04, 0x6F, 0x28, 0x02, 0x17, 0x5C, 0xB7, 0xE5, 0xF7, 0x80, 0x1F, 0x46, 0x2A, 0xDE, 0xBE,
0xF0, 0x59, 0x45, 0x5C, 0xCE, 0x39, 0x75, 0x99, 0xF7, 0x10, 0x1B, 0x7B, 0xFF, 0x78, 0x18, 0x5D, 0xFE, 0x00, 0x00, 0xE8, 0x55, 0x07, 0xC8, 0x8F, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x10, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xB9, 0xC6, 0x84, 0x26, 0x63, 0x02, 0x0C, 0x60, 0x9D, 0xDA, 0x44, 0x5E, 0xE2, 0x3C, 0x27, 0xDD, 0xED,
0xF5, 0x3B, 0xDE, 0xC1, 0xDE, 0x39, 0xA7, 0xDD, 0xF9, 0x20, 0x11, 0x54, 0x2A, 0x80, 0xFB, 0x6C, 0x80, 0x00, 0xFF, 0xEF, 0x55, 0x06, 0x17, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x15, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xB9, 0xC6, 0x04, 0x6F, 0xC3, 0x02, 0xF0, 0xC6, 0x33, 0xC1, 0x45, 0x3F, 0x28, 0xC9, 0xBB, 0xBF, 0x1B,
0x1B, 0xEC, 0x14, 0xF1, 0xF5, 0x39, 0x55, 0x25, 0x06, 0x30, 0x84, 0xAE, 0xC7, 0xA8, 0x89, 0x3D, 0x44, 0x00, 0xFD, 0xEF, 0x55, 0x0B, 0x89, 0xE0, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x17, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB5, 0xB9, 0xC6, 0x04, 0x34, 0xBC, 0x02, 0xF5, 0xBE, 0x0D, 0x15, 0xEA, 0x21, 0xA3, 0xC8, 0xDB, 0x1E, 0x3A,
0x31, 0x5A, 0x38, 0xB6, 0x20, 0x39, 0x8B, 0x4A, 0xD9, 0x30, 0xDF, 0x66, 0xF8, 0xB8, 0x9D, 0x5B, 0x00, 0x02, 0xFF, 0xEF, 0x55, 0x0A, 0x20, 0x5A, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x01, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x00, 0x7B, 0xB0, 0x04, 0xC5, 0xE4, 0x01, 0x73, 0x47, 0x5B, 0xAE, 0x1C, 0x18, 0x0D, 0xA1, 0x00, 0x65, 0xFD,
0x00, 0x7B, 0x41, 0x2C, 0xEA, 0x00, 0x14, 0x16, 0x24, 0x00, 0xF1, 0x02, 0x67, 0x00, 0x06, 0xEA, 0x3F, 0x8A, 0xA4, 0x7B, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x02, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x7B, 0xB0, 0x44, 0x66, 0x1F, 0x03, 0xC2, 0x82, 0xA8, 0x90, 0x0E, 0x1C, 0x0E, 0xA1, 0x00, 0x4E, 0xFD, 0x00, 0x7B, 0x4F, 0x99,
0xE6, 0x00, 0xF3, 0xEB, 0xC3, 0x00, 0xE8, 0x8A, 0x6E, 0x00, 0x5C, 0x05, 0x00, 0x8A, 0xDF, 0xF9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x03, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x02, 0x7B, 0xB0, 0x04, 0x96, 0x8D, 0x01, 0xEB, 0x94, 0x1F, 0x20, 0x13, 0x6B, 0x0D, 0xA1, 0x00, 0x69, 0xFD, 0x00, 0x7B, 0xC1, 0x59, 0x14, 0x00, 0x8A, 0xAC,
0x28, 0x00, 0xDD, 0x24, 0x37, 0x00, 0xE0, 0xEF, 0x3F, 0x8A, 0x0F, 0xED, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x04, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x03, 0x7B, 0xB0, 0x44, 0x8F, 0x51, 0x01, 0xFF, 0xCA, 0x0C, 0xA8, 0x0B, 0xD6, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0x00, 0x7B, 0x3F, 0x67, 0x40, 0x00, 0x77, 0x26, 0x80, 0x00, 0x3A, 0x7C,
0xB2, 0x00, 0x2E, 0x07, 0x00, 0x8A, 0xD8, 0xB6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x00,
0xB0, 0x14, 0xB8, 0x76, 0x03, 0xEA, 0xD0, 0x30, 0x92, 0x0A, 0xF1, 0x0C, 0xA1, 0x00, 0x25, 0xFD, 0xD4, 0x49, 0x71, 0xCF, 0x12, 0x00, 0x49, 0x7B, 0x29, 0x00, 0xFA, 0x42, 0x25, 0x00, 0xBE, 0xFF,
0x3F, 0x8A, 0xD6, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x06, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x05, 0x7B, 0xB0, 0x44, 0xBB, 0x76,
0x01, 0x15, 0x1F, 0x14, 0x47, 0x1C, 0xB5, 0x0C, 0xA1, 0x00, 0x63, 0xFD, 0x00, 0x7B, 0x16, 0xD6, 0xE9, 0x00, 0xEC, 0xC2, 0xD5, 0x00, 0xAB, 0x35, 0x77, 0x00, 0x8C, 0x18, 0x80, 0x8A, 0x81, 0xB1,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x00, 0xB0, 0x14, 0x33, 0xF6, 0x03, 0x49, 0x98, 0x7D,
0xC9, 0x05, 0xCA, 0x0D, 0xA1, 0x00, 0x63, 0xFD, 0xD4, 0x49, 0xD0, 0x05, 0x6A, 0x00, 0x7D, 0x4A, 0xA2, 0x00, 0x1D, 0xBC, 0x9F, 0x00, 0x2B, 0x09, 0x00, 0x8A, 0x4B, 0xEC, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x08, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x07, 0x7B, 0xB0, 0x04, 0x04, 0xE8, 0x01, 0xB3, 0x40, 0x38, 0xDD, 0x0E, 0x13, 0x0D,
0xA1, 0x00, 0x22, 0xFD, 0x00, 0x7B, 0x33, 0x39, 0xBE, 0x00, 0x60, 0x6D, 0x02, 0x00, 0xAF, 0xE0, 0xC5, 0x00, 0xCF, 0x07, 0x80, 0x8A, 0x59, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x09, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x00, 0xB0, 0x14, 0x50, 0xB2, 0x03, 0x0A, 0x6B, 0x13, 0x14, 0x07, 0x44, 0x0D, 0xA1, 0x00, 0x28, 0xFD,
0xD4, 0x49, 0x4F, 0x56, 0x3E, 0x00, 0xFE, 0xA8, 0x4A, 0x00, 0x07, 0xF5, 0x25, 0x00, 0x85, 0x06, 0x00, 0x8A, 0x09, 0xB0, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0A, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x09, 0x7B, 0xB0, 0x44, 0x94, 0x64, 0x01, 0x0C, 0xB3, 0x3B, 0x06, 0x13, 0x0D, 0x0D, 0xA1, 0x00, 0x6E, 0xFD, 0x00, 0x7B, 0x68, 0x3C,
0x14, 0x00, 0x15, 0x6E, 0x97, 0x00, 0x53, 0x99, 0x16, 0x00, 0xEF, 0xF6, 0xBF, 0x8A, 0xC1, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x7B, 0xB0, 0x04, 0xF5, 0x0B, 0x01, 0xDE, 0x10, 0x03, 0x70, 0x0C, 0x97, 0x0D, 0xA1, 0xFF, 0x52, 0xFD, 0x00, 0x7B, 0x7A, 0x06, 0xEC, 0x00, 0xA3, 0x44,
0x6B, 0x00, 0xA1, 0xEB, 0xC8, 0x00, 0x11, 0xF8, 0xBF, 0x8A, 0xB4, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x0B, 0x7B, 0xB0, 0x04, 0xFD, 0x31, 0x01, 0x09, 0xE0, 0x44, 0xFA, 0x12, 0xD4, 0x0C, 0xA1, 0x00, 0x54, 0xFD, 0x00, 0x7B, 0xBC, 0x3F, 0x97, 0x00, 0x0C, 0x17, 0x32, 0x00, 0x5D, 0xE0,
0x30, 0x00, 0x72, 0xF7, 0xBF, 0x8A, 0x91, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x00,
0xB0, 0x14, 0x82, 0xD3, 0x03, 0x6F, 0x0C, 0x2F, 0x96, 0x10, 0x63, 0x0D, 0xA1, 0x00, 0x31, 0xFD, 0xD4, 0x49, 0x9F, 0x84, 0x44, 0x00, 0x1B, 0xDB, 0x27, 0x00, 0xBE, 0x5F, 0xFE, 0x00, 0xE9, 0x08,
0x00, 0x8A, 0x4A, 0x74, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0E, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0D, 0x7B, 0xB0, 0x44, 0x3E, 0xB1,
0x01, 0x66, 0xD7, 0x09, 0x30, 0x08, 0xCD, 0x0C, 0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x72, 0x05, 0x96, 0x00, 0x85, 0x34, 0x7E, 0x00, 0xFE, 0xFB, 0x2F, 0x00, 0xCC, 0xF7, 0xBF, 0x8A, 0x3C, 0x14,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0E, 0x7B, 0xB0, 0x44, 0x92, 0xB0, 0x01, 0xBF, 0xF2, 0x71,
0x4F, 0xF7, 0x0E, 0x0D, 0xA1, 0x00, 0x26, 0xFD, 0x00, 0x7B, 0x66, 0x06, 0x3A, 0x00, 0xAE, 0x39, 0x2B, 0x00, 0xEF, 0x2D, 0x9C, 0x00, 0x95, 0x0F, 0x80, 0x8A, 0x3F, 0x35, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x00, 0xB0, 0x14, 0x96, 0x34, 0x03, 0x8E, 0xB0, 0x65, 0xEC, 0x12, 0x8F, 0x0C,
0xA1, 0x00, 0x1F, 0xFD, 0xD4, 0x49, 0x4F, 0x13, 0x98, 0x00, 0x3B, 0xE7, 0x1B, 0x00, 0xBB, 0xBD, 0x37, 0x00, 0x39, 0xF6, 0x3F, 0x8A, 0xF3, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x11, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x10, 0x7B, 0xB0, 0x04, 0x5E, 0xE6, 0x01, 0xF3, 0xDF, 0x70, 0xA4, 0x18, 0x50, 0x0D, 0xA1, 0x00, 0x34, 0xFD,
0x00, 0x7B, 0x86, 0x84, 0xC1, 0x00, 0x0F, 0xBA, 0xC1, 0x00, 0xF9, 0x59, 0xC2, 0x00, 0x39, 0x0A, 0x80, 0x8A, 0x83, 0x21, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x12, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x11, 0x7B, 0xB0, 0x04, 0x92, 0xB3, 0x01, 0xCD, 0x23, 0x11, 0x1A, 0x12, 0xC7, 0x0C, 0xA1, 0x00, 0x57, 0xFD, 0x00, 0x7B, 0x1B, 0x89,
0xEA, 0x00, 0x3E, 0x35, 0x7D, 0x00, 0x7D, 0xB8, 0x6F, 0x00, 0x2B, 0xF1, 0xBF, 0x8A, 0x1F, 0x89, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x13, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x7B, 0xB0, 0x44, 0xDE, 0x29, 0x01, 0x15, 0x35, 0x49, 0xCA, 0x17, 0xF3, 0x0C, 0xA1, 0x00, 0x30, 0xFD, 0x00, 0x7B, 0xBE, 0x59, 0xC3, 0x00, 0xEA, 0xA7,
0x50, 0x00, 0xBF, 0x3E, 0x23, 0x00, 0x5C, 0x08, 0x80, 0x8A, 0x31, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x13, 0x00, 0xB0, 0x14, 0x3E, 0x72, 0x03, 0xA1, 0xC5, 0x2C, 0xFA, 0xFE, 0x86, 0x0D, 0xA1, 0x00, 0x1B, 0xFD, 0xD4, 0x49, 0x2C, 0x39, 0x0E, 0x00, 0xE5, 0x41, 0x7C, 0x00, 0x59, 0xEE,
0xE7, 0x00, 0x1F, 0xFA, 0x3F, 0x8A, 0x05, 0x19, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x15, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x14, 0x7B,
0xB0, 0x44, 0x9E, 0xFA, 0x01, 0xD6, 0x02, 0xC7, 0xCD, 0x0A, 0x8B, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0x38, 0x8D, 0xE6, 0x00, 0x0D, 0x36, 0xD5, 0x00, 0xBA, 0x5E, 0xC7, 0x00, 0xA0, 0x00,
0x80, 0x8A, 0x7F, 0x6E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x16, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x15, 0x7B, 0xB0, 0x44, 0x9E, 0x17,
0x01, 0x24, 0x81, 0x37, 0xE8, 0xFC, 0xEA, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0xDE, 0x06, 0x10, 0x00, 0xD1, 0x69, 0xDC, 0x00, 0xC5, 0x18, 0x94, 0x00, 0x28, 0x16, 0x80, 0x8A, 0xBE, 0x20,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x17, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x16, 0x7B, 0xB0, 0x44, 0x2E, 0xDB, 0x01, 0x43, 0xB7, 0x0F,
0xCC, 0x0F, 0x25, 0x0D, 0xA1, 0x00, 0x68, 0xFD, 0x00, 0x7B, 0x32, 0x3D, 0x13, 0x00, 0x85, 0x6C, 0x73, 0x00, 0xE0, 0xD5, 0x4F, 0x00, 0x1B, 0xF8, 0xBF, 0x8A, 0x13, 0xA5, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x18, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x17, 0x7B, 0xB0, 0x04, 0xAC, 0x23, 0x01, 0x3F, 0x2F, 0x63, 0xE2, 0xFA, 0x29, 0x0D,
0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x90, 0xA3, 0x66, 0x00, 0x3C, 0x04, 0x20, 0x00, 0x7B, 0x4A, 0x74, 0x00, 0x1E, 0x09, 0x80, 0x8A, 0x67, 0xDD, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x19, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x18, 0x7B, 0xB0, 0x04, 0xF3, 0x84, 0x01, 0x2A, 0xEE, 0x52, 0xCB, 0x0A, 0x9F, 0x0D, 0xA1, 0x00, 0x4E, 0xFD,
0x00, 0x7B, 0xFC, 0x28, 0x94, 0x00, 0x03, 0x3B, 0x27, 0x00, 0x5D, 0xC2, 0x28, 0x00, 0x06, 0x11, 0x00, 0x8A, 0xBF, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1A, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x7B, 0xB0, 0x44, 0x12, 0x8B, 0x01, 0xA4, 0xBC, 0x35, 0x56, 0xFE, 0xF0, 0x0C, 0xA1, 0x00, 0x43, 0xFD, 0x00, 0x7B, 0x47, 0x4D,
0x92, 0x00, 0xCE, 0xEF, 0x0C, 0x00, 0x55, 0x6B, 0x0E, 0x00, 0xA9, 0x08, 0x00, 0x8A, 0x09, 0xC6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1A, 0x7B, 0xB0, 0x44, 0x25, 0xAF, 0x01, 0xD4, 0x10, 0x50, 0x81, 0x14, 0xC4, 0x0C, 0xA1, 0x00, 0x29, 0xFD, 0x00, 0x7B, 0xA9, 0xFD, 0xBE, 0x00, 0x17, 0x91,
0x19, 0x00, 0x63, 0x98, 0xC1, 0x00, 0x12, 0xFF, 0x3F, 0x8A, 0x9F, 0x4C, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x1C, 0x00, 0xB0, 0x14, 0x3D, 0x4B, 0x03, 0x1C, 0xF4, 0x0E, 0xF2, 0x19, 0x63, 0x0C, 0xA1, 0x00, 0x2E, 0xFD, 0xD4, 0x49, 0x34, 0x1C, 0xC2, 0x00, 0x7E, 0x9D, 0x60, 0x00, 0x79, 0x3B,
0x17, 0x00, 0x2A, 0xF6, 0x3F, 0x8A, 0x99, 0x1E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x00,
0xB0, 0x14, 0x9C, 0x70, 0x03, 0x50, 0xC4, 0x2B, 0x21, 0xFC, 0xF9, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0xD4, 0x49, 0x07, 0x9B, 0x6A, 0x00, 0x77, 0x0C, 0x90, 0x00, 0xE5, 0x6F, 0x9E, 0x00, 0xF8, 0xFD,
0x3F, 0x8A, 0x8C, 0x9F, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1E, 0x7B, 0xB0, 0x04, 0x9F, 0xDA,
0x01, 0x5F, 0x6C, 0x55, 0x80, 0x08, 0xD4, 0x0C, 0xA1, 0x00, 0x5E, 0xFD, 0x00, 0x7B, 0xCB, 0xAE, 0x6A, 0x00, 0x9B, 0x04, 0x0E, 0x00, 0x96, 0x65, 0x3A, 0x00, 0x5F, 0x07, 0x80, 0x8A, 0xAA, 0xFA,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x20, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1F, 0x7B, 0xB0, 0x44, 0x7E, 0x41, 0x01, 0x92, 0xEF, 0x2A,
0x99, 0x09, 0x6C, 0x0D, 0xA1, 0x00, 0x40, 0xFD, 0x00, 0x7B, 0x3C, 0xB6, 0x3E, 0x00, 0x0C, 0xA2, 0x9E, 0x00, 0x27, 0x24, 0xDF, 0x00, 0xE0, 0xFF, 0xBF, 0x8A, 0xEB, 0xFB, 0xB5, 0x62, 0x13, 0x80,
0x24, 0x00, 0x02, 0x00, 0x01, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x23, 0x00, 0xB0, 0x44, 0x55, 0xF1, 0x01, 0x0A, 0x01, 0xB6, 0x8F, 0x10, 0x40, 0x8D,
0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x92, 0x02, 0xB5, 0x62, 0x13, 0x80, 0x24, 0x00, 0x02, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x30, 0x00,
0xB0, 0x44, 0x66, 0xC5, 0x03, 0x31, 0x1B, 0xBF, 0xC2, 0x02, 0x40, 0x8D, 0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x02, 0x61, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x01, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x9F, 0xBD, 0xD2, 0x04, 0x7B, 0x94, 0x00, 0x0C, 0xC5, 0x40, 0x6B, 0x08, 0x38, 0xC3, 0x24, 0xFD, 0xC5, 0xC3, 0xA5, 0x57, 0xE1, 0x21,
0x3E, 0x01, 0x58, 0x1D, 0x78, 0x3A, 0x38, 0x13, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x02, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA0, 0xBD,
0xB2, 0x04, 0x91, 0x39, 0x00, 0x56, 0xDD, 0x3F, 0x2B, 0x17, 0x59, 0xC0, 0x82, 0xEF, 0x6C, 0x9A, 0xA8, 0x57, 0x7C, 0x9D, 0x72, 0x07, 0xBA, 0x27, 0x78, 0x3A, 0xB1, 0x11, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x03, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA1, 0xBD, 0xD2, 0x04, 0xBE, 0x31, 0x00, 0xB5, 0xD6, 0x3F, 0x6B, 0x19, 0x87, 0xDB,
0x80, 0xFE, 0x42, 0x0C, 0xAB, 0x57, 0xDE, 0xA0, 0x21, 0x07, 0xF9, 0x23, 0x74, 0x3A, 0x7E, 0x46, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x04, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA2, 0xBD, 0xB2, 0x04, 0x57, 0x31, 0x00, 0x4B, 0xBE, 0x3F, 0xAB, 0x21, 0x5E, 0x0B, 0x3F, 0xFC, 0x75, 0x74, 0xAD, 0x57, 0x5F, 0xB2, 0x07, 0x03, 0x1B, 0x2B,
0x70, 0x3A, 0xBB, 0x0F, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x05, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA3, 0xBD, 0xD2, 0x04, 0x33, 0x11,
0x00, 0x49, 0xAC, 0x3F, 0x6B, 0x28, 0xE3, 0x3A, 0x7D, 0xFD, 0x5F, 0xDB, 0xAF, 0x57, 0x9D, 0x88, 0x4D, 0x02, 0x72, 0x2B, 0x6C, 0x3A, 0x3E, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x06, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA4, 0xBD, 0xD2, 0x04, 0xEC, 0x1E, 0x00, 0xD0, 0xF5, 0x3F, 0x2B, 0x37, 0x2E, 0xF3, 0xBA, 0x80, 0x9A, 0xA6,
0xB2, 0x57, 0xF7, 0x5D, 0x55, 0x03, 0xF4, 0x1C, 0x68, 0x3A, 0x19, 0x49, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x07, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xA5, 0xBD, 0xD2, 0x84, 0xCD, 0x4A, 0x02, 0x75, 0xE1, 0x3F, 0x6B, 0x39, 0x75, 0x51, 0x48, 0x81, 0x45, 0x3F, 0xA1, 0x57, 0x5D, 0xA0, 0x16, 0x06, 0x27, 0x24, 0x84, 0x3A, 0xA8, 0x47,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x08, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA6, 0xBD, 0xD2, 0x04, 0x3F, 0xAB, 0x00, 0xC5, 0xCE, 0x3F,
0xAB, 0x41, 0x2F, 0x8F, 0x06, 0x82, 0x68, 0x8F, 0xA3, 0x57, 0xB1, 0xB2, 0x4E, 0x07, 0x51, 0x24, 0x90, 0x3A, 0x81, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x09, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA7, 0xBD, 0xD2, 0x04, 0xEF, 0x93, 0x00, 0x15, 0x7A, 0x40, 0xAB, 0x4F, 0xD9, 0xD5, 0x4F, 0xFF, 0xD6, 0x42, 0xA5, 0x57, 0xAC, 0x90,
0x39, 0x06, 0x3F, 0x11, 0x94, 0x3B, 0xA2, 0xFC, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0A, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA8, 0xBD,
0xD2, 0x84, 0x00, 0xC3, 0x00, 0xBA, 0x16, 0x40, 0x6B, 0x56, 0xF5, 0x1B, 0x8E, 0x82, 0xD8, 0x8B, 0xA7, 0x57, 0x1B, 0x06, 0xE9, 0x06, 0x2D, 0x21, 0x94, 0x3B, 0x71, 0x55, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x0B, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA9, 0xBD, 0xD2, 0x04, 0xD3, 0x18, 0x00, 0x90, 0x2C, 0x40, 0x2B, 0x58, 0xCF, 0x2D,
0x8C, 0x7E, 0xEF, 0x12, 0xAA, 0x57, 0xD2, 0xB1, 0xAD, 0x01, 0x45, 0x27, 0x94, 0x3B, 0x8F, 0x20, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0C, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAA, 0xBD, 0xD2, 0x04, 0x7F, 0x3D, 0x00, 0x5E, 0x7A, 0x40, 0xEB, 0x67, 0x2C, 0x45, 0xCA, 0xF6, 0x48, 0xA8, 0xAC, 0x57, 0xF8, 0xD5, 0x66, 0x04, 0x36, 0x22,
0x94, 0x3B, 0x5B, 0x01, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0D, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAB, 0xBD, 0xD2, 0x84, 0xC1, 0x1E,
0x00, 0xC6, 0xFF, 0x3F, 0xAB, 0x6F, 0xFE, 0x69, 0x28, 0x82, 0xE4, 0x06, 0xAF, 0x57, 0x3D, 0x34, 0x38, 0x02, 0xFB, 0x20, 0x94, 0x3B, 0xC8, 0xB3, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x0E, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAC, 0xBD, 0xB2, 0x04, 0x41, 0xAE, 0x00, 0xFC, 0x51, 0x40, 0x6B, 0x76, 0x2D, 0x7B, 0xA6, 0xFD, 0x9C, 0x9F,
0xB1, 0x57, 0xDA, 0xAF, 0xDE, 0x01, 0xB5, 0x1B, 0x98, 0x3B, 0x8D, 0x75, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0F, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xAD, 0xBD, 0xD2, 0x04, 0x32, 0x99, 0x02, 0x17, 0x61, 0x40, 0x2B, 0x78, 0x76, 0xB4, 0xD3, 0xFC, 0x10, 0x45, 0xA0, 0x57, 0x67, 0xC7, 0xEF, 0x02, 0x93, 0x20, 0x90, 0x3B, 0xC3, 0x1E,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x10, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xBD, 0xD2, 0x04, 0x70, 0x64, 0x02, 0x10, 0xC5, 0x40,
0xEB, 0x87, 0x72, 0x87, 0xF1, 0x80, 0x8E, 0xF2, 0xA2, 0x57, 0x57, 0x0A, 0x76, 0x0C, 0xD9, 0x17, 0x88, 0x3B, 0x91, 0xAA, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x11, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAF, 0xBD, 0xD2, 0x04, 0x95, 0xB0, 0x00, 0x24, 0x2D, 0x40, 0x2B, 0x89, 0x3B, 0x4D, 0x5B, 0xF0, 0xAB, 0x5C, 0xA4, 0x57, 0x50, 0x95,
0x23, 0x04, 0xB1, 0x3A, 0x0C, 0x3A, 0x59, 0x64, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x12, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB0, 0xBD,
0xD2, 0x04, 0x61, 0xBD, 0x00, 0xC7, 0x14, 0x40, 0x6B, 0x97, 0x82, 0x8D, 0xD9, 0xFC, 0xB9, 0xB4, 0xA6, 0x57, 0x71, 0xE6, 0x0F, 0x05, 0x96, 0x40, 0x10, 0x3A, 0xD3, 0x7B, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x13, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB1, 0xBD, 0xD2, 0x04, 0x61, 0x35, 0x00, 0xC3, 0xC6, 0x3F, 0xEB, 0x98, 0x44, 0x01,
0x98, 0x85, 0xA8, 0xE9, 0xA8, 0x57, 0xC2, 0xA4, 0x0D, 0x01, 0xFD, 0x45, 0x10, 0x3A, 0x94, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x14, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB2, 0xBD, 0xD2, 0x04, 0xB1, 0x18, 0x00, 0x5D, 0x11, 0x40, 0xAB, 0xA0, 0xC8, 0xDF, 0x15, 0x82, 0xB1, 0xB9, 0xAB, 0x57, 0xF1, 0xE9, 0xC1, 0x03, 0x4A, 0x46,
0x10, 0x3A, 0xA7, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x15, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xBD, 0xD2, 0x04, 0x28, 0x00,
0x02, 0x5E, 0x5E, 0x40, 0x2B, 0xA9, 0x27, 0xA6, 0x73, 0x88, 0xE6, 0x73, 0xAE, 0x57, 0xCC, 0x8C, 0xAD, 0x02, 0x36, 0x3F, 0x14, 0x3A, 0xAF, 0x7C, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x16, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB4, 0xBD, 0xD2, 0x04, 0x85, 0xEC, 0x00, 0x91, 0xEE, 0x3F, 0x6B, 0xB7, 0x72, 0xF2, 0xD1, 0x84, 0x7D, 0xBE,
0xB0, 0x57, 0xEE, 0x05, 0x09, 0x08, 0x71, 0x43, 0x18, 0x3A, 0x1D, 0x65, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x17, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xB5, 0xBD, 0xD2, 0x04, 0xB1, 0x72, 0x02, 0x0E, 0xDA, 0x3E, 0xEB, 0xB8, 0xE4, 0xB4, 0xAF, 0x80, 0x21, 0xAF, 0xB3, 0x57, 0x7C, 0x50, 0x49, 0x00, 0x24, 0x43, 0x18, 0x3A, 0x26, 0xE7,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x18, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB6, 0xBD, 0xD2, 0x04, 0xE1, 0x9D, 0x00, 0xA2, 0x0C, 0x40,
0xAB, 0xC0, 0xEA, 0x39, 0xDD, 0xFD, 0x09, 0xEC, 0xA1, 0x57, 0x92, 0xAE, 0x92, 0x03, 0x96, 0x2B, 0x08, 0x3A, 0x64, 0xD1, 0xB5, 0x62, 0x13, 0x80, 0x78, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x07, 0x00, 0x8A, 0x08, 0x89, 0x08, 0x12, 0x07,
0x12, 0x00, 0xC1, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x32, 0x00, 0x00, 0x80, 0xB2, 0x00, 0x00, 0x80, 0xB3, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xEC, 0x47, 0x00, 0x00,
0x60, 0xC8, 0x00, 0x00, 0x80, 0xC7, 0x00, 0x00, 0x50, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x22, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x03, 0x00, 0x06, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x00, 0x06, 0x07, 0x11, 0x00, 0x06, 0x15, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xBD, 0x3A, 0xBD, 0x02, 0x92, 0xC7,
0x1E, 0x00, 0xBD, 0x3A, 0x00, 0x00, 0x83, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x04, 0x14, 0x0F, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x5E,
0xAD, 0x14, 0x0D, 0xD9, 0x01, 0x99, 0x8A, 0x08, 0x57, 0xFD, 0x00, 0x00, 0x00, 0xC4, 0xA0, 0xFF, 0xAF, 0x13, 0x31, 0x04, 0x00, 0xED, 0x07, 0xBB, 0xE2, 0xC1, 0xE2, 0xA6, 0xA2, 0x5F, 0x18, 0xC2,
0x8E, 0x08, 0x42, 0xC9, 0xD5, 0x17, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x07, 0x20, 0x00, 0x50, 0xF8, 0xAB, 0xA6, 0xD0, 0xC2, 0x7C, 0xE2, 0xDC, 0x80, 0x36, 0x92, 0x07, 0x9C, 0x36, 0xA1, 0x2E,
0x78, 0x0C, 0x91, 0xCE, 0x7E, 0xE6, 0x3E, 0x63, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x5E,
0xAD, 0x14, 0xBB, 0x54, 0x01, 0x85, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0xA9, 0xFF, 0xAF, 0x13, 0xEE, 0xD1, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDB, 0xA6, 0xE2, 0x4F, 0x93, 0xCC,
0x86, 0x08, 0x5E, 0xE0, 0xFB, 0x01, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xB2, 0xC2, 0xA1, 0xA2, 0x5A, 0xF1, 0x5A, 0x67, 0xD2, 0x32, 0xCB, 0x87, 0x73, 0xEA, 0xA6, 0x22, 0x7E, 0xCE,
0xB7, 0xF8, 0x59, 0xCB, 0x13, 0xCF, 0x90, 0x3D, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5E,
0xAD, 0x14, 0x1C, 0x84, 0x01, 0x3C, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x5B, 0x01, 0xA0, 0x13, 0xB1, 0x77, 0x00, 0xF4, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0x62, 0x0D, 0x9B, 0x10,
0x8D, 0x08, 0xE8, 0xB3, 0x12, 0x04, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xD3, 0xB5, 0xB7, 0x0A, 0x9E, 0x12, 0x42, 0xA2, 0x14, 0xB9, 0xAD, 0xE8, 0xD6, 0xBA, 0xA1, 0x04, 0xEB, 0x56,
0xE5, 0x29, 0xD2, 0xF1, 0x3E, 0xD4, 0x51, 0xD3, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x09, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E,
0xAD, 0x14, 0xAE, 0x75, 0x01, 0xEB, 0x8A, 0x08, 0x58, 0x7D, 0x00, 0x00, 0x40, 0x44, 0x27, 0x00, 0xA0, 0x13, 0x2A, 0x09, 0x80, 0x01, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x7D, 0x43, 0x25,
0x97, 0x08, 0x0E, 0x55, 0xE8, 0x19, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x34, 0x43, 0x60, 0xE2, 0x59, 0x42, 0xAE, 0xE1, 0xE5, 0x34, 0x86, 0x80, 0xA7, 0xDF, 0xA3, 0xE9, 0x4E, 0xB1,
0xF7, 0x28, 0xB4, 0xBC, 0x8B, 0xD9, 0x5E, 0x5F, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x5E,
0xAD, 0x14, 0x79, 0x8D, 0x01, 0x81, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x91, 0x01, 0xA0, 0x13, 0x16, 0xD5, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x62, 0x60, 0x15, 0x2D,
0x81, 0x08, 0x74, 0x9A, 0x0E, 0x09, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x43, 0x1D, 0xEA, 0x22, 0xB7, 0x2E, 0xD8, 0x3E, 0x59, 0x3A, 0x55, 0x75, 0x09, 0xE7, 0x0A, 0x39, 0xC6, 0x02,
0x6D, 0xFD, 0xE5, 0xF4, 0x5E, 0xEB, 0x85, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x5E,
0xAD, 0x14, 0xB3, 0xBB, 0x01, 0x4E, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x49, 0xFE, 0xAF, 0x13, 0x9A, 0xA4, 0x3F, 0xF5, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0xA2, 0x33, 0xC9, 0x6D,
0x90, 0x08, 0x5A, 0x9A, 0xE3, 0x00, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0D, 0xDD, 0x6D, 0xCD, 0xC2, 0x40, 0x3A, 0x97, 0x5C, 0x01, 0x02, 0x3D, 0x12, 0x48, 0x55, 0xDE, 0xBA, 0x35,
0x8E, 0xFB, 0xE1, 0xF2, 0x92, 0xCE, 0x5C, 0xFB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x5E,
0xAD, 0x14, 0x31, 0xC2, 0x01, 0x0F, 0x8A, 0x08, 0x58, 0x81, 0x00, 0x00, 0x40, 0x44, 0xF0, 0xFF, 0xAF, 0x13, 0x98, 0x87, 0x3F, 0xF7, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x50, 0xFF, 0x9B,
0x8B, 0x08, 0x16, 0xF0, 0x21, 0x1C, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x93, 0x50, 0xE6, 0x06, 0xCF, 0xB8, 0x8C, 0x20, 0xB6, 0x0C, 0x26, 0x4A, 0xC1, 0xC6, 0x7E, 0x22, 0xAC, 0xC6,
0x13, 0x14, 0x27, 0xFF, 0x18, 0xD2, 0xBA, 0xBA, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x5E,
0xAD, 0x14, 0x13, 0x8D, 0x01, 0xBC, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x8F, 0xFE, 0xAF, 0x13, 0x52, 0xDC, 0x00, 0xF5, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0xC2, 0x76, 0x7B, 0x55,
0x91, 0x08, 0x2A, 0xA2, 0xE2, 0x18, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0F, 0xB0, 0x0B, 0x57, 0x2E, 0x66, 0x57, 0xE9, 0x32, 0x5E, 0x4E, 0x14, 0x13, 0x5E, 0xFF, 0x22, 0xFA, 0x2A,
0x77, 0xDB, 0x2C, 0xC6, 0xC6, 0xDE, 0x74, 0x97, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x5E,
0xAD, 0x14, 0x8D, 0x68, 0x01, 0xBB, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0x44, 0x28, 0xFF, 0xAF, 0x13, 0x5F, 0x5B, 0x00, 0x04, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x22, 0x7D, 0x16, 0x76,
0x89, 0x08, 0xDE, 0x80, 0xDF, 0x08, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xE3, 0x37, 0xB1, 0x7F, 0xE8, 0xDA, 0x6C, 0x66, 0x21, 0x07, 0x1F, 0x55, 0x27, 0x27, 0x42, 0x1B, 0x68, 0x58,
0x2E, 0x2E, 0x19, 0xA5, 0xC5, 0xE3, 0xBB, 0x38
};

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,325 @@
/*
Use ESP32 WiFi to get AssistNow Offline data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 26th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Offline data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
The module still needs to be given time assistance to achieve a fast fix. This example
uses network time to do that. If you don't have a WiFi connection, you may have to use
a separate RTC to provide the time.
Note: AssistNow Offline is not supported by the ZED-F9P! "The ZED-F9P supports AssistNow Online only."
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://offline-live1.services.u-blox.com";
//const char assistNowServer[] = "https://offline-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOfflineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getFormat[] = "format=mga;"; // Data format. Leave set to mga for M8 onwards. Can be aid.
const char getPeriod[] = "period=1;"; // Optional. The number of weeks into the future that the data will be valid. Can be 1-5. Default = 4.
const char getMgaResolution[] = "resolution=1;"; // Optional. Data resolution: 1 = every day; 2 = every other day; 3 = every 3rd day.
//Note: always use resolution=1. findMGAANOForDate does not yet support finding the 'closest' date. It needs an exact match.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getFormat,
getPeriod,
getMgaResolution
);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Find where the AssistNow data for today starts and ends
size_t todayStart = 0; // Default to sending all the data
size_t tomorrowStart = (size_t)payloadSize;
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if (payloadSize > 0)
{
if(getLocalTime(&timeinfo))
{
// Find the start of today's data
todayStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
if (todayStart < (size_t)payloadSize)
{
Serial.print(F("Found the data for today starting at location "));
Serial.println(todayStart);
}
else
{
Serial.println("Could not find the data for today. This will not work well. The GNSS needs help to start up quickly.");
}
// Find the start of tomorrow's data
tomorrowStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, 1);
if (tomorrowStart < (size_t)payloadSize)
{
Serial.print(F("Found the data for tomorrow starting at location "));
Serial.println(tomorrowStart);
}
else
{
Serial.println("Could not find the data for tomorrow. (Today's data may be the last?)");
}
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
if(getLocalTime(&timeinfo)) // Get the local time again, just to make sure we are using the most accurate time
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data for today to the module - without the time
if (payloadSize > 0)
{
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push the AssistNow data for today. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
// Push the AssistNow data for today.
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
myGNSS.setI2CpollingWait(125);
#endif
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,236 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module
if (payloadSize > 0)
{
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
// Push all the AssistNow data.
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
// MGA-ACK messages are actually enabled.
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
myGNSS.setI2CpollingWait(125);
#endif
}
Serial.println(F("Here we go!"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,254 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
The AssistNow Online data is valid for 2-4 hours, so it can be re-used.
BUT you need to provide the time assistance separately.
This example shows how to do that.
The ESP32's RTC is set from network time.
The RTC time is pushed to the module using setUTCTimeAssistance,
followed by the AssistNow data (without time).
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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 <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module - WITHOUT THE TIME
if (payloadSize > 0)
{
// Push the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,299 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
This example shows how to provide initial position assistance. Uncomment #define USE_SERVER_ASSISTANCE
below to include the position in the AssistNow data request, instead of using setPositionAssistanceLLH.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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
*/
//#define USE_SERVER_ASSISTANCE // Uncomment this line to include the position in the AssistNow data request
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
#ifdef USE_SERVER_ASSISTANCE
const char useLatitude[] = "lat=55.0;"; // Use an approximate latitude of 55 degrees north. Replace this with your latitude.
const char useLongitude[] = "lon=-1.0;"; // Use an approximate longitude of 1 degree west. Replace this with your longitude.
const char useAlt[] = "alt=100;"; // Use an approximate latitude of 100m above WGS84. Replace this with your altitude.
const char usePosAcc[] = "pacc=100000;"; // Use a position accuracy of 100000m (100km)
#endif
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
#ifdef USE_SERVER_ASSISTANCE
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType,
useLatitude,
useLongitude,
useAlt,
usePosAcc);
#else
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
#endif
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// Provide time assistance. Use the UBX_MGA_ACK_DATA0 acknowledgements. Set tAccS to 2 seconds.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, 0, 2, 0, 0, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// If desired - push initial position assistance to the module
#ifndef USE_SERVER_ASSISTANCE
// Use 55 degrees (*10^7) north, 1 degree (*10^7) west, 100m (10000cm) altitude, 100km (10000000cm) accuracy. Replace these with your position.
// The units for lat and lon are degrees * 1e-7 (WGS84)
// The units for alt (WGS84) and posAcc (stddev) are cm.
myGNSS.setPositionAssistanceLLH(550000000, -10000000, 10000, 10000000, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
// We could use setPositionAssistanceXYZ instead if needed.
#endif
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module - WITHOUT THE TIME
if (payloadSize > 0)
{
// Push the AssistNow data. Use the UBX_MGA_ACK_DATA0 acknowledgements.
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Avoid pounding the I2C bus by setting setI2CpollingWait to 125ms
myGNSS.setI2CpollingWait(125);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,232 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi
and push it to a u-blox module using Serial.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#define mySerial Serial1 // Use Serial1 to communicate with the GNSS module
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
mySerial.begin(9600); // Use 9600 baud (for u-blox M8)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to the GNSS.
if (myGNSS.begin(mySerial) == false) //Connect to the Ublox module using mySerial
{
Serial.println(F("u-blox GPS not detected. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module
if (payloadSize > 0)
{
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Push all the AssistNow data.
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
// MGA-ACK messages are actually enabled.
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
#endif
}
Serial.println(F("Here we go!"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}

View file

@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

View file

@ -0,0 +1,186 @@
/*
Use ESP32 WiFi to get AssistNow Online (MGA) data from PointPerfect (broker) as a Client using MQTT
By: Paul Clark / SparkFun
Date: March 9th, 2022
Based on original code by: u-blox AG / Michael Ammann
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain AssistNow Online (MGA) data from a PointPerfect Broker over WiFi
and push it over I2C to a ZED-F9x.
It's confusing, but the Arduino is acting as a 'client' to the PointPerfect service.
You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan.
To sign up, go to: https://portal.thingstream.io/app/location-services/things
This is a proof of concept to show how to connect via MQTT to get AssistNow MGA data.
For more information about MQTT, SPARTN and PointPerfect Correction Services
please see: https://www.u-blox.com/en/product/pointperfect
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
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 <WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoMqttClient.h> // Click here to get the library: http://librarymanager/All#ArduinoMqttClient
#include "secrets.h"
#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;
//Global variables
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReceived_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(F("PointPerfect AssistNow testing"));
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN);
myGNSS.setNavigationFrequency(1); //Set output in Hz.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.print(F("WiFi connected with IP: "));
Serial.println(WiFi.localIP());
while (Serial.available()) Serial.read();
}
void loop()
{
if (Serial.available())
{
beginClient();
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
}
Serial.println(F("Press any key to start MQTT Client."));
delay(1000);
}
WiFiClientSecure wifiClient = WiFiClientSecure();
MqttClient mqttClient(wifiClient);
void mqttMessageHandler(int messageSize)
{
const uint16_t mqttLimit = 512;
uint8_t *mqttData = new uint8_t[mqttLimit]; // Allocate memory to hold the MQTT data
if (mqttData == NULL)
{
Serial.println(F("Memory allocation for mqttData failed!"));
return;
}
Serial.print(F("Pushing data from "));
Serial.print(mqttClient.messageTopic());
Serial.println(F(" topic to ZED"));
while (mqttClient.available())
{
uint16_t mqttCount = 0;
while (mqttClient.available())
{
char ch = mqttClient.read();
//Serial.write(ch); //Pipe to serial port is fine but beware, it's a lot of binary data
mqttData[mqttCount++] = ch;
if (mqttCount == mqttLimit)
break;
}
if (mqttCount > 0)
{
//Push KEYS or SPARTN data to GNSS module over I2C
myGNSS.pushRawData(mqttData, mqttCount, false);
lastReceived_ms = millis();
}
}
delete[] mqttData;
}
//Connect to MQTT broker, receive MGA, and push to ZED module over I2C
void beginClient()
{
Serial.println(F("Subscribing to Broker. Press key to stop"));
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush
while (Serial.available() == 0)
{
//Connect if we are not already
if (wifiClient.connected() == false)
{
// Connect to AWS IoT
wifiClient.setCACert(AWS_CERT_CA);
wifiClient.setCertificate(AWS_CERT_CRT);
wifiClient.setPrivateKey(AWS_CERT_PRIVATE);
mqttClient.setId(MQTT_CLIENT_ID);
mqttClient.setKeepAliveInterval(60*1000);
mqttClient.setConnectionTimeout( 5*1000);
if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) {
Serial.print(F("MQTT connection failed! Error code = "));
Serial.println(mqttClient.connectError());
return;
} else {
Serial.println(F("You're connected to the PointPerfect MQTT broker: "));
Serial.println(AWS_IOT_ENDPOINT);
// Subscribe to MQTT and register a callback
Serial.println(F("Subscribe to Topics"));
mqttClient.onMessage(mqttMessageHandler);
mqttClient.subscribe(MQTT_TOPIC_ASSISTNOW);
lastReceived_ms = millis();
} //End attempt to connect
} //End connected == false
else {
mqttClient.poll();
}
//Close socket if we don't have new data for 10s
if (millis() - lastReceived_ms > maxTimeBeforeHangup_ms)
{
Serial.println(F("Timeout. Disconnecting..."));
if (mqttClient.connected() == true)
mqttClient.stop();
return;
}
delay(10);
}
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
wifiClient.stop();
}

View file

@ -0,0 +1,39 @@
//Your WiFi credentials
const char ssid[] = "<YOUR SSID>";
const char password[] = "<YOUR PASSWORD>";
// Below infomation you can set after signing up with u-blox Thingstream portal
// and after add a new New PointPerfect Thing
// https://portal.thingstream.io/app/location-services/things
// in the new PointPerfect Thing you go to the credentials page and copy past the values and certificate into this.
// <Your PointPerfect Thing> -> Credentials -> Hostname
const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com";
const unsigned short AWS_IOT_PORT = 8883;
// <Your PointPerfect Thing> -> Credentials -> AssistNow (MGA) topic
const char MQTT_TOPIC_ASSISTNOW[] = "/pp/ubx/mga";
// <Your PointPerfect Thing> -> Credentials -> Client Id
static const char MQTT_CLIENT_ID[] = "<ADD YOUR CLIENT ID HERE>";
// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)EOF";
// <Your PointPerfect Thing> -> Credentials -> Client Certificate
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)KEY";
// Get this from Thingstream Portal
// <Your PointPerfect Thing> -> Credentials -> Client Key
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
<ADD YOUR KEY HERE>
-----END RSA PRIVATE KEY-----
)KEY";

View file

@ -0,0 +1,222 @@
# SparkFun u-blox Arduino GNSS Library - AssistNow<sup>TM</sup>
v2.1.0 of the library adds support for u-blox [AssistNow<sup>TM</sup> Assisted GNSS (A-GNSS)](https://www.u-blox.com/en/product/assistnow) which can dramatically reduce the time-to-first-fix.
To use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server. See [below](#AssistNow-Service-Token) for details.
## AssistNow<sup>TM</sup> Online
With AssistNow Online, an Internet connected host downloads assistance data from the u-blox AssistNow Online service to the receiver at system start-up. AssistNow Online data is valid for 2 - 4 hours; beyond that fresh data must be downloaded.
Please see the [AssistNow_Online](./AssistNow_Online) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
The new functions we've added to the library to support AssistNow Online are described [Support for AssistNow below](#Support-for-AssistNow).
## AssistNow<sup>TM</sup> Offline
With the AssistNow Offline service, users can download long-term orbit data over the Internet at their convenience. The orbit data can be stored in the memory of the application processor. The function requires no connectivity at system start-up, enabling a position fix within seconds, even when no network is available. AssistNow Offline offers augmentation for up to 35 days.
Please see the [AssistNow_Offline](./AssistNow_Offline) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
**Note: AssistNow Offline is not supported by the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
The new functions we've added to the library to support AssistNow Offline are described [Support for AssistNow](#Support-for-AssistNow) and [Additional Support for AssistNow Offline](#Additional-Support-for-AssistNow-Offline).
## AssistNow<sup>TM</sup> Autonomous
AssistNow Autonomous provides aiding information without the need for a host or external network connection. Based on previous broadcast satellite ephemeris data downloaded to and stored by the GNSS receiver, AssistNow Autonomous automatically generates accurate predictions of satellite orbital data (“AssistNow Autonomous data”) that is usable for future GNSS position fixes.
The benefits of AssistNow Autonomous are:
* Faster fix in situations where GNSS satellite signals are weak
* No connectivity required
* Compatible with AssistNow Online (can work stand-alone, or in tandem with AssistNow Online service)
* No integration effort; calculations are done in the background, transparent to the user
AssistNow Autonomous offers augmentation for up to 6 days.
Please see the [AssistNow_Autonomous](./AssistNow_Autonomous) examples for more details.
**Note: AssistNow Autonomous does not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
The new functions we've added to the library to support AssistNow Autonomous are described [Support for AssistNow Autonomous below](#Support-for-AssistNow-Autonomous).
## AssistNow Service Token
To be able to use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server.
The following u-blox resources contain useful information:
* [AssistNow - u-blox A-GNSS services](https://www.u-blox.com/en/product/assistnow)
* [AssistNow Product Summary](https://www.u-blox.com/sites/default/files/products/documents/AssistNow_ProductSummary_UBX-13003352.pdf)
* [AssistNow User Guide](https://www.u-blox.com/sites/default/files/products/documents/MultiGNSS-Assistance_UserGuide_%28UBX-13004360%29.pdf)
* [Thingstream Pricing](https://portal.thingstream.io/pricing)
You can apply for a _free_ AssistNow Service Evaluation Token by completing the request form:
* [AssistNow Service evaluation token request form](https://www.u-blox.com/en/assistnow-service-evaluation-token-request-form)
The _free_ AssistNow Developer token entitles you to:
* AssistNow Online Developer: 100K free location requests per month. Capped.
* AssistNow Offline Developer: 20K free location requests per month. Capped.
* CellLocate Developer: 5K free location requests per month. Capped.
The free token will expire after 90 days, but you can continue to use it beyond that by registering it on [Thingstream](https://portal.thingstream.io/).
## Initial Position Assistance
You can further decrease the time-to-first-fix by providing the receiver's approximate position - if known. There are two ways to do this:
* The position can be specified when requesting AssistNow Online data from the server:
* include the key name ```lat``` with the approximate user latitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -90 to 90. Example: ```lat=47.2;```
* include the key name ```lon``` with the approximate user longitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -180 to 180. Example: ```lon=8.55;```
* include the key name ```alt``` with the approximate user altitude above WGS 84 Ellipsoid in meters. If this value is not provided, the server assumes an altitude of 0 meters. Must be in range -1000 to 50000
* include the key name ```pacc``` with the approximate accuracy of submitted position in meters. If this value is not provided, the server assumes an accuracy of 300 km. Must be in range 0 to 6000000
* the position assistance data will then be automatically included in the AssistNow Online data
* Provide initial position assistance data by calling one of:
* <b>bool setPositionAssistanceXYZ(int32_t ecefX, int32_t ecefY, int32_t ecefZ, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* The units for ```ecefX/Y/Z``` and ```posAcc``` (stddev) are cm
* <b>bool setPositionAssistanceLLH(int32_t lat, int32_t lon, int32_t alt, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* The units for ```lat``` and ```lon``` are degrees * 1e-7 (WGS84). The units for ```alt``` (WGS84) and ```posAcc``` (stddev) are cm (not m)
## Support for AssistNow
```pushAssistNowData``` allows AssistNow Online, Offline or Autonomous data to be pushed to the module. As the ESP32 HTTP GET function returns a ```String```, we've included overloaded functions which allow you to pass the data as a ```String``` or as ```const uint8_t *```.
The String-based function declarations are:
* <b>size_t pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
The const uint8_t * function declarations are:
* <b>size_t pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
```dataBytes``` is a pointer to the AssistNow data.
<br>
```numDataBytes``` is the length of the AssistNow data.
<br>
```pushAssistNowData``` pushes individual packets of data to the u-blox module. Sending all of the data contiguously would overload the module, so ```pushAssistNowData``` can either:
* insert a small delay between each packet (the default is 7ms)
* or use the ```UBX-MGA-ACK-DATA0``` acknowledgement message to acknowledge each packet
```mgaAck``` controls which method is used.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_NO``` (**default**), a delay of ```maxWait``` milliseconds is inserted between each packet. ```maxWait``` defaults to 7ms.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_YES```, acknowledgement messages will be expected with a _timeout_ of ```maxWait``` milliseconds. The default timeout is again 7ms, but you can change this if required by passing a different value.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE```, the code will poll the module to enquire if the acknowledgement messages are enabled. If they are, they will be used. If not, a delay is used.
```setAckAiding``` enables or disables the acknowledgement messages. By default they are disabled. ```setAckAiding(1)``` will enable them. ```setAckAiding(0)``` will disable them again.
* <b>bool setAckAiding(uint8_t ackAiding, uint16_t maxWait);</b>
```getAckAiding``` returns 1 if the acknowledgement messages are enabled, 0 if they are disabled. 255 indicates an error or timeout.
* <b>uint8_t getAckAiding(uint16_t maxWait);</b>
```pushAssistNowData``` returns the number of _bytes_ pushed (not the number of _packets_). The return value should be equal to ```numDataBytes``` if all data was valid and pushed successfully.
AssistNow Online data is valid for 2-4 hours. 'Stale' data can be re-used but:
* ```pushAssistNowData``` needs to be told to skip the time information contained in the AssistNow data
* the user needs to provide the module with UTC time separately
The ```skipTime``` parameter tells ```pushAssistNowData``` to skip any time information in the data. ```skipTime``` is bool. Set it to ```true``` to skip the time information.
<br>
UTC time can be pushed to the module first by calling ```setUTCTimeAssistance```:
* <b>bool setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t nanos, uint16_t tAccS, uint32_t tAccNs, uint8_t source, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
Only the ```year```, ```month```, ```day```, ```hour```, ```minute``` and ```second``` parameters are mandatory. The others default to sensible values. Again ```mgaAck``` and ```maxWait``` control if a delay is used when configuring the time, or if an acknowledgement message will be expected.
<br>
```nanos``` (nanoseconds), ```tAccS``` (time accuracy estimate (seconds)), ```tAccNs``` (time accuracy estimate (nanoseconds)) and ```source``` (if a clock signal will be provided on EXT_INT) are optional, but are available for advanced users.
<br>
```year``` numbering starts at 0; 2021 is 2021, not 121 (years since 1900). ```month``` and ```day``` numbering starts at 1, not 0.
<br>
Call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
## Additional Support for AssistNow Offline
AssistNow Offline data downloaded from the u-blox server can contain 1-5 weeks of data. However, only the data for _today_ should be pushed the module. Sending data for past or future days will confuse the module.
```findMGAANOForDate``` can be used to find the location of the start of the UBX-MGA-ANO data for the specified date within the offline data. That location can then be passed to ```pushAssistNowData``` using the ```offset``` parameter.
* <b>size_t findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture);</b>
The sequence of events is:
* call ```findMGAANOForDate``` passing the ```year```, ```month``` and ```day``` for today. ```findMGAANOForDate``` will return the location / offset of the data for today within the offline data.
* call ```findMGAANOForDate``` again passing the ```year```, ```month``` and ```day``` for _today_ but also set ```daysIntoFuture``` to 1. ```findMGAANOForDate``` will then return the location / offset of the data for _tomorrow_ (one day into the future).
* call ```pushAssistNowData``` setting:
* ```offset``` to the location (offset) of today's data within the offline data
* ```skipTime``` to ```true```
* ```numDataBytes``` to ((tomorrow's location) - (today's location)). Only the offline data for today will be pushed.
```findMGAANOForDate``` will return a value of numDataBytes if the data for the chosen day cannot be found.
<br>
Again, call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
## Support for AssistNow Autonomous
AssistNow Autonomous is disabled by default. You can enable it by calling ```setAopCfg``` and check if it is enabled by calling ```getAopCfg```:
* <b>uint8_t getAopCfg(uint16_t maxWait);</b>
* <b>bool SFE_UBLOX_GNSS::setAopCfg(uint8_t aopCfg, uint16_t aopOrbMaxErr, uint16_t maxWait)</b>
```getAopCfg``` will return 1 if AssistNow Autonomous is enabled, 0 if disabled. 255 indicates an error or timeout.
```setAopCfg``` has two parameters:
* set ```aopCfg``` to 1 to enable AssistNow Autonomous, or 0 to disable it
* ```aopOrbMaxErr``` is used to set the 'lifetime' of the AssistNow data. It is recommended to set aopOrbMaxErr to 0 (the default value). This instructs the module to use the firmware default value that corresponds to a default orbit data validity of approximately three days (for GPS satellites observed once) and up to six days (for GPS and GLONASS satellites observed multiple times over a period of at least half a day).
Once AssistNow Autonomous is enabled, you can monitor its status via the ```status``` field in the UBX-NAV-AOPSTATUS message. You can read the ```status``` by calling the helper function ```getAOPSTATUSstatus```. It will return zero when the AssistNow Autonomous data collection is idle. Non-zero values indicate that data collection is in progress. Only power-off the receiver when the subsystem is idle (that is, when the status shows a steady zero).
* <b>uint8_t getAOPSTATUSstatus(uint16_t maxWait);</b>
* <b>uint8_t getAOPSTATUSuseAOP(uint16_t maxWait);</b>
We have included full 'auto' support for UBX-NAV-AOPSTATUS, so you can have the message delivered periodically, add a callback for it, and/or log it to the file buffer:
* <b>bool getAOPSTATUS(uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUS(bool enabled, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUSrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUScallback(void (*callbackPointer)(UBX_NAV_AOPSTATUS_data_t), uint16_t maxWait);</b>
* <b>bool assumeAutoAOPSTATUS(bool enabled, bool implicitUpdate);</b>
* <b>void flushAOPSTATUS();</b>
* <b>void logAOPSTATUS(bool enabled);</b>
You can also monitor the AssistNow Autonomous satellite information via the UBX-NAV-SAT message. Again, we have included full 'auto' support for UBX-NAV-SAT. UBX-NAV-SAT contains useful information for each individual satellite which the module has acquired: carrier to noise ratio (signal strength); elevation; azimuth; pseudorange residual; quality indication, health; ephemeris available; almanac available; **AssistNow Offline data availability**; and more. The data can be analyzed using a callback. Please see the AssistNowAutonomous examples for more details.
* <b>bool getNAVSAT(uint16_t maxWait);</b>
* <b>bool setAutoNAVSAT(bool enabled, uint16_t maxWait);</b>
* <b>bool setAutoNAVSAT(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoNAVSATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait);</b>
* <b>bool setAutoNAVSATcallback(void (*callbackPointer)(UBX_NAV_NAVSAT_data_t), uint16_t maxWait);</b>
* <b>bool assumeAutoNAVSAT(bool enabled, bool implicitUpdate);</b>
* <b>void flushNAVSAT();</b>
* <b>void logNAVSAT(bool enabled);</b>
The AssistNow Autonomous data is stored in the module's RAM memory. If that RAM is Battery-Backed - all SparkFun GNSS boards include battery back-up - then the data will be available after the module is powered down and powered back up again. However, you can also read (poll) the navigation database and store the contents in processor memory. ```readNavigationDatabase``` allows you to do that:
* <b>size_t readNavigationDatabase(uint8_t *dataBytes, size_t maxNumDataBytes, uint16_t maxWait);</b>
Data is written to ```dataBytes```. Set ```maxNumDataBytes``` to the (maximum) size of dataBytes. If the database exceeds maxNumDataBytes, the excess bytes will be lost.
```readNavigationDatabase``` returns the number of database bytes written to ```dataBytes```. The return value will be equal to ```maxNumDataBytes``` if excess data was received.
```readNavigationDatabase``` will timeout after ```maxWait``` milliseconds - in case the final UBX-MGA-ACK was missed.
You can then write the database back into the module using ```pushAssistNowData```. Don't forget to call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
Note: UBX-MGA-DBD messages are only intended to be sent back to the same receiver that generated them. They are firmware-specific.

View file

@ -0,0 +1,125 @@
/*
Get the GPGGA NMEA sentence using getLatestNMEAGPGGA
By: Paul Clark
SparkFun Electronics
Date: January 12th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
This example shows how to turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to use the new getLatestNMEAGPGGA function to retrieve the latest GPGGA message.
getLatestNMEAGPGGA returns immediately - it is not blocking.
It returns:
0 if no data is available
1 if the data is valid but is stale (you have read it before)
2 if the data is valid and fresh
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
The library includes a getLatestNMEAGNGGA function too.
This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA.
This example turns off all sentences except for GGA.
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 GNSS and a RedBoard
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 <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;
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
// 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.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
}
void loop()
{
// getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here
NMEA_GGA_data_t data; // Storage for the GPGGA data
uint8_t result = myGNSS.getLatestNMEAGPGGA(&data); // Get the latest GPGGA data (if any)
if (result == 0)
{
Serial.println(F("No GPGGA data available"));
}
else if (result == 1)
{
Serial.println(F("GPGGA data is available but is stale"));
}
else // if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPGGA: Length: "));
Serial.print(data.length);
Serial.print(F("\tData: "));
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNGGA(&data); // Get the latest GNGGA data (if any)
if (result == 0)
{
Serial.println(F("No GNGGA data available"));
}
else if (result == 1)
{
Serial.println(F("GNGGA data is available but is stale"));
}
else // if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNGGA: Length: "));
Serial.print(data.length);
Serial.print(F("\tData: "));
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
}
delay(250);
}

View file

@ -0,0 +1,119 @@
/*
Get the latest GPGGA / GNGGA NMEA sentence using callbacks
By: Paul Clark
SparkFun Electronics
Date: January 12th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
This example shows how to turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to get the latest GPGGA or GNGGA message autonomously using callbacks.
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
This example shows how to change the Talker ID so the GNGGA messages become GPGGA.
It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages.
This example turns off all sentences except for GGA.
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 GNSS and a RedBoard
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 <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;
// Callback: printGPGGA will be called when new GPGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGPGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNGGA will be called if new GNGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGNGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
// 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.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
// Set up the callback for GPGGA
myGNSS.setNMEAGPGGAcallbackPtr(&printGPGGA);
// Set up the callback for GNGGA
myGNSS.setNMEAGNGGAcallbackPtr(&printGNGGA);
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,183 @@
/*
Get the NMEA sentence using getLatestNMEAGPxxx (GGA, VTG, RMC, ZDA)
By: Paul Clark
SparkFun Electronics
Date: March 2nd, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
This example shows how to turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to use the new getLatestNMEAGPxxx function to retrieve the latest GPGGA message.
getLatestNMEAGPxxx returns immediately - it is not blocking.
It returns:
0 if no data is available
1 if the data is valid but is stale (you have read it before)
2 if the data is valid and fresh
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
The library includes getLatestNMEAGNxxx functions too.
This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA etc..
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 GNSS and a RedBoard
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 <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;
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_I2C);
// 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.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
}
void loop()
{
// getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here
NMEA_GGA_data_t dataGGA; // Storage for the GPGGA data
uint8_t result = myGNSS.getLatestNMEAGPGGA(&dataGGA); // Get the latest GPGGA data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPGGA: Length: "));
Serial.print(dataGGA.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataGGA.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNGGA(&dataGGA); // Get the latest GNGGA data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNGGA: Length: "));
Serial.print(dataGGA.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataGGA.nmea); // .nmea is printable (NULL-terminated)
}
// getLatestNMEAGPVTG calls checkUblox for us. We don't need to do it here
NMEA_VTG_data_t dataVTG; // Storage for the GPVTG data
result = myGNSS.getLatestNMEAGPVTG(&dataVTG); // Get the latest GPVTG data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPVTG: Length: "));
Serial.print(dataVTG.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataVTG.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNVTG(&dataVTG); // Get the latest GNVTG data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNVTG: Length: "));
Serial.print(dataVTG.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataVTG.nmea); // .nmea is printable (NULL-terminated)
}
// getLatestNMEAGPRMC calls checkUblox for us. We don't need to do it here
NMEA_RMC_data_t dataRMC; // Storage for the GPRMC data
result = myGNSS.getLatestNMEAGPRMC(&dataRMC); // Get the latest GPRMC data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPRMC: Length: "));
Serial.print(dataRMC.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataRMC.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNRMC(&dataRMC); // Get the latest GNRMC data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNRMC: Length: "));
Serial.print(dataRMC.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataRMC.nmea); // .nmea is printable (NULL-terminated)
}
// getLatestNMEAGPZDA calls checkUblox for us. We don't need to do it here
NMEA_ZDA_data_t dataZDA; // Storage for the GPZDA data
result = myGNSS.getLatestNMEAGPZDA(&dataZDA); // Get the latest GPZDA data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPZDA: Length: "));
Serial.print(dataZDA.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataZDA.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNZDA(&dataZDA); // Get the latest GNZDA data (if any)
if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNZDA: Length: "));
Serial.print(dataZDA.length);
Serial.print(F("\tData: "));
Serial.print((const char *)dataZDA.nmea); // .nmea is printable (NULL-terminated)
}
delay(250);
}

View file

@ -0,0 +1,226 @@
/*
Get the latest GGA, VTG, RMC, ZDA NMEA sentence using callbacks
By: Paul Clark
SparkFun Electronics
Date: March 2nd, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
** Please note: this example will not run on Arduino Uno. See https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/README.md#memory-usage
This example shows how to turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to get the latest GGA, VTG, RMC or ZDA message autonomously using callbacks.
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
This example shows how to change the Talker ID so the GNGGA messages become GPGGA.
It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages.
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 GNSS and a RedBoard
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 <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;
// Callback: printGPGGA will be called when new GPGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGPGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNGGA will be called if new GNGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGNGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGPVTG will be called when new GPVTG NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_VTG_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPVTGcallback
// / _____ This _must_ be NMEA_VTG_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPVTG(NMEA_VTG_data_t *nmeaData)
{
Serial.print(F("\r\nGPVTG: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNVTG will be called if new GNVTG NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_VTG_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNVTGcallback
// / _____ This _must_ be NMEA_VTG_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNVTG(NMEA_VTG_data_t *nmeaData)
{
Serial.print(F("\r\nGNVTG: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGPRMC will be called when new GPRMC NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_RMC_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPRMCcallback
// / _____ This _must_ be NMEA_RMC_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPRMC(NMEA_RMC_data_t *nmeaData)
{
Serial.print(F("\r\nGPRMC: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNRMC will be called if new GNRMC NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_RMC_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNRMCcallback
// / _____ This _must_ be NMEA_RMC_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNRMC(NMEA_RMC_data_t *nmeaData)
{
Serial.print(F("\r\nGNRMC: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGPZDA will be called when new GPZDA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_ZDA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPZDAcallback
// / _____ This _must_ be NMEA_ZDA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPZDA(NMEA_ZDA_data_t *nmeaData)
{
Serial.print(F("\r\nGPZDA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNZDA will be called if new GNZDA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_ZDA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNZDAcallback
// / _____ This _must_ be NMEA_ZDA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNZDA(NMEA_ZDA_data_t *nmeaData)
{
Serial.print(F("\r\nGNZDA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_I2C);
// 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.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
// Set up the callback for GPGGA
myGNSS.setNMEAGPGGAcallbackPtr(&printGPGGA);
// Set up the callback for GNGGA
myGNSS.setNMEAGNGGAcallbackPtr(&printGNGGA);
// Set up the callback for GPVTG
myGNSS.setNMEAGPVTGcallbackPtr(&printGPVTG);
// Set up the callback for GNVTG
myGNSS.setNMEAGNVTGcallbackPtr(&printGNVTG);
// Set up the callback for GPRMC
myGNSS.setNMEAGPRMCcallbackPtr(&printGPRMC);
// Set up the callback for GNRMC
myGNSS.setNMEAGNRMCcallbackPtr(&printGNRMC);
// Set up the callback for GPZDA
myGNSS.setNMEAGPZDAcallbackPtr(&printGPZDA);
// Set up the callback for GNZDA
myGNSS.setNMEAGNZDAcallbackPtr(&printGNZDA);
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,196 @@
/*
Callback Example: ESF RAW (100Hz!)
By: Paul Clark
SparkFun Electronics
Date: September 8th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the External Sensor Fusion RAW IMU sensor messages on the NEO-M8U / ZED-F9R and
uses callbacks to process and display the ESF data automatically.
Notes:
On the ZED-F9R, each ESF RAW message contains _one_ set of IMU sensor data: seven readings in total (3 x Accel, 3 x Gyro, 1 x Temperature).
However, on the NEO-M8U, each message contains _ten_ sets of IMU sensor data, seventy readings in total.
The NEO-M8U data is all timestamped and it is possible to reconstruct the full data stream, you just need to do it
ten samples at a time...
Also, note that the sensor data is 24-bit signed (two's complement). You need to be careful when converting to int32_t.
Data will arrive at 100Hz! (10Hz x 10 on the NEO-M8U)
400kHz I2C is essential...
Serial printing needs to be kept short and the baud rate needs to be at least 230400.
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printESFRAWdata will be called when new ESF RAW data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_RAW_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFRAWcallback
// / _____ This _must_ be UBX_ESF_RAW_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printESFRAWdata(UBX_ESF_RAW_data_t *ubxDataStruct)
{
// ubxDataStruct->numEsfRawBlocks indicates how many sensor readings the UBX_ESF_RAW_data_t contains.
// On the ZED-F9R, numEsfRawBlocks will be 7: 3 x Accel, 3 x Gyro, 1 x Temperature.
// On the NEO-M8U, numEsfRawBlocks will be 70: 10 sets of sensor data. The sensor time tag (sTag)
// indicates the timing of each sample.
// Serial output will be approx. 110 bytes depending on how many digits are in the sensor readings.
// To keep up, Serial needs to be running at 100k baud minimum. 230400 is recommended.
uint32_t sTag = 0xFFFFFFFF; // Sensor time tag
// Only print the first seven sensor readings (on the NEO-M8U)
for (uint8_t i = 0; (i < ubxDataStruct->numEsfRawBlocks) && (i < 7); i++)
// For fun, and to prove it works, uncomment use this line instead to get the full 100Hz data on the NEO-M8U
//for (uint8_t i = 0; i < ubxDataStruct->numEsfRawBlocks; i++)
{
// Print sTag the first time - and also if it changes
if (sTag != ubxDataStruct->data[i].sTag)
{
sTag = ubxDataStruct->data[i].sTag;
Serial.print(F("Time:"));
Serial.println(sTag);
}
// Print the sensor data type
// From the M8 interface description:
// 0: None
// 1-4: Reserved
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 11: speed m/s * 1e-3 signed
// 12: gyroscope temperature deg Celsius * 1e-2 signed
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
switch (ubxDataStruct->data[i].data.bits.dataType)
{
case 5:
Serial.print(F("Zgyr:"));
break;
case 12:
Serial.print(F("Temp:"));
break;
case 13:
Serial.print(F("Ygyr:"));
break;
case 14:
Serial.print(F("Xgyr:"));
break;
case 16:
Serial.print(F("Xacc:"));
break;
case 17:
Serial.print(F("Yacc:"));
break;
case 18:
Serial.print(F("Zacc:"));
break;
default:
break;
}
// Gyro data
if ((ubxDataStruct->data[i].data.bits.dataType == 5) || (ubxDataStruct->data[i].data.bits.dataType == 13) || (ubxDataStruct->data[i].data.bits.dataType == 14))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
rate /= 256.0; // Divide by 256 to undo the shift
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
Serial.println(rate);
}
// Accelerometer data
else if ((ubxDataStruct->data[i].data.bits.dataType == 16) || (ubxDataStruct->data[i].data.bits.dataType == 17) || (ubxDataStruct->data[i].data.bits.dataType == 18))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
force /= 256.0; // Divide by 256 to undo the shift
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
Serial.println(force);
}
// Gyro Temperature
else if (ubxDataStruct->data[i].data.bits.dataType == 12)
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = ubxDataStruct->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
temperature /= 256.0; // Divide by 256 to undo the shift
temperature *= 0.01; // Convert from C * 1e-2 to C
Serial.println(temperature);
}
}
}
void setup()
{
Serial.begin(230400); // <--- Use >> 100k baud (see notes above)
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
Wire.setClock(400000); // <-- Use 400kHz I2C (ESSENTIAL)
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setI2CpollingWait(5); //Allow checkUblox to poll I2C data every 5ms to keep up with the ESF RAW messages
if (myGNSS.setAutoESFRAWcallbackPtr(&printESFRAWdata) == true) // Enable automatic ESF RAW messages with callback to printESFRAWdata
Serial.println(F("setAutoESFRAWcallback successful"));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
}

View file

@ -0,0 +1,209 @@
/*
u-blox Example: ESF RAW (100Hz!)
By: Paul Clark
SparkFun Electronics
Date: September 8th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the External Sensor Fusion RAW IMU sensor messages on the NEO-M8U / ZED-F9R and
shows how to access the ESF data in the loop - without using the callback.
Notes:
On the ZED-F9R, each ESF RAW message contains _one_ set of IMU sensor data: seven readings in total (3 x Accel, 3 x Gyro, 1 x Temperature).
However, on the NEO-M8U, each message contains _ten_ sets of IMU sensor data, seventy readings in total.
The NEO-M8U data is all timestamped and it is possible to reconstruct the full data stream, you just need to do it
ten samples at a time...
Also, note that the sensor data is 24-bit signed (two's complement). You need to be careful when converting to int32_t.
Data will arrive at 100Hz! (10Hz x 10 on the NEO-M8U)
400kHz I2C is essential...
Serial printing needs to be kept short and the baud rate needs to be at least 230400.
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printESFRAWdata will be called when new ESF RAW data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_RAW_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFRAWcallback
// / _____ This _must_ be UBX_ESF_RAW_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printESFRAWdata(UBX_ESF_RAW_data_t *ubxDataStruct)
{
Serial.println(F("Hey! The ESF RAW callback has been called!"));
}
void setup()
{
Serial.begin(230400); // <--- Use >> 100k baud (see notes above)
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
Wire.setClock(400000); // <-- Use 400kHz I2C (ESSENTIAL)
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setI2CpollingWait(5); //Allow checkUblox to poll I2C data every 5ms to keep up with the ESF RAW messages
if (myGNSS.setAutoESFRAWcallbackPtr(&printESFRAWdata) == true) // Enable automatic ESF RAW messages with callback to printESFRAWdata
Serial.println(F("setAutoESFRAWcallback successful"));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// Check if new ESF RAW data has arrived:
// If myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new ESF RAW data has been received and has been copied.
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
if (myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid == true)
{
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
myGNSS.packetUBXESFRAW->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
// myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks indicates how many sensor readings the UBX_ESF_RAW_data_t contains.
// On the ZED-F9R, numEsfRawBlocks will be 7: 3 x Accel, 3 x Gyro, 1 x Temperature.
// On the NEO-M8U, numEsfRawBlocks will be 70: 10 sets of sensor data. The sensor time tag (sTag)
// indicates the timing of each sample.
// Serial output will be approx. 110 bytes depending on how many digits are in the sensor readings.
// To keep up, Serial needs to be running at 100k baud minimum. 230400 is recommended.
uint32_t sTag = 0xFFFFFFFF; // Sensor time tag
// Only print the first seven sensor readings (on the NEO-M8U)
for (uint8_t i = 0; (i < myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks) && (i < 7); i++)
// For fun, and to prove it works, uncomment use this line instead to get the full 100Hz data on the NEO-M8U
//for (uint8_t i = 0; i < myGNSS.packetUBXESFRAW->callbackData->numEsfRawBlocks; i++)
{
// Print sTag the first time - and also if it changes
if (sTag != myGNSS.packetUBXESFRAW->callbackData->data[i].sTag)
{
sTag = myGNSS.packetUBXESFRAW->callbackData->data[i].sTag;
Serial.print(F("Time:"));
Serial.println(sTag);
}
// Print the sensor data type
// From the M8 interface description:
// 0: None
// 1-4: Reserved
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 11: speed m/s * 1e-3 signed
// 12: gyroscope temperature deg Celsius * 1e-2 signed
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
switch (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType)
{
case 5:
Serial.print(F("Zgyr:"));
break;
case 12:
Serial.print(F("Temp:"));
break;
case 13:
Serial.print(F("Ygyr:"));
break;
case 14:
Serial.print(F("Xgyr:"));
break;
case 16:
Serial.print(F("Xacc:"));
break;
case 17:
Serial.print(F("Yacc:"));
break;
case 18:
Serial.print(F("Zacc:"));
break;
default:
break;
}
// Gyro data
if ((myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 5) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 13) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 14))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
rate /= 256.0; // Divide by 256 to undo the shift
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
Serial.println(rate);
}
// Accelerometer data
else if ((myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 16) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 17) || (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 18))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
force /= 256.0; // Divide by 256 to undo the shift
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
Serial.println(force);
}
// Gyro Temperature
else if (myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataType == 12)
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFRAW->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
temperature /= 256.0; // Divide by 256 to undo the shift
temperature *= 0.01; // Convert from C * 1e-2 to C
Serial.println(temperature);
}
}
}
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
}

View file

@ -0,0 +1,224 @@
/*
u-blox Example: ESF MEAS (Wheel Ticks)
By: Paul Clark
SparkFun Electronics
Date: September 8th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the External Sensor Fusion MEAS sensor messages on the NEO-M8U / ZED-F9R and
shows how to access the ESF data in the loop - without using the callback.
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printESFMEASdata will be called when new ESF MEAS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFMEAScallback
// / _____ This _must_ be UBX_ESF_MEAS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct)
{
Serial.println(F("Hey! The ESF MEAS callback has been called!"));
}
void setup()
{
Serial.begin(230400); // <-- Use a fast baud rate to avoid the Serial prints slowing the code
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
Wire.setClock(400000); // <-- Use 400kHz I2C
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
Serial.println(F("setAutoESFMEAScallback successful"));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// Check if new ESF MEAS data has arrived:
// If myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new ESF MEAS data has been received and has been copied.
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
if (myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid == true)
{
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
// Print the timeTag
Serial.print(F("Time: "));
Serial.println(myGNSS.packetUBXESFMEAS->callbackData->timeTag);
// myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas indicates how many sensor groups the UBX_ESF_MEAS_data_t contains.
for (uint8_t i = 0; i < myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas; i++)
{
// Print the sensor data type
// From the M8 interface description:
// 0: None
// 1-4: Reserved
// 5: z-axis gyroscope angular rate deg/s * 2^-12 signed
// 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward)
// 11: speed m/s * 1e-3 signed
// 12: gyroscope temperature deg Celsius * 1e-2 signed
// 13: y-axis gyroscope angular rate deg/s * 2^-12 signed
// 14: x-axis gyroscope angular rate deg/s * 2^-12 signed
// 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed
// 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed
// 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed
switch (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType)
{
case 5:
Serial.print(F("Z Gyro: "));
break;
case 6:
Serial.print(F("Front Left: "));
break;
case 7:
Serial.print(F("Front Right: "));
break;
case 8:
Serial.print(F("Rear Left: "));
break;
case 9:
Serial.print(F("Rear Right: "));
break;
case 10:
Serial.print(F("Speed Ticks: "));
break;
case 11:
Serial.print(F("Speed: "));
break;
case 12:
Serial.print(F("Temp: "));
break;
case 13:
Serial.print(F("Y Gyro: "));
break;
case 14:
Serial.print(F("X Gyro: "));
break;
case 16:
Serial.print(F("X Accel: "));
break;
case 17:
Serial.print(F("Y Accel: "));
break;
case 18:
Serial.print(F("Z Accel: "));
break;
default:
break;
}
// Tick data
if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType >= 6) && (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType <= 10))
{
if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & (1 << 23)) > 0)
Serial.print(F("-")); // Backward
else
Serial.print(F("+")); // Forward
Serial.println(myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & 0x007FFFFF);
}
// Speed
else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 11)
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float speed = signedUnsigned.signed32; // Extract the signed data. Convert to float
speed /= 256.0; // Divide by 256 to undo the shift
speed *= 0.001; // Convert from m/s * 1e-3 to m/s
Serial.println(speed, 3);
}
// Gyro data
else if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 5) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 13) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 14))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float
rate /= 256.0; // Divide by 256 to undo the shift
rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s
Serial.println(rate);
}
// Accelerometer data
else if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 16) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 17) || (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 18))
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float force = signedUnsigned.signed32; // Extract the signed data. Convert to float
force /= 256.0; // Divide by 256 to undo the shift
force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2
Serial.println(force);
}
// Gyro Temperature
else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 12)
{
union
{
int32_t signed32;
uint32_t unsigned32;
} signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t
// The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t
signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data
float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float
temperature /= 256.0; // Divide by 256 to undo the shift
temperature *= 0.01; // Convert from C * 1e-2 to C
Serial.println(temperature);
}
}
}
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
}

View file

@ -0,0 +1,104 @@
/*
Configuring the GNSS to automatically send position reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: December 30th, 2020
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 GNSS to send navigation reports automatically
and access the data via a callback. No more polling!
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = ubxDataStruct->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,110 @@
/*
Configuring the GNSS to automatically send odometer reports over I2C and display the data using a callback
By: Paul Clark
SparkFun Electronics
Date: March 20th, 2023
License: MIT. See license file for more information.
This example shows how to configure the u-blox GNSS to send odometer reports automatically
and display the data via a callback. No more polling!
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printODOdata will be called when new NAV ODO data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_ODO_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVODOcallback
// / _____ This _must_ be UBX_NAV_ODO_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printODOdata(UBX_NAV_ODO_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("TOW: ")); // Print the Time Of Week
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
Serial.print(iTOW);
Serial.print(F(" (ms)"));
Serial.print(F(" Distance: "));
unsigned long distance = ubxDataStruct->distance; // Print the distance
Serial.print(distance);
Serial.print(F(" (m)"));
Serial.print(F(" Total Distance: "));
unsigned long totalDistance = ubxDataStruct->totalDistance; // Print the total distance
Serial.print(totalDistance);
Serial.println(F(" (m)"));
}
void setup()
{
delay(1000);
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
while (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring."));
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second
//By default, the odometer is disabled. We need to enable it.
//We can enable it using the default settings:
myGNSS.enableOdometer();
//Or we can configure it using our own settings, by performing a read-modify-write:
uint8_t flags; // Odometer/Low-speed COG filter flags
uint8_t odoCfg; // Odometer filter settings
uint8_t cogMaxSpeed; // Speed below which course-over-ground (COG) is computed with the low-speed COG filter : m/s * 0.1
uint8_t cogMaxPosAcc; // Maximum acceptable position accuracy for computing COG with the low-speed COG filter
uint8_t velLpGain; // Velocity low-pass filter level
uint8_t cogLpGain; // COG low-pass filter level
if (myGNSS.getOdometerConfig(&flags, &odoCfg, &cogMaxSpeed, &cogMaxPosAcc, &velLpGain, &cogLpGain))
{
flags = UBX_CFG_ODO_USE_ODO; // Enable the odometer
odoCfg = UBX_CFG_ODO_CAR; // Use the car profile (others are RUN, CYCLE, SWIM, CUSTOM)
myGNSS.setOdometerConfig(flags, odoCfg, cogMaxSpeed, cogMaxPosAcc, velLpGain, cogLpGain); // Set the configuration
}
else
Serial.println("Could not read odometer config!");
//myGNSS.resetOdometer(); //Uncomment this line to reset the odometer
myGNSS.setAutoNAVODOcallbackPtr(&printODOdata); // Enable automatic NAV ODO messages with callback to printODOdata
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,115 @@
/*
Configuring the GNSS to automatically send TIM TM2 reports over I2C and display the data using a callback
By: Paul Clark
SparkFun Electronics
Date: December 30th, 2020
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 GNSS to send TIM TM2 reports automatically
and display the data via a callback. No more polling!
Connecting the PPS (Pulse Per Second) breakout pin to the INT (Interrupt) pin with a jumper wire
will cause a TIM TM2 message to be produced once per second. You can then study the timing of the
pulse edges with nanosecond resolution!
Note: TIM TM2 can only capture the timing of one rising edge and one falling edge per
navigation solution. So with setNavigationFrequency set to 1Hz, we can only see the timing
of one rising and one falling edge per second. If the frequency of the signal on the INT pin
is higher than 1Hz, we will only be able to see the timing of the most recent edges.
However, the module can count the number of rising edges too, at rates faster than the navigation rate.
TIM TM2 messages are only produced when a rising or falling edge is detected on the INT pin.
If you disconnect your PPS to INT jumper wire, the messages will stop.
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
NEO-M9N: https://www.sparkfun.com/products/17285
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
// Callback: printTIMTM2data will be called when new TIM TM2 data arrives
// See u-blox_structs.h for the full definition of UBX_TIM_TM2_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
// / _____ This _must_ be UBX_TIM_TM2_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
Serial.print(ubxDataStruct->count);
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
Serial.print(ubxDataStruct->towMsR);
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
Serial.print(ubxDataStruct->towSubMsR);
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
Serial.print(ubxDataStruct->towMsF);
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
Serial.println(ubxDataStruct->towSubMsF);
dotsPrinted = 0; // Reset dotsPrinted
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
if (++dotsPrinted > 50)
{
Serial.println();
dotsPrinted = 0;
}
}

View file

@ -0,0 +1,117 @@
/*
By: Paul Clark
SparkFun Electronics
Date: December, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the High Navigation Rate on the NEO-M8U and then
reads and displays the attitude solution, vehicle dynamics information
and high rate position, velocity and time.
This example uses callbacks to process the HNR data automatically. No more polling!
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printHNRATTdata will be called when new HNR ATT data arrives
// See u-blox_structs.h for the full definition of UBX_HNR_ATT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoHNRATTcallback
// / _____ This _must_ be UBX_HNR_ATT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printHNRATTdata(UBX_HNR_ATT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Roll: ")); // Print selected data
Serial.print((float)ubxDataStruct->roll / 100000.0, 2); // Convert roll to degrees
Serial.print(F(" Pitch: "));
Serial.print((float)ubxDataStruct->pitch / 100000.0, 2); // Convert pitch to degrees
Serial.print(F(" Heading: "));
Serial.println((float)ubxDataStruct->heading / 100000.0, 2); // Convert heading to degrees
}
// Callback: printHNRINSdata will be called when new HNR INS data arrives
// See u-blox_structs.h for the full definition of UBX_HNR_INS_data_t
void printHNRINSdata(UBX_HNR_INS_data_t *ubxDataStruct)
{
Serial.print(F("xAccel: ")); // Print selected data
Serial.print(ubxDataStruct->xAccel);
Serial.print(F(" yAccel: "));
Serial.print(ubxDataStruct->yAccel);
Serial.print(F(" zAccel: "));
Serial.println(ubxDataStruct->zAccel);
}
// Callback: printHNRPVTdata will be called when new HNR PVT data arrives
// See u-blox_structs.h for the full definition of UBX_HNR_PVT_data_t
void printHNRPVTdata(UBX_HNR_PVT_data_t *ubxDataStruct)
{
Serial.print(F("ns: ")); // Print selected data
Serial.print(ubxDataStruct->nano);
Serial.print(F(" Lat: "));
Serial.print(ubxDataStruct->lat);
Serial.print(F(" Lon: "));
Serial.println(ubxDataStruct->lon);
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
Serial.println(F("setHNRNavigationRate was successful"));
else
Serial.println(F("setHNRNavigationRate was NOT successful"));
if (myGNSS.setAutoHNRATTcallbackPtr(&printHNRATTdata) == true) // Enable automatic HNR ATT messages with callback to printHNRATTdata
Serial.println(F("setAutoHNRATTcallback successful"));
if (myGNSS.setAutoHNRINScallbackPtr(&printHNRINSdata) == true) // Enable automatic HNR INS messages with callback to printHNRINSdata
Serial.println(F("setAutoHNRINScallback successful"));
if (myGNSS.setAutoHNRPVTcallbackPtr(&printHNRPVTdata) == true) // Enable automatic HNR PVT messages with callback to printHNRPVTdata
Serial.println(F("setAutoHNRPVTcallback successful"));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(25);
}

View file

@ -0,0 +1,179 @@
/*
By: Paul Clark
SparkFun Electronics
Date: December, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the External Sensor Fusion messages on the NEO-M8U and
uses callbacks to process and display the ESF data automatically. No more polling!
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printESFALGdata will be called when new ESF ALG data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_ALG_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFALGcallback
// / _____ This _must_ be UBX_ESF_ALG_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printESFALGdata(UBX_ESF_ALG_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("TOW: ")); // Print the Time Of Week
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
Serial.print(iTOW);
Serial.print(F(" (ms)"));
Serial.print(F(" Roll: ")); // Print selected data
Serial.print((float)ubxDataStruct->roll / 100.0, 2); // Convert roll to degrees
Serial.print(F(" Pitch: "));
Serial.print((float)ubxDataStruct->pitch / 100.0, 2); // Convert pitch to degrees
Serial.print(F(" Yaw: "));
Serial.print((float)ubxDataStruct->yaw / 100.0, 2); // Convert yaw to degrees
Serial.println(F(" (Degrees)"));
}
// Callback: printESFINSdata will be called when new ESF INS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_INS_data_t
void printESFINSdata(UBX_ESF_INS_data_t *ubxDataStruct)
{
Serial.print(F("xAccel: ")); // Print selected data
Serial.print(ubxDataStruct->xAccel);
Serial.print(F(" yAccel: "));
Serial.print(ubxDataStruct->yAccel);
Serial.print(F(" zAccel: "));
Serial.print(ubxDataStruct->zAccel);
Serial.println(F(" (m/s^2)"));
}
// Callback: printESFMEASdata will be called when new ESF MEAS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t
// and UBX_ESF_MEAS_sensorData_t
void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("id: ")); // Print selected data
Serial.print(ubxDataStruct->id);
Serial.print(F(" numMeas: "));
Serial.println(ubxDataStruct->flags.bits.numMeas);
for (uint8_t num = 0; num < ubxDataStruct->flags.bits.numMeas; num++) // For each sensor
{
Serial.print(F("Sensor "));
Serial.print(num);
UBX_ESF_MEAS_sensorData_t sensorData;
myGNSS.getSensorFusionMeasurement(&sensorData, *ubxDataStruct, num); // Extract the data for one sensor
Serial.print(F(": Type: "));
Serial.print(sensorData.data.bits.dataType);
Serial.print(F(" Data: "));
Serial.println(sensorData.data.bits.dataField);
}
}
// Callback: printESFSTATUSdata will be called when new ESF STATUS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_STATUS_data_t
// and UBX_ESF_STATUS_sensorStatus_t
void printESFSTATUSdata(UBX_ESF_STATUS_data_t *ubxDataStruct)
{
Serial.print(F("fusionMode: ")); // Print selected data
Serial.print(ubxDataStruct->fusionMode);
Serial.print(F(" numSens: "));
Serial.println(ubxDataStruct->numSens);
for (uint8_t num = 0; num < ubxDataStruct->numSens; num++) // For each sensor
{
Serial.print(F("Sensor "));
Serial.print(num);
UBX_ESF_STATUS_sensorStatus_t sensorStatus;
myGNSS.getSensorFusionStatus(&sensorStatus, *ubxDataStruct, num); // Extract the data for one sensor
Serial.print(F(": Type: "));
Serial.print(sensorStatus.sensStatus1.bits.type);
Serial.print(F(" Used: "));
Serial.print(sensorStatus.sensStatus1.bits.used);
Serial.print(F(" Ready: "));
Serial.print(sensorStatus.sensStatus1.bits.ready);
Serial.print(F(" Calib Status: "));
Serial.print(sensorStatus.sensStatus2.bits.calibStatus);
Serial.print(F(" Noisy: "));
Serial.println(sensorStatus.faults.bits.noisyMeas);
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setHNRNavigationRate(1); //Set the High Navigation Rate to 1Hz
myGNSS.setI2CpollingWait(50); //Allow checkUblox to poll I2C data every 50ms to keep up with the ESF MEAS messages
if (myGNSS.setAutoESFALGcallbackPtr(&printESFALGdata) == true) // Enable automatic ESF ALG messages with callback to printESFALGdata
Serial.println(F("setAutoESFALGcallback successful"));
if (myGNSS.setAutoESFINScallbackPtr(&printESFINSdata) == true) // Enable automatic ESF INS messages with callback to printESFINSdata
Serial.println(F("setAutoESFINScallback successful"));
if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
Serial.println(F("setAutoESFMEAScallback successful"));
if (myGNSS.setAutoESFSTATUScallbackPtr(&printESFSTATUSdata) == true) // Enable automatic ESF STATUS messages with callback to printESFSTATUSdata
Serial.println(F("setAutoESFSTATUScallback successful"));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(25);
}

View file

@ -0,0 +1,107 @@
/*
Configuring the GNSS to automatically send RXM RZWX reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: March 11th, 2021
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 GNSS to send RXM RAWX reports automatically
and access the data via a callback. No more polling!
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: newRAWX will be called when new RXM RAWX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
// / _____ This _must_ be UBX_RXM_RAWX_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("New RAWX data received. It contains "));
Serial.print(ubxDataStruct->header.numMeas); // Print numMeas (Number of measurements / blocks)
Serial.println(F(" data blocks:"));
for (uint8_t block = 0; block < ubxDataStruct->header.numMeas; block++) // For each block
{
Serial.print(F("GNSS ID: "));
if (ubxDataStruct->blocks[block].gnssId < 100) Serial.print(F(" ")); // Align the gnssId
if (ubxDataStruct->blocks[block].gnssId < 10) Serial.print(F(" ")); // Align the gnssId
Serial.print(ubxDataStruct->blocks[block].gnssId);
Serial.print(F(" SV ID: "));
if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" ")); // Align the svId
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" ")); // Align the svId
Serial.print(ubxDataStruct->blocks[block].svId);
if (sizeof(double) == 8) // Check if our processor supports 64-bit double
{
// Convert prMes from uint8_t[8] to 64-bit double
// prMes is little-endian
double pseudorange;
memcpy(&pseudorange, &ubxDataStruct->blocks[block].prMes, 8);
Serial.print(F(" PR: "));
Serial.print(pseudorange, 3);
// Convert cpMes from uint8_t[8] to 64-bit double
// cpMes is little-endian
double carrierPhase;
memcpy(&carrierPhase, &ubxDataStruct->blocks[block].cpMes, 8);
Serial.print(F(" m CP: "));
Serial.print(carrierPhase, 3);
Serial.print(F(" cycles"));
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second (RAWX produces a _lot_ of data!)
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,121 @@
/*
Configuring the GNSS to automatically send NAV SAT reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: December 1st, 2021
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 GNSS to send NAV SAT reports automatically
and access the data via a callback. No more polling!
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: newNAVSAT will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newNAVSAT(UBX_NAV_SAT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("New NAV SAT data received. It contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV."));
else
Serial.println(F(" SVs."));
// Just for giggles, print the signal strength for each SV as a barchart
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
switch (ubxDataStruct->blocks[block].gnssId) // Print the GNSS ID
{
case 0:
Serial.print(F("GPS "));
break;
case 1:
Serial.print(F("SBAS "));
break;
case 2:
Serial.print(F("Galileo "));
break;
case 3:
Serial.print(F("BeiDou "));
break;
case 4:
Serial.print(F("IMES "));
break;
case 5:
Serial.print(F("QZSS "));
break;
case 6:
Serial.print(F("GLONASS "));
break;
default:
Serial.print(F("UNKNOWN "));
break;
}
Serial.print(ubxDataStruct->blocks[block].svId); // Print the SV ID
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" "));
else if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" "));
else Serial.print(F(" "));
// Print the signal strength as a bar chart
for (uint8_t cno = 0; cno < ubxDataStruct->blocks[block].cno; cno++)
Serial.print(F("="));
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&newNAVSAT); // Enable automatic NAV SAT messages with callback to newNAVSAT
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,127 @@
/*
Configuring the GNSS to automatically send NAV SVIN reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: April 4th, 2022
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 GNSS to send NAV SVIN reports automatically
and access the data via a callback. No more polling!
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: newNAVSVIN will be called when new NAV SVIN data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SVIN_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSVINcallbackPtr
// / _____ This _must_ be UBX_NAV_SVIN_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newNAVSVIN(UBX_NAV_SVIN_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Survey-in is "));
if (ubxDataStruct->active == 0)
Serial.print(F("not "));
Serial.println(F("in progress"));
Serial.print(F("Survey-in position is "));
if (ubxDataStruct->valid == 0)
Serial.print(F("not "));
Serial.println(F("valid"));
Serial.print(F("Survey-in observation time (s): "));
Serial.println(ubxDataStruct->dur);
Serial.print(F("ECEF position (cm): "));
Serial.print(ubxDataStruct->meanX);
Serial.print(F(" ("));
if (ubxDataStruct->meanXHP >= 0)
Serial.print(F("+"));
Serial.print((float)ubxDataStruct->meanXHP * 0.01); // Convert 0.1mm to cm
Serial.print(F("), "));
Serial.print(ubxDataStruct->meanY);
Serial.print(F(" ("));
if (ubxDataStruct->meanYHP >= 0)
Serial.print(F("+"));
Serial.print((float)ubxDataStruct->meanYHP * 0.01); // Convert 0.1mm to cm
Serial.print(F("), "));
Serial.print(ubxDataStruct->meanZ);
Serial.print(F(" ("));
if (ubxDataStruct->meanZHP >= 0)
Serial.print(F("+"));
Serial.print((float)ubxDataStruct->meanZHP * 0.01); // Convert 0.1mm to cm
Serial.println(F(")"));
Serial.print(F("Mean position accuracy (cm): "));
Serial.println((float)ubxDataStruct->meanAcc * 0.01); // Convert 0.1mm to cm
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("u-blox Base Station example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save the communications port settings to flash and BBR
// Set up the callback for NAV SVIN. This will enable SVIN messages at the navigation rate
myGNSS.setAutoNAVSVINcallbackPtr(&newNAVSVIN);
while (Serial.available()) Serial.read(); //Clear the serial buffer
Serial.println(F("Press any key to begin Survey-In"));
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
myGNSS.checkCallbacks(); //Process any waiting callbacks
if (Serial.available()) // Check if user has pressed a key
{
bool success = myGNSS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
//bool success = myGNSS.enableSurveyModeFull(86400, 2.000); //Enable Survey in, 24 hours, 2.0m
Serial.println();
if (success)
{
Serial.println(F("Survey-In started!"));
}
else
{
Serial.println(F("Survey start failed!"));
}
while (Serial.available()) Serial.read(); //Clear the serial buffer
}
}

View file

@ -0,0 +1,120 @@
/*
Configuring the GNSS to automatically send position reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: April 15th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to access the callback data from the main loop.
The simple way to check if new data is available is to use a global flag: set it in the callback, check it and clear it in the main loop.
Or, you can be more sophisticated and use the callback flags themselves.
This example shows how to use the sophisticated method.
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: callbackPVT will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallbackPtr
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void callbackPVT(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println(F("Hey! The NAV PVT callback has been called!"));
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVTcallbackPtr(&callbackPVT); // Enable automatic NAV PVT messages with callback to callbackPVT
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// Check if new NAV PVT data has been received:
// If myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new PVT data has been received and has been copied.
// automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called.
if (myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid == true)
{
// But, we can manually clear the callback flag too. This will prevent the callback from being called!
myGNSS.packetUBXNAVPVT->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = myGNSS.packetUBXNAVPVT->callbackData->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = myGNSS.packetUBXNAVPVT->callbackData->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = myGNSS.packetUBXNAVPVT->callbackData->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = myGNSS.packetUBXNAVPVT->callbackData->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = myGNSS.packetUBXNAVPVT->callbackData->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = myGNSS.packetUBXNAVPVT->callbackData->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.packetUBXNAVPVT->callbackData->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
}
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. There will not be any in this example, unless you commented the line above
Serial.print(".");
delay(50);
}

View file

@ -0,0 +1,256 @@
/*
Configuring the GNSS to automatically send NAV PVT reports over I2C and log them to file on SD card
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send NAV PVT reports automatically
and log the data to SD card in UBX format.
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
You can replay and analyze the data using u-center:
https://www.u-blox.com/en/product/u-center
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
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define packetLength 100 // NAV PVT is 92 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = ubxDataStruct->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin(); // Start I2C communication with the GNSS
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "NAV_PVT.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("NAV_PVT.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
// NAV PVT messages are 100 bytes long.
// In this example, the data will arrive no faster than one message per second.
// So, setting the file buffer size to 301 bytes should be more than adequate.
// I.e. room for three messages plus an empty tail byte.
myGNSS.setFileBufferSize(301); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte NAV PVT message has been stored
{
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
//printBuffer(myBuffer); // Uncomment this line to print the data as Hexadecimal bytes
}
if (Serial.available()) // Check if the user wants to stop logging
{
myFile.close(); // Close the data file
Serial.println(F("\r\nLogging stopped. Freezing..."));
while(1); // Do nothing more
}
Serial.print(".");
delay(50);
}
// Print the buffer contents as Hexadecimal bytes
// You should see:
// SYNC CHAR 1: 0xB5
// SYNC CHAR 2: 0x62
// CLASS: 0x01 for NAV
// ID: 0x07 for PVT
// LENGTH: 2-bytes Little Endian (0x5C00 = 92 bytes for NAV PVT)
// PAYLOAD: LENGTH bytes
// CHECKSUM_A
// CHECKSUM_B
// Please see the u-blox protocol specification for more details
void printBuffer(uint8_t *ptr)
{
for (int i = 0; i < packetLength; i++)
{
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
Serial.print(" ");
}
Serial.println();
}

View file

@ -0,0 +1,267 @@
/*
Configuring the GNSS to automatically send TIM TM2 reports over I2C and log them to file on SD card
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send TIM TM2 reports automatically
and log the data to SD card in UBX format.
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
Connecting the PPS (Pulse Per Second) breakout pin to the INT (Interrupt) pin with a jumper wire
will cause a TIM TM2 message to be produced once per second. You can then study the timing of the
pulse edges with nanosecond resolution!
Note: TIM TM2 can only capture the timing of one rising edge and one falling edge per
navigation solution. So with setNavigationFrequency set to 1Hz, we can only see the timing
of one rising and one falling edge per second. If the frequency of the signal on the INT pin
is higher than 1Hz, we will only be able to see the timing of the most recent edges.
However, the module can count the number of rising edges too, at rates faster than the navigation rate.
TIM TM2 messages are only produced when a rising or falling edge is detected on the INT pin.
If you disconnect your PPS to INT jumper wire, the messages will stop.
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
You can replay and analyze the data using u-center:
https://www.u-blox.com/en/product/u-center
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
NEO-M9N: https://www.sparkfun.com/products/17285
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define packetLength 36 // TIM TM2 is 28 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
// Callback: printTIMTM2data will be called when new TIM TM2 data arrives
// See u-blox_structs.h for the full definition of UBX_TIM_TM2_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
// / _____ This _must_ be UBX_TIM_TM2_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
Serial.print(ubxDataStruct->count);
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
Serial.print(ubxDataStruct->towMsR);
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
Serial.print(ubxDataStruct->towSubMsR);
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
Serial.print(ubxDataStruct->towMsF);
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
Serial.println(ubxDataStruct->towSubMsF);
dotsPrinted = 0; // Reset dotsPrinted
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin(); // Start I2C communication with the GNSS
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "TIM_TM2.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("TIM_TM2.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
// TIM TM2 messages are 36 bytes long.
// In this example, the data will arrive no faster than one message per second.
// So, setting the file buffer size to 109 bytes should be more than adequate.
// I.e. room for three messages plus an empty tail byte.
myGNSS.setFileBufferSize(109); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
myGNSS.logTIMTM2(); // Enable TIM TM2 data logging
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte TIM TM2 message has been stored
{
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
//printBuffer(myBuffer); // Uncomment this line to print the data
}
if (Serial.available()) // Check if the user wants to stop logging
{
myFile.close(); // Close the data file
Serial.println(F("\r\nLogging stopped. Freezing..."));
while(1); // Do nothing more
}
Serial.print("."); // Print dots in rows of 50
delay(50);
if (++dotsPrinted > 50)
{
Serial.println();
dotsPrinted = 0;
}
}
// Print the buffer contents as Hexadecimal
// You should see:
// SYNC CHAR 1: 0xB5
// SYNC CHAR 2: 0x62
// CLASS: 0x0D for TIM
// ID: 0x03 for TM2
// LENGTH: 2-bytes Little Endian (0x1C00 = 28 bytes for TIM TM2)
// PAYLOAD: LENGTH bytes
// CHECKSUM_A
// CHECKSUM_B
// Please see the u-blox protocol specification for more details
void printBuffer(uint8_t *ptr)
{
for (int i = 0; i < packetLength; i++)
{
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
Serial.print(" ");
}
Serial.println();
}

View file

@ -0,0 +1,297 @@
/*
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send RXM SFRBX and RAWX reports automatically
and log the data to SD card in UBX format.
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
You can replay and analyze the data using u-center:
https://www.u-blox.com/en/product/u-center
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
Post-Processed Kinematic data:
https://rtklibexplorer.wordpress.com/
http://rtkexplorer.com/downloads/rtklib-code/
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
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
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate.
// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will
// only increase by one.
int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above)
int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above)
// Callback: newSFRBX will be called when new RXM SFRBX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct)
{
numSFRBX++; // Increment the count
}
// Callback: newRAWX will be called when new RXM RAWX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
// / _____ This _must_ be UBX_RXM_RAWX_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
{
numRAWX++; // Increment the count
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
digitalWrite(LED_BUILTIN, LOW);
Wire.begin(); // Start I2C communication
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "RXM_RAWX.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
// to hold the backlog of data if/when this happens.
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print the message count once per second
{
Serial.print(F("Number of message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
Serial.print(numSFRBX);
Serial.print(F(" RAWX: "));
Serial.println(numRAWX);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
//Serial.println(maxBufferBytes);
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
{
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
}
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
myFile.close(); // Close the data file
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}

View file

@ -0,0 +1,271 @@
/*
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
** without using callbacks **
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send RXM SFRBX and RAWX reports automatically
and log the data to SD card in UBX format ** without using callbacks **
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
You can replay and analyze the data using u-center:
https://www.u-blox.com/en/product/u-center
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
Post-Processed Kinematic data:
https://rtklibexplorer.wordpress.com/
http://rtkexplorer.com/downloads/rtklib-code/
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
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
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
digitalWrite(LED_BUILTIN, LOW);
Wire.begin(); // Start I2C communication
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "RXM_RAWX.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
// to hold the backlog of data if/when this happens.
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += sdWriteSize; // Update bytesWritten
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
{
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
//Serial.println(maxBufferBytes);
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
{
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
}
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += bytesToWrite; // Update bytesWritten
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
myFile.close(); // Close the data file
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}

View file

@ -0,0 +1,296 @@
/*
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
without using callbacks and ** as fast as your module can go! **
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send RXM SFRBX and RAWX reports automatically
and log the data to SD card in UBX format without using callbacks and ** as fast as your module can go! **
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
You can replay and analyze the data using u-center:
https://www.u-blox.com/en/product/u-center
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
Post-Processed Kinematic data:
https://rtklibexplorer.wordpress.com/
http://rtkexplorer.com/downloads/rtklib-code/
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
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
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 32768 // Allocate 32KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
digitalWrite(LED_BUILTIN, LOW);
Wire.begin(); // Start I2C communication
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "Fast_RXM.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("Fast_RXM.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
// to hold the backlog of data if/when this happens.
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// (This will also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
// Modules like the ZED-F9P can produce RAW navigation data at rates of up to 25Hz but not while using all of the GNSS constellations.
// Please consult the data sheet for the Performance figures for your module.
// In this example we make sure GPS is enabled and then disable Galileo, GLONASS, BeiDou, SBAS and QZSS to achieve 25Hz.
myGNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS); // Make sure GPS is enabled (we must leave at least one major GNSS enabled!)
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_SBAS); // Disable SBAS
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GALILEO); // Disable Galileo
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_BEIDOU); // Disable BeiDou
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_IMES); // Disable IMES
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_QZSS); // Disable QZSS
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GLONASS); // Disable GLONASS
delay(2000); // Give the module some extra time to get ready
//Produce 7 navigation solutions per second. That's a lot of RAWX data - especially when using both GPS bands L1 and L2.
//The SD library and card need to be able to cope with the data rate too. You may need a faster SD library to go above 7Hz.
myGNSS.setNavigationFrequency(7);
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += sdWriteSize; // Update bytesWritten
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
{
Serial.print(F("The number of bytes written to SD card is: ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
//Serial.println(maxBufferBytes);
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
{
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
}
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
myGNSS.setAutoRXMSFRBX(false, false); // Disable the automatic RXM SFRBX messages
myGNSS.setAutoRXMRAWX(false, false); // Disable the automatic RXM RAWX messages
delay(1000); // Allow time for any remaining messages to arrive
myGNSS.checkUblox(); // Process any remaining data
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += bytesToWrite; // Update bytesWritten
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
Serial.print(F("The total number of bytes written to SD card is: ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Show how full the file buffer has been (not how full it is now)
Serial.print(F("The maximum number of bytes which the file buffer has contained is: "));
Serial.println(maxBufferBytes);
myFile.close(); // Close the data file
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}

View file

@ -0,0 +1,265 @@
/*
Demonstrate how to log NMEA and UBX data simultaneously
By: Paul Clark
SparkFun Electronics
Date: October 18th, 2021
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 GNSS to send PVT reports automatically
and log those and any incoming NMEA messages to SD card in UBX format
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
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
ZOE-M8Q: https://www.sparkfun.com/products/15193
SAM-M8Q: https://www.sparkfun.com/products/15210
*/
#include <SPI.h>
#include <SD.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;
File myFile; //File that all GNSS data is written to
//Define the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
#else
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
#endif
#else
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
#endif
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
digitalWrite(LED_BUILTIN, LOW);
Wire.begin(); // Start I2C communication
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
#endif
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "PVT_NMEA.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("PVT_NMEA.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
//myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F. Uncomment this line to disable the "7F" check in checkUbloxI2C
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
// to hold the backlog of data if/when this happens.
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// This will (re)enable the standard NMEA messages too
// This will also disable any "auto" UBX messages that were enabled and saved by other examples and reduce the load on the I2C bus
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both UBX and NMEA messages
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoPVT(true, false); // Enable automatic NAV PVT messages: without callback; without implicit update
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 1); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every measurement.
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C, 1); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every measurement.
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C, 1); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every measurement.
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_ALL); // Enable logging of all enabled NMEA messages
//myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA); // Or we can, for example, log only GxGGA & GxGSA and ignore GxGSV
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += sdWriteSize; // Update bytesWritten
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
{
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
//Serial.println(maxBufferBytes);
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
{
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
}
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += bytesToWrite; // Update bytesWritten
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
myFile.close(); // Close the data file
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}

View file

@ -0,0 +1,340 @@
/*
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over SPI and log them to file on SD card using full 4-bit SDIO
By: Paul Clark
SparkFun Electronics
Date: October 20th, 2022
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 GNSS to send RXM SFRBX and RAWX reports automatically
and log the data to SD card in UBX format.
This code is written for the OpenLog ESP32 (DEV-20594) - coming soon!
Hardware set-up:
Close the DSEL jumper on the ZED-F9P breakout - to select SPI mode
Connect:
OpenLog ESP32 : ZED-F9P
GND GND
3V3_SW 3V3
SCK (18) SCK
PICO (23) PICO (MOSI)
POCI (19) POCI (MISO)
33 CS
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
Data is logged in u-blox UBX format.
Feel like supporting open source hardware?
Buy a board from SparkFun!
OpenLog ESP32: https://www.sparkfun.com/products/20594
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
NEO-M8P RTK: https://www.sparkfun.com/products/15005
*/
#define GNSS_CS 33 // Connect the ZED-F9P CS pin to OpenLog ESP32 pin 33
#define EN_3V3_SW 32 // The 3.3V_SW regulator Enable pin is connected to D32
#define STAT_LED 25 // The OpenLog ESP32 STAT LED is connected to pin 25
#define IMU_CS 5 // The ISM330 IMU CS is connected to pin 5
#define MAG_CS 27 // The MMC5983 Mag CS is connected to pin 27
#include "FS.h"
#include "SD_MMC.h"
File myFile;
#include <SPI.h>
#define spiPort SPI
#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;
#define sdWriteSize 2048 // Write data to the SD card in blocks of n*512 bytes
#define fileBufferSize 65530 // Allocate just under 64KBytes of RAM for UBX message storage
#define navRate 20 // Set the Nav Rate (Frequency) to 20Hz
//#define ubxOnly // Uncomment this line to log UBX (RAWX and SFRBX) only
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate.
// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will
// only increase by one.
int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above)
int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above)
// Callback: newSFRBX will be called when new RXM SFRBX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct)
{
numSFRBX++; // Increment the count
}
// Callback: newRAWX will be called when new RXM RAWX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
// / _____ This _must_ be UBX_RXM_RAWX_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
{
numRAWX++; // Increment the count
}
void setup()
{
Serial.begin(115200);
pinMode(STAT_LED, OUTPUT); // Flash the STAT LED each time we write to the SD card
digitalWrite(STAT_LED, LOW);
pinMode(GNSS_CS, OUTPUT);
digitalWrite(GNSS_CS, HIGH);
pinMode(IMU_CS, OUTPUT);
digitalWrite(IMU_CS, HIGH);
pinMode(MAG_CS, OUTPUT);
digitalWrite(MAG_CS, HIGH);
spiPort.begin();
// Do a fake transaction to initialize the SPI pins
spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
spiPort.transfer(0);
spiPort.endTransaction();
pinMode(EN_3V3_SW, OUTPUT); // Enable power for the microSD card and GNSS
digitalWrite(EN_3V3_SW, HIGH);
delay(3000); // Allow time for the GNSS and SD card to start up and for Tera Term to reconnect
Serial.println(F("SparkFun OpenLog ESP32 GNSS Logging : SPI and SDIO"));
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Initialize the GNSS
Serial.println(F("Initializing the GNSS..."));
//myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
// Connect to the u-blox module using SPI port, csPin and speed setting
// ublox devices generally work up to 5MHz. We'll use 4MHz for this example:
bool begun = false;
do
{
begun = myGNSS.begin(spiPort, GNSS_CS, 4000000);
if (!begun)
{
Serial.println(F("u-blox GNSS not detected on SPI bus."));
delay(1000);
}
}
while (!begun);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Wait for a 3D fix. Get the date and time for the log file
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults
#ifdef ubxOnly
myGNSS.setSPIOutput(COM_TYPE_UBX); //Set the SPI port to output only UBX
#else
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the SPI port to output both UBX and NMEA messages
#endif
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
Serial.print(F("Waiting for a 3D fix"));
uint8_t fix = 0;
do
{
fix = myGNSS.getFixType();
delay(1000);
Serial.print(F("."));
}
while ( fix != 3 ); // Wait for a 3D fix
Serial.println();
uint16_t y = myGNSS.getYear();
uint8_t M = myGNSS.getMonth();
uint8_t d = myGNSS.getDay();
uint8_t h = myGNSS.getHour();
uint8_t m = myGNSS.getMinute();
uint8_t s = myGNSS.getSecond();
char szBuffer[40] = {'\0'};
snprintf(szBuffer, sizeof(szBuffer), "/%04d%02d%02d%02d%02d%02d.ubx", y, M, d, h, m, s);
Serial.println(F("GNSS initialized."));
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Initialize the SD card. Open the log file
Serial.println(F("Initializing SD card..."));
// Begin the SD card
if(!SD_MMC.begin())
{
Serial.println(F("Card mount failed. Freezing..."));
while(1);
}
// Open the log file for writing
Serial.printf("Log file is: %s\r\n", szBuffer);
myFile = SD_MMC.open((const char *)szBuffer, FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to open log file for writing. Freezing..."));
while(1);
}
Serial.println(F("SD card initialized."));
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Wait for a key press
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable RAWX and SFRBX
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
#ifndef ubxOnly
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, navRate); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every second.
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_SPI, navRate); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every second.
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_SPI, navRate); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every second.
myGNSS.enableNMEAMessage(UBX_NMEA_GST, COM_PORT_SPI, navRate); // Ensure the GxGST (Position error statistics) message is enabled. Send every second.
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_SPI, navRate); // Ensure the GxRMC (Recommended minimum: position, velocity and time) message is enabled. Send every second.
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA | SFE_UBLOX_FILTER_NMEA_GSV | SFE_UBLOX_FILTER_NMEA_GST | SFE_UBLOX_FILTER_NMEA_RMC); // Log only these NMEA messages
#endif
myGNSS.setNavigationFrequency(navRate); // Set navigation rate
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(STAT_LED, HIGH); // Flash the STAT LED each time we write to the SD card
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
digitalWrite(STAT_LED, LOW); // Turn the STAT LED off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print the message count once per second
{
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
float bufferHigh = 100.0 * (float)maxBufferBytes / (float)fileBufferSize;
Serial.print(F("Message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
Serial.print(numSFRBX);
Serial.print(F(" RAWX: "));
Serial.print(numRAWX);
Serial.print(F(" \tBuffer high tide: "));
Serial.print(bufferHigh, 1); // It is a fun thing to watch how full the buffer gets
if (bufferHigh > 90.)
Serial.println(F("%!!"));
else if (bufferHigh > 80.)
Serial.println(F("%!"));
else
Serial.println(F("%"));
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(STAT_LED, HIGH); // Flash the STAT LED while we write to the SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(STAT_LED, LOW); // Turn the STAT LED off
myFile.close(); // Close the data file
myGNSS.setNavigationFrequency(1); // Set navigation rate to 1Hz
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_RAWX, COM_PORT_SPI);
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_SFRBX, COM_PORT_SPI);
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); // Re-enable NMEA
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}

View file

@ -0,0 +1,75 @@
/*
By: Elias Santistevan
SparkFun Electronics
Date: May, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
To take advantage of the internal IMU of either the Dead Reckoning GNSS
boards (ZED-F9R, NEO-M8U), you must first calibrate it. This includes securing the GNSS module
to your vehicle so that it is stable within 2 degrees and that the frame of
reference of the board is consistent with the picture outlined in the
Receiver-Description-Prot-Spec Datasheet under Automotive/Untethered Dead
Reckoning. You may also check either the ZED-F9R or NEO-M8U Hookup Guide for
more information. After the board is secure, you'll need to put the module
through certain conditions for proper calibration: acceleration, turning,
stopping for a few minutes, getting to a speed over 30km/h all under a clear sky
with good GNSS signal. This example simply looks at the
"fusionMode" status which indicates whether the SparkFun Dead Reckoning is
initializing - 0, calibrated - 1, or if an error has occurred - 2,3.
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.resetIMUalignment(); // Uncomment this line to reset the IMU alignment
}
void loop()
{
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
{
Serial.print(F("Fusion Mode: "));
Serial.print(myGNSS.packetUBXESFSTATUS->data.fusionMode);
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 0)
Serial.println(F(" Sensor is initializing..."));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1)
Serial.println(F(" Sensor is calibrated!"));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 2)
Serial.println(F(" Sensor fusion is suspended!"));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 3)
Serial.println(F(" Sensor fusion is disabled!"));
}
delay(250);
}

View file

@ -0,0 +1,91 @@
/*
By: Elias Santistevan
SparkFun Electronics
Date: May, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
After calibrating the module, also known as "Fusion Mode", you can get
data directly from the IMU. This data is integrated directly into the GNSS
output, but is provided by the module as well.
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
if (myGNSS.getEsfInfo()){
Serial.print(F("Fusion Mode: "));
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
Serial.println(F("Fusion Mode is Initialized!"));
}
else {
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
Serial.println(F("Please see the previous example for more information."));
}
}
}
void loop()
{
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getEsfIns()) // Poll new ESF INS data
{
Serial.print(F("X Ang Rate: "));
Serial.print(myGNSS.packetUBXESFINS->data.xAngRate);
Serial.print(F(" Y Ang Rate: "));
Serial.print(myGNSS.packetUBXESFINS->data.yAngRate);
Serial.print(F(" Z Ang Rate: "));
Serial.print(myGNSS.packetUBXESFINS->data.zAngRate);
Serial.print(F(" X Accel: "));
Serial.print(myGNSS.packetUBXESFINS->data.xAccel);
Serial.print(F(" Y Accel: "));
Serial.print(myGNSS.packetUBXESFINS->data.yAccel);
Serial.print(F(" Z Accel: "));
Serial.print(myGNSS.packetUBXESFINS->data.zAccel);
// These values also have "validity checks" that can be provided by the
// ublox library by reading bitfield0
Serial.print(F(" Validity: "));
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.xAngRateValid);
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.yAngRateValid);
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.zAngRateValid);
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.xAccelValid);
Serial.print(myGNSS.packetUBXESFINS->data.bitfield0.bits.yAccelValid);
Serial.println(myGNSS.packetUBXESFINS->data.bitfield0.bits.zAccelValid);
}
delay(250);
}

View file

@ -0,0 +1,125 @@
/*
By: Elias Santistevan
SparkFun Electronics
Date: May, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
After calibrating the module, also known as "Fusion Mode", you can get
data directly from the IMU. This example code walks you through trouble
shooting or identifying the different states of any individual
"external" (which include internal) sensors you've hooked up (vehicle speed
sensor) or the internal IMU used by the modules. You can see if the sensor is
being used, if it's calibrated, ready, what data type it returns, the state
of the measurement etc.
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// GetEsfInfo also gets the number of sensors used by the ublox module, this
// includes (in the case of the ZED-F9R) wheel tick input from the vehicle
// speed sensor attached to the module.
if (myGNSS.getEsfInfo()){
Serial.print(F("Fusion Mode: "));
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
Serial.println(F("Fusion Mode is Initialized!"));
}
else {
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
Serial.println(F("Please see the previous example for more information."));
}
}
}
void loop()
{
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
{
UBX_ESF_STATUS_sensorStatus_t sensorStatus; // Create storage for the individual sensor status
//See ublox receiver description or our hookup guide for information on the return values
Serial.println(F(" "));
Serial.println(F(" C "));
Serial.println(F(" a "));
Serial.println(F(" l "));
Serial.println(F(" i "));
Serial.println(F(" b M "));
Serial.println(F(" r i N"));
Serial.println(F(" a B s o"));
Serial.println(F(" S t T B a s i"));
Serial.println(F("S e B i i a d e s"));
Serial.println(F("e n e o m d d y"));
Serial.println(F("n s i I n e T "));
Serial.println(F("s o n s M i M M"));
Serial.println(F("o r g S S e m e e"));
Serial.println(F("r R t t a e a a"));
Serial.println(F(" T U e a a s s s"));
Serial.println(F("N y s a t t u T u u"));
Serial.println(F("o p e d u u r a r r"));
Serial.println(F(". e d y s s e g e e"));
Serial.println(F(" "));
for(uint8_t i = 0; i < myGNSS.packetUBXESFSTATUS->data.numSens; i++)
{
myGNSS.getSensorFusionStatus(&sensorStatus, i); // Extract the individual sensor data for this sensor
Serial.print(i); Serial.print(F(" ")); // Print the sensor number
// Print the sensor type
Serial.print(sensorStatus.sensStatus1.bits.type);
if (sensorStatus.sensStatus1.bits.type < 10) Serial.print(F(" "));
Serial.print(F(" "));
Serial.print(sensorStatus.sensStatus1.bits.used); Serial.print(F(" ")); // Print the used flag
Serial.print(sensorStatus.sensStatus1.bits.ready); Serial.print(F(" ")); // Print the ready flag
Serial.print(sensorStatus.sensStatus2.bits.calibStatus); Serial.print(F(" ")); // Print the calibration status
Serial.print(sensorStatus.sensStatus2.bits.timeStatus); Serial.print(F(" ")); // Print the time status
Serial.print(sensorStatus.faults.bits.badMeas); Serial.print(F(" ")); // Print the bad measurement flag
Serial.print(sensorStatus.faults.bits.badTTag); Serial.print(F(" ")); // Print the time tag flag
Serial.print(sensorStatus.faults.bits.missingMeas); Serial.print(F(" ")); // Print the missing measurement flag
Serial.print(sensorStatus.faults.bits.noisyMeas); // Print the noisy measure flag
Serial.println();
}
}
delay(250);
}

View file

@ -0,0 +1,95 @@
/*
By: Elias Santistevan
SparkFun Electronics
Date: May, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
getEsfAlignment (UBX-ESF-ALG) reports the status and alignment angles of the IMU within the vehicle.
These define the rotation of the IMU frame within the vehicle (installation frame) - not the heading
of the vehicle itself. The vehicle attitude solution is reported separately by getNAVATT (UBX-NAV-ATT).
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setESFAutoAlignment(true); //Enable Automatic IMU-mount Alignment
if (myGNSS.getEsfInfo()){
Serial.print(F("Fusion Mode: "));
Serial.println(myGNSS.packetUBXESFSTATUS->data.fusionMode);
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1){
Serial.println(F("Fusion Mode is Initialized!"));
}
else {
Serial.println(F("Fusion Mode is either disabled or not initialized!"));
Serial.println(F("Please see the previous example for more information."));
}
}
}
void loop()
{
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getEsfAlignment()) // Poll new ESF ALG data
{
Serial.print(F("IMU-Mount Alignment: On/Off: "));
Serial.print(myGNSS.packetUBXESFALG->data.flags.bits.autoMntAlgOn);
Serial.print(F(" Status: "));
Serial.print(myGNSS.packetUBXESFALG->data.flags.bits.status);
Serial.print(F(" Roll: "));
Serial.print(myGNSS.getESFroll(), 2); // Use the helper function to get the roll in degrees
Serial.print(F(" Pitch: "));
Serial.print(myGNSS.getESFpitch(), 2); // Use the helper function to get the pitch in degrees
Serial.print(F(" Yaw: "));
Serial.print(myGNSS.getESFyaw(), 2); // Use the helper function to get the yaw in degrees
Serial.print(F(" Errors: "));
Serial.print(myGNSS.packetUBXESFALG->data.error.bits.tiltAlgError);
Serial.print(myGNSS.packetUBXESFALG->data.error.bits.yawAlgError);
Serial.println(myGNSS.packetUBXESFALG->data.error.bits.angleError);
}
if (myGNSS.getNAVATT()) // Poll new NAV ATT data
{
Serial.print(F("Vehicle Attitude: Roll: "));
Serial.print(myGNSS.getATTroll(), 2); // Use the helper function to get the roll in degrees
Serial.print(F(" Pitch: "));
Serial.print(myGNSS.getATTpitch(), 2); // Use the helper function to get the pitch in degrees
Serial.print(F(" Heading: "));
Serial.println(myGNSS.getATTheading(), 2); // Use the helper function to get the heading in degrees
}
delay(250);
}

View file

@ -0,0 +1,94 @@
/*
By: Paul Clark
SparkFun Electronics
Date: December, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the High Navigation Rate on the NEO-M8U and then
polls and displays the attitude solution, vehicle dynamics information
and high rate position, velocity and time.
This example polls the high rate data.
(The next example uses "autoHNR" to receive the HNR data automatically.)
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
Serial.println(F("setHNRNavigationRate was successful"));
else
Serial.println(F("setHNRNavigationRate was NOT successful"));
myGNSS.setAutoHNRATT(false); //Make sure auto HNR attitude messages are disabled
myGNSS.setAutoHNRINS(false); //Make sure auto HNR vehicle dynamics messages are disabled
myGNSS.setAutoHNRPVT(false); //Make sure auto HNR PVT messages are disabled
}
void loop()
{
// Poll and print selected HNR data
if (myGNSS.getHNRAtt(125) == true) // Request HNR Att data using a 125ms timeout
{
Serial.print(F("Roll: "));
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
Serial.print(F(" Pitch: "));
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
Serial.print(F(" Heading: "));
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
}
if (myGNSS.getHNRDyn(125) == true) // Request HNR Dyn data using a 125ms timeout
{
Serial.print(F("xAccel: "));
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
Serial.print(F(" yAccel: "));
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
Serial.print(F(" zAccel: "));
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
}
if (myGNSS.getHNRPVT(125) == true) // Request HNR PVT data using a 125ms timeout
{
Serial.print(F("ns: "));
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
Serial.print(F(" Lat: "));
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
Serial.print(F(" Lon: "));
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
}
}

View file

@ -0,0 +1,107 @@
/*
By: Paul Clark
SparkFun Electronics
Date: December, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the High Navigation Rate on the NEO-M8U and then
reads and displays the attitude solution, vehicle dynamics information
and high rate position, velocity and time.
This example uses "autoHNR" to receive the HNR data automatically.
Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary:
https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
bool usingAutoHNRAtt = false;
bool usingAutoHNRDyn = false;
bool usingAutoHNRPVT = false;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
if (myGNSS.setHNRNavigationRate(10) == true) //Set the High Navigation Rate to 10Hz
Serial.println(F("setHNRNavigationRate was successful"));
else
Serial.println(F("setHNRNavigationRate was NOT successful"));
usingAutoHNRAtt = myGNSS.setAutoHNRATT(true); //Attempt to enable auto HNR attitude messages
if (usingAutoHNRAtt)
Serial.println(F("AutoHNRATT successful"));
usingAutoHNRDyn = myGNSS.setAutoHNRINS(true); //Attempt to enable auto HNR vehicle dynamics messages
if (usingAutoHNRDyn)
Serial.println(F("AutoHNRINS successful"));
usingAutoHNRPVT = myGNSS.setAutoHNRPVT(true); //Attempt to enable auto HNR PVT messages
if (usingAutoHNRPVT)
Serial.println(F("AutoHNRPVT successful"));
}
void loop()
{
if (usingAutoHNRAtt && (myGNSS.getHNRAtt() == true)) // If setAutoHNRAtt was successful and new data is available
{
Serial.print(F("Roll: ")); // Print selected data
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
Serial.print(F(" Pitch: "));
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
Serial.print(F(" Heading: "));
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
myGNSS.flushHNRATT(); // Mark data as stale
}
if (usingAutoHNRDyn && (myGNSS.getHNRDyn() == true)) // If setAutoHNRDyn was successful and new data is available
{
Serial.print(F("xAccel: ")); // Print selected data
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
Serial.print(F(" yAccel: "));
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
Serial.print(F(" zAccel: "));
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
myGNSS.flushHNRINS(); // Mark data as stale
}
if (usingAutoHNRPVT && (myGNSS.getHNRPVT() == true)) // If setAutoHNRPVT was successful and new data is available
{
Serial.print(F("ns: ")); // Print selected data
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
Serial.print(F(" Lat: "));
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
Serial.print(F(" Lon: "));
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
myGNSS.flushHNRPVT(); // Mark data as stale
}
}

View file

@ -0,0 +1,116 @@
/*
By: Nathan Seidle
SparkFun Electronics
Date: August, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example configures the AutoAlignment option for the IMU.
The ZED-F9R Integration guide recommends enabling Auto Alignment once
the device has been attached to the vehicle's frame.
Enabling auto-alignment will cause the the sensor fusion status
to begin initialization. After driving around a few turns, the sensors
should enter 'Calibrated' state. See example 1 for fusion state or
monitor UBX-ESF-STATUS.
As of writing the ZED-F9R is using HPS v1.2 firmware. Please update using u-center if necessary.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9R: https://www.sparkfun.com/products/16344
ZED-F9R pHat: https://www.sparkfun.com/products/16475
NEO-M8U: https://www.sparkfun.com/products/16329
Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
If you don't have a platform with a Qwiic connection use the
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/17912)
Open the serial monitor at 115200 baud to see the output
*/
#include <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("Warning! u-blox GPS did not begin correctly."));
Serial.println(F("(This may be because the I2C port is busy with HNR messages.)"));
}
bool esfAutoAlignment = myGNSS.getESFAutoAlignment();
Serial.print(F("esfAutoAlignment: "));
if (esfAutoAlignment == true)
Serial.println(F("True"));
else
Serial.println(F("False"));
myGNSS.setESFAutoAlignment(true); //Enable UBX-CFG-ESFALG Automatic IMU-mount Alignment
myGNSS.setAutoHNRATT(false); //Make sure auto HNR attitude messages are disabled
myGNSS.setAutoHNRINS(false); //Make sure auto HNR vehicle dynamics messages are disabled
myGNSS.setAutoHNRPVT(false); //Make sure auto HNR PVT messages are disabled
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
}
void loop()
{
// ESF data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getEsfInfo()) // Poll new ESF STATUS data
{
Serial.print(F("Fusion Mode: "));
Serial.print(myGNSS.packetUBXESFSTATUS->data.fusionMode);
if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 0)
Serial.println(F(" Sensor is initializing..."));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 1)
Serial.println(F(" Sensor is calibrated!"));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 2)
Serial.println(F(" Sensor fusion is suspended!"));
else if (myGNSS.packetUBXESFSTATUS->data.fusionMode == 3)
Serial.println(F(" Sensor fusion is disabled!"));
}
// Poll and print selected HNR data
if (myGNSS.getHNRAtt(125) == true) // Request HNR Att data using a 125ms timeout
{
Serial.print(F("Roll: "));
Serial.print(myGNSS.getHNRroll(), 2); // Use the helper function to get the roll in degrees
Serial.print(F(" Pitch: "));
Serial.print(myGNSS.getHNRpitch(), 2); // Use the helper function to get the pitch in degrees
Serial.print(F(" Heading: "));
Serial.println(myGNSS.getHNRheading(), 2); // Use the helper function to get the heading in degrees
}
if (myGNSS.getHNRDyn(125) == true) // Request HNR Dyn data using a 125ms timeout
{
Serial.print(F("xAccel: "));
Serial.print(myGNSS.packetUBXHNRINS->data.xAccel);
Serial.print(F(" yAccel: "));
Serial.print(myGNSS.packetUBXHNRINS->data.yAccel);
Serial.print(F(" zAccel: "));
Serial.println(myGNSS.packetUBXHNRINS->data.zAccel);
}
if (myGNSS.getHNRPVT(125) == true) // Request HNR PVT data using a 125ms timeout
{
Serial.print(F("ns: "));
Serial.print(myGNSS.packetUBXHNRPVT->data.nano);
Serial.print(F(" Lat: "));
Serial.print(myGNSS.packetUBXHNRPVT->data.lat);
Serial.print(F(" Lon: "));
Serial.println(myGNSS.packetUBXHNRPVT->data.lon);
}
}

View file

@ -0,0 +1,111 @@
/*
By: Paul CLark
SparkFun Electronics
Date: January, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
After calibrating the module and securing it to your vehicle such that it's
stable within 2 degrees, and the board is oriented correctly with regards to
the vehicle's frame, you can now read the vehicle's "attitude". The attitude
includes the vehicle's heading, pitch, and roll.
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
}
void loop()
{
// PVAT data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getNAVPVAT()) // Poll new PVAT
{
Serial.print(F("Roll: "));
Serial.print((float)myGNSS.getVehicleRoll() / 100000.0, 5); // Use the helper function to get the roll in degrees * 10^-5
Serial.print(F(" Pitch: "));
Serial.print((float)myGNSS.getVehiclePitch() / 100000.0, 5); // Use the helper function to get the pitch in degrees * 10^-5
Serial.print(F(" Heading: "));
Serial.print((float)myGNSS.getVehicleHeading() / 100000.0, 5); // Use the helper function to get the heading in degrees * 10^-5
// We don't have helper functions to extract the roll, pitch and heading valid flags from the PVAT message. But we can do it manually:
Serial.print(F(" Roll Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehRollValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehRollValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Pitch Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehPitchValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehPitchValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Heading Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehHeadingValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehHeadingValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
// We don't have helper functions to extract the roll, pitch and heading accuracy from the PVAT message. But we can do it manually:
Serial.print(F(" Roll Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accRoll) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accRoll = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Pitch Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accPitch) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accPitch = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Heading Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accHeading) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accHeading = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
// We don't have helper functions to extract the lat and lon from the PVAT message. But we can do it manually:
Serial.print(F(" Lat: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lat) / 10000000.0, 7);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lat = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Lon: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lon) / 10000000.0, 7);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lon = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.println();
}
delay(250);
}

View file

@ -0,0 +1,82 @@
/*
Reading two altitudes - Mean Sea Level and Ellipsode
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for its lat/long/altitude.
getAltitude() reports mm above ellipsode model of the globe. There are some
instances where altitude above Mean Sea Level is better. This example shows how
to use getAltitudeMSL(). The difference varies but is ~20m.
Ellipsoid model: https://www.esri.com/news/arcuser/0703/geoid1of3.html
Difference between Ellipsoid Model and Mean Sea Level: https://eos-gnss.com/elevation-for-beginners/
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Tracks the passing of 2000ms (2 seconds)
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
long altitudeMSL = myGNSS.getAltitudeMSL();
Serial.print(F(" AltMSL: "));
Serial.print(altitudeMSL);
Serial.print(F(" (mm)"));
Serial.println();
}
}

View file

@ -0,0 +1,60 @@
/*
Send command to reset module over I2C
By: Nathan Seidle
Date: January 29rd, 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 reset the U-Blox module to factory defaults over I2C.
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 GNSS 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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
while (Serial.available()) Serial.read(); //Trash any incoming chars
Serial.println("Press a key to reset module to factory defaults");
while (Serial.available() == false) ; //Wait for user to send character
myGNSS.factoryReset(); //Reset everything: baud rate, I2C address, update rate, everything.
delay(5000); // Wait while the module restarts
while (myGNSS.begin() == false) //Attempt to re-connect
{
delay(1000);
Serial.println(F("Attempting to re-connect to u-blox GNSS..."));
}
Serial.println("Unit has now been factory reset. Freezing...");
while(1); // Do nothing more
}
void loop()
{
}

View file

@ -0,0 +1,110 @@
/*
Test baud rate changes on serial, factory reset, and hard reset.
By: Thorsten von Eicken
Date: January 29rd, 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 reset the U-Blox module to factory defaults over serial.
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:
Connect the U-Blox serial port to Serial1
If you're using a Uno or don't have a 2nd serial port (Serial1), use SoftwareSerial instead (see below)
Open the serial monitor at 115200 baud to see the output
*/
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#include <SoftwareSerial.h>
//#define mySerial Serial1 // Uncomment this line to connect via Serial1
// - or -
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
#define defaultRate 9600 // Uncomment this line if you are using an M8 - which defaults to 9600 Baud on UART1
// - or -
//#define defaultRate 38400 // Uncomment this line if you are using an F9 - which defaults to 38400 Baud on UART1
int state = 0; // steps through auto-baud, reset, etc states
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
}
void loop()
{
Serial.print("===== STATE ");
Serial.println(state);
switch (state) {
case 0: // auto-baud connection, then switch to 38400 and save config
do {
Serial.println("GNSS: trying 38400 baud");
mySerial.begin(38400);
if (myGNSS.begin(mySerial)) break;
delay(100);
Serial.println("GNSS: trying 9600 baud");
mySerial.begin(9600);
if (myGNSS.begin(mySerial)) {
Serial.println("GNSS: connected at 9600 baud, switching to 38400");
myGNSS.setSerialRate(38400);
delay(100);
} else {
delay(2000); //Wait a bit before trying again to limit the Serial output flood
}
} while(1);
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
Serial.println("GNSS serial connected, saved config");
state++;
break;
case 1: // hardReset, expect to see GNSS back at 38400 baud
Serial.println("Issuing hardReset (cold start)");
myGNSS.hardReset();
delay(2000);
mySerial.begin(38400);
if (myGNSS.begin(mySerial)) {
Serial.println("Success.");
state++;
} else {
Serial.println("*** GNSS did not respond at 38400 baud, starting over.");
state = 0;
}
break;
case 2: // factoryReset, expect to see GNSS back at defaultRate baud
Serial.println("Issuing factoryReset");
myGNSS.factoryReset();
delay(5000); // takes more than one second... a loop to resync would be best
mySerial.begin(defaultRate);
if (myGNSS.begin(mySerial)) {
Serial.println("Success.");
state++;
} else {
Serial.println("*** GNSS did not come back at defaultRate baud, starting over.");
state = 0;
}
break;
case 3: // print version info
// Note: this may fail on boards like the UNO (ATmega328P) with modules like the ZED-F9P
// because getProtocolVersion returns a lot of data - more than the UNO's serial buffer can hold
Serial.print("GNSS protocol version: ");
Serial.print(myGNSS.getProtocolVersionHigh());
Serial.print('.');
Serial.println(myGNSS.getProtocolVersionLow());
Serial.println("All finished! Freezing...");
while(1);
}
delay(1000);
}

View file

@ -0,0 +1,98 @@
/*
Reading lat and long via UBX binary commands using UART @38400 baud - free from I2C
By: Nathan Seidle, Adapted from Example3_GetPosition by Thorsten von Eicken
SparkFun Electronics
Date: January 28rd, 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 and U-Blox for serial port use as well as
switching the module from the default 9600 baud to 38400.
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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
Hardware Connections:
Connect the U-Blox serial TX pin to Uno pin 10
Connect the U-Blox serial RX pin to Uno pin 11
Open the serial monitor at 115200 baud to see the output
*/
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX. Pin 10 on Uno goes to TX pin on GNSS module.
long lastTime = 0; //Simple local timer. Limits amount of I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
//Assume that the U-Blox GNSS is running at 9600 baud (the default) or at 38400 baud.
//Loop until we're in sync and then ensure it's at 38400 baud.
do {
Serial.println("GNSS: trying 38400 baud");
mySerial.begin(38400);
if (myGNSS.begin(mySerial) == true) break;
delay(100);
Serial.println("GNSS: trying 9600 baud");
mySerial.begin(9600);
if (myGNSS.begin(mySerial) == true) {
Serial.println("GNSS: connected at 9600 baud, switching to 38400");
myGNSS.setSerialRate(38400);
delay(100);
} else {
//myGNSS.factoryReset();
delay(2000); //Wait a bit before trying again to limit the Serial output
}
} while(1);
Serial.println("GNSS serial connected");
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
}

View file

@ -0,0 +1,141 @@
/*
Configuring the GNSS to automatically send position reports over I2C
By: Nathan Seidle and Thorsten von Eicken
SparkFun Electronics
Date: January 3rd, 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 GNSS the send navigation reports automatically
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS
produces a fresh navigation solution at the expense of returning a slighly old solution.
This can be used over serial or over I2C, this example shows the I2C use. With serial the GNSS
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
void loop()
{
// Calling getPVT returns true if there actually is a fresh navigation solution available.
// Start the reading only when valid LLH is available
if (myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false))
{
Serial.println();
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
int PDOP = myGNSS.getPDOP();
Serial.print(F(" PDOP: "));
Serial.print(PDOP);
Serial.print(F(" (10^-2)"));
int nedNorthVel = myGNSS.getNedNorthVel();
Serial.print(F(" VelN: "));
Serial.print(nedNorthVel);
Serial.print(F(" (mm/s)"));
int nedEastVel = myGNSS.getNedEastVel();
Serial.print(F(" VelE: "));
Serial.print(nedEastVel);
Serial.print(F(" (mm/s)"));
int nedDownVel = myGNSS.getNedDownVel();
Serial.print(F(" VelD: "));
Serial.print(nedDownVel);
Serial.print(F(" (mm/s)"));
int verticalAccEst = myGNSS.getVerticalAccEst();
Serial.print(F(" VAccEst: "));
Serial.print(verticalAccEst);
Serial.print(F(" (mm)"));
int horizontalAccEst = myGNSS.getHorizontalAccEst();
Serial.print(F(" HAccEst: "));
Serial.print(horizontalAccEst);
Serial.print(F(" (mm)"));
int speedAccEst = myGNSS.getSpeedAccEst();
Serial.print(F(" SpeedAccEst: "));
Serial.print(speedAccEst);
Serial.print(F(" (mm/s)"));
int headAccEst = myGNSS.getHeadingAccEst();
Serial.print(F(" HeadAccEst: "));
Serial.print(headAccEst);
Serial.print(F(" (degrees * 10^-5)"));
if (myGNSS.getHeadVehValid() == true) {
int headVeh = myGNSS.getHeadVeh();
Serial.print(F(" HeadVeh: "));
Serial.print(headVeh);
Serial.print(F(" (degrees * 10^-5)"));
int magDec = myGNSS.getMagDec();
Serial.print(F(" MagDec: "));
Serial.print(magDec);
Serial.print(F(" (degrees * 10^-2)"));
int magAcc = myGNSS.getMagAcc();
Serial.print(F(" MagAcc: "));
Serial.print(magAcc);
Serial.print(F(" (degrees * 10^-2)"));
}
Serial.println();
} else {
Serial.print(".");
delay(50);
}
}

View file

@ -0,0 +1,103 @@
/*
Configuring the GNSS 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 GNSS 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 GNSS
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVT(true, false); //Tell the GNSS to "send" each solution and the lib not to update stale data implicitly
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
/*
Calling getPVT would return false now (compare to previous example 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 GNSS 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
// GNSS 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 = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
// call checkUblox all 50ms to capture the GNSS data
if (counter % 50 == 0)
{
myGNSS.checkUblox();
}
delay(1);
counter++;
}

View file

@ -0,0 +1,107 @@
/*
Configuring the GNSS to automatically send position reports over Serial
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 U-Blox GNSS the send navigation reports automatically
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS
produces a fresh navigation solution at the expense of returning a slighly old solution.
This can be used over serial or over I2C, this example shows the Serial use. With serial the GNSS
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.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#include <SoftwareSerial.h>
//#define mySerial Serial2 // Uncomment this line to connect via Serial2
// - or -
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
//#define baudRate 9600 // Uncomment this line to select 9600 Baud for the M8
// - or -
#define baudRate 38400 // Uncomment this line to select 38400 Baud for the F9
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
mySerial.begin(baudRate); // Start the Serial port
if (myGNSS.begin(mySerial) == false) //Connect to the u-blox module using Serial
{
Serial.println(F("u-blox GNSS not detected. Please check wiring. Freezing."));
while (1);
}
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART1 port to output UBX only (turn off NMEA noise)
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
void loop()
{
// getPVT will return true if there actually is a fresh navigation solution available.
// Important note: the PVT message is 100 bytes long. We need to call getPVT often enough
// to prevent serial buffer overflows on boards like the original RedBoard / UNO.
// At 38400 Baud, the 100 PVT bytes will arrive in 26ms.
// On the RedBoard, we need to call getPVT every 5ms to keep up.
if (myGNSS.getPVT())
{
Serial.println();
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
else
{
delay(5); // Delay for 5ms only
static int counter = 0; // Print a dot every 50ms
counter++;
if (counter > 10)
{
Serial.print(".");
counter = 0;
}
}
}

View file

@ -0,0 +1,110 @@
/*
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 :-)
This example only works correctly if the module has already been configured is sending PVT messages via its UART1 TX pin.
Run the previous example to enable the auto PVT messages if you need to.
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
Or, switch to SoftwareSerial
Open the serial monitor at 115200 baud to see the output
*/
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#include <SoftwareSerial.h>
//#define mySerial Serial2 // Uncomment this line to connect via Serial2
// - or -
SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
//#define baudRate 9600 // Uncomment this line to select 9600 Baud for the M8
// - or -
#define baudRate 38400 // Uncomment this line to select 38400 Baud for the F9
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
//Use any Serial port with at least a RX Pin connected or a receive only version of SoftwareSerial here
//Assume that the U-Blox GNSS is running at baudRate baud
mySerial.begin(baudRate);
// No need to check return value as internal call to isConnected() will not succeed
myGNSS.begin(mySerial);
// 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);
}
void loop()
{
// If implicit updates are enabled, calling getPVT will trigger parsing of the incoming messages
// and return 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.
//
// Important note: the PVT message is 100 bytes long. We need to call getPVT often enough
// to prevent serial buffer overflows on boards like the original RedBoard / UNO.
// At 38400 Baud, the 100 PVT bytes will arrive in 26ms.
// On the RedBoard, we need to call getPVT every 5ms to keep up.
if (myGNSS.getPVT())
{
Serial.println();
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
else
{
delay(5); // Delay for 5ms only
static int counter = 0; // Print a dot every 50ms
counter++;
if (counter > 10)
{
Serial.print(".");
counter = 0;
}
}
}

View file

@ -0,0 +1,107 @@
/*
Debug Output
By: Nathan Seidle, Adapted from Example3_GetPosition by Thorsten von Eicken
SparkFun Electronics
Date: January 28rd, 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 debug output from the library.
Debug shows various packet and status outputs. These prints can be directed
towards Serial (as in Serial.print) or any other port (Serial1, SerialUSB, etc).
You can also limit the debug messages to the "critical" ones by adding an extra argument.
The debug messages can be disabled again by calling disableDebugging()
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 GNSS 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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
unsigned long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
int counter = 0; // Disable the debug messages when counter reaches 20
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
myGNSS.enableDebugging(); //Enable all the debug messages over Serial (default)
//myGNSS.enableDebugging(SerialUSB); //Enable debug messages over Serial USB
//myGNSS.enableDebugging(Serial, true); //Enable only the critical debug messages over Serial
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.print(F(" "));
Serial.print(myGNSS.getYear());
Serial.print(F("-"));
Serial.print(myGNSS.getMonth());
Serial.print(F("-"));
Serial.print(myGNSS.getDay());
Serial.print(F(" "));
Serial.print(myGNSS.getHour());
Serial.print(F(":"));
Serial.print(myGNSS.getMinute());
Serial.print(F(":"));
Serial.println(myGNSS.getSecond());
Serial.println();
counter++; // Increment counter
if (counter == 20)
{
myGNSS.disableDebugging(); // Disable the debug messages when counter reaches 20
}
}
}

View file

@ -0,0 +1,107 @@
/*
Getting time and date using u-blox commands
By: davidallenmann
SparkFun Electronics
Date: April 16th, 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 query a u-blox module for the current time and date. We also
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
dramatically.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
Serial.print(myGNSS.getYear());
Serial.print("-");
Serial.print(myGNSS.getMonth());
Serial.print("-");
Serial.print(myGNSS.getDay());
Serial.print(" ");
Serial.print(myGNSS.getHour());
Serial.print(":");
Serial.print(myGNSS.getMinute());
Serial.print(":");
Serial.print(myGNSS.getSecond());
Serial.print(" Time is ");
if (myGNSS.getTimeValid() == false)
{
Serial.print("not ");
}
Serial.print("valid Date is ");
if (myGNSS.getDateValid() == false)
{
Serial.print("not ");
}
Serial.print("valid");
Serial.println();
}
}

View file

@ -0,0 +1,109 @@
/*
Getting time and date using u-blox commands
By: davidallenmann
SparkFun Electronics
Date: April 16th, 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 query a u-blox module for the current time and date. We also
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
dramatically.
Note: you will need to set your Serial Monitor to 500000 Baud to see the output
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(500000); //Increase serial speed to maximize
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
Wire.setClock(400000); // Increase I2C clock speed to 400kHz
//myGNSS.enableDebugging(); //Uncomment this line to enable debug messages over Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
myGNSS.setNavigationFrequency(5); //Set output to 5 times a second
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
Serial.print("Current update rate: ");
Serial.println(rate);
}
void loop()
{
// Calling getPVT returns true if there actually is a fresh navigation solution available.
if (myGNSS.getPVT())
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.print(" ");
Serial.print(myGNSS.getYear());
Serial.print("-");
Serial.print(myGNSS.getMonth());
Serial.print("-");
Serial.print(myGNSS.getDay());
Serial.print(" ");
Serial.print(myGNSS.getHour());
Serial.print(":");
Serial.print(myGNSS.getMinute());
Serial.print(":");
Serial.print(myGNSS.getSecond());
Serial.print(" nanoseconds: ");
Serial.print(myGNSS.getNanosecond()); // Nanoseconds can be negative
myGNSS.flushPVT();
Serial.println();
}
}

View file

@ -0,0 +1,118 @@
/*
Getting time and date using u-blox commands
By: Nathan Seidle
SparkFun Electronics
Date: April 16th, 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 use the Millisecond and Nanosecond output as well as increase the
I2C speed (100 to 400kHz), and serial output (115200 to 500kbps).
Note: you will need to set your Serial Monitor to 500000 Baud to see the output
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(500000); //Increase serial speed to maximize
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
Wire.setClock(400000); // Increase I2C clock speed to 400kHz
//myGNSS.enableDebugging(); //Uncomment this line to enable debug messages over Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Note: not all u-blox modules can output solutions at 10Hz - or not while tracking all satellite constellations
// If the rate drops back to 1Hz, you're asking too much of your module
myGNSS.setNavigationFrequency(10); //Set output to 10 times a second
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
Serial.print("Current update rate:");
Serial.println(rate);
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
void loop()
{
// Calling getPVT returns true if there actually is a fresh navigation solution available.
if (myGNSS.getPVT())
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.print(" ");
Serial.print(myGNSS.getYear());
Serial.print("-");
Serial.print(myGNSS.getMonth());
Serial.print("-");
Serial.print(myGNSS.getDay());
Serial.print(" ");
Serial.print(myGNSS.getHour());
Serial.print(":");
Serial.print(myGNSS.getMinute());
Serial.print(":");
Serial.print(myGNSS.getSecond());
Serial.print(".");
//Pretty print leading zeros
int mseconds = myGNSS.getMillisecond();
if (mseconds < 100)
Serial.print("0");
if (mseconds < 10)
Serial.print("0");
Serial.print(mseconds);
Serial.print(" nanoseconds: ");
Serial.print(myGNSS.getNanosecond());
Serial.println();
}
}

View file

@ -0,0 +1,169 @@
/*
u-blox M8 geofence example
Written by Paul Clark (PaulZC)
10th December 2019
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example demonstrates how to use the addGeofence and getGeofenceState functions
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/15210
ZOE-M8Q: https://www.sparkfun.com/products/15193
This example powers up the GNSS and reads the fix.
Once a valid 3D fix has been found, the code reads the latitude and longitude.
The code then sets four geofences around that position with a radii of 5m, 10m, 15m and 20m with 95% confidence.
The code then monitors the geofence status.
The LED will be illuminated if you are inside the _combined_ geofence (i.e. within the 20m radius).
This code has been tested on the ZOE-M8Q.
*/
#define LED LED_BUILTIN // Change this if your LED is on a different pin
#include <Wire.h> // Needed for I2C
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
pinMode(LED, OUTPUT);
// Set up the I2C pins
Wire.begin();
// Start the console serial port
Serial.begin(115200);
while (!Serial); // Wait for the user to open the serial monitor
delay(100);
Serial.println();
Serial.println();
Serial.println(F("u-blox M8 geofence example"));
Serial.println();
Serial.println();
delay(1000); // Let the GNSS power up
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
//myGNSS.enableDebugging(); // Enable debug messages
myGNSS.setI2COutput(COM_TYPE_UBX); // Limit I2C output to UBX (disable the NMEA noise)
Serial.println(F("Waiting for a 3D fix..."));
byte fixType = 0;
while (fixType < 3)
{
fixType = myGNSS.getFixType(); // Get the fix type
Serial.print(F("Fix: ")); // Print it
Serial.print(fixType);
if(fixType == 0) Serial.print(F(" = No fix"));
else if(fixType == 1) Serial.print(F(" = Dead reckoning"));
else if(fixType == 2) Serial.print(F(" = 2D"));
else if(fixType == 3) Serial.print(F(" = 3D"));
else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F(" = Time only"));
Serial.println();
delay(1000);
}
Serial.println(F("3D fix found!"));
long latitude = myGNSS.getLatitude(); // Get the latitude in degrees * 10^-7
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude(); // Get the longitude in degrees * 10^-7
Serial.print(F(" Long: "));
Serial.println(longitude);
uint32_t radius = 500; // Set the radius to 5m (radius is in m * 10^-2 i.e. cm)
byte confidence = 2; // Set the confidence level: 0=none, 1=68%, 2=95%, 3=99.7%, 4=99.99%
// Call clearGeofences() to clear all existing geofences.
Serial.print(F("Clearing any existing geofences. clearGeofences returned: "));
Serial.println(myGNSS.clearGeofences());
// It is possible to define up to four geofences.
// Call addGeofence up to four times to define them.
Serial.println(F("Setting the geofences:"));
Serial.print(F("addGeofence for geofence 1 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
radius = 1000; // 10m
Serial.print(F("addGeofence for geofence 2 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
radius = 1500; // 15m
Serial.print(F("addGeofence for geofence 3 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
radius = 2000; // 20m
Serial.print(F("addGeofence for geofence 4 returned: "));
Serial.println(myGNSS.addGeofence(latitude, longitude, radius, confidence));
}
void loop()
{
geofenceState currentGeofenceState; // Create storage for the geofence state
bool result = myGNSS.getGeofenceState(currentGeofenceState);
Serial.print(F("getGeofenceState returned: ")); // Print the combined state
Serial.print(result); // Get the geofence state
if (!result) // If getGeofenceState did not return true
{
Serial.println(F(".")); // Tidy up
return; // and go round the loop again
}
Serial.print(F(". status is: ")); // Print the status
Serial.print(currentGeofenceState.status);
Serial.print(F(". numFences is: ")); // Print the numFences
Serial.print(currentGeofenceState.numFences);
Serial.print(F(". combState is: ")); // Print the combined state
Serial.print(currentGeofenceState.combState);
if (currentGeofenceState.combState == 0)
{
Serial.print(F(" = Unknown"));
digitalWrite(LED, LOW);
}
if (currentGeofenceState.combState == 1)
{
Serial.print(F(" = Inside"));
digitalWrite(LED, HIGH);
}
else if (currentGeofenceState.combState == 2)
{
Serial.print(F(" = Outside"));
digitalWrite(LED, LOW);
}
Serial.print(F(". The individual states are: ")); // Print the state of each geofence
for(int i = 0; i < currentGeofenceState.numFences; i++)
{
if (i > 0) Serial.print(F(","));
Serial.print(currentGeofenceState.states[i]);
}
Serial.println();
delay(1000);
}

View file

@ -0,0 +1,163 @@
/*
Power Save Mode
By: Paul Clark (PaulZC)
Date: April 22nd, 2020
Based extensively on Example3_GetPosition
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 put the u-blox module into power save mode and then
query its lat/long/altitude. We also turn off the NMEA output on the I2C port.
This decreases the amount of I2C traffic dramatically.
** When it is able to ** the module will reduce its current draw.
For the ZOE-M8Q with a passive antenna, you should see the current drop
from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in.
Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Uncomment this line to save the current settings to flash and BBR
Serial.println("Power save example.");
Serial.println("1) Enable power saving");
Serial.println("2) Disable power saving");
}
void loop()
{
if (Serial.available())
{
byte incoming = Serial.read();
if (incoming == '1')
{
// Put the GNSS into power save mode
// (If you want to disable power save mode, call myGNSS.powerSaveMode(false) instead)
// This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
if (myGNSS.powerSaveMode()) // Defaults to true
Serial.println(F("Power Save Mode enabled."));
else
Serial.println(F("*** Power Save Mode FAILED ***"));
}
else if (incoming == '2')
{
//Go to normal power mode (not power saving mode)
if (myGNSS.powerSaveMode(false))
Serial.println(F("Power Save Mode disabled."));
else
Serial.println(F("*** Power Save Disable FAILED ***"));
}
// Read and print the new low power mode
uint8_t lowPowerMode = myGNSS.getPowerSaveMode();
if (lowPowerMode == 255)
{
Serial.println(F("*** getPowerSaveMode FAILED ***"));
}
else
{
Serial.print(F("The low power mode is: "));
Serial.print(lowPowerMode);
if (lowPowerMode == 0)
{
Serial.println(F(" (Continuous)"));
}
else if (lowPowerMode == 1)
{
Serial.println(F(" (Power Save)"));
}
else if (lowPowerMode == 4)
{
Serial.println(F(" (Continuous)"));
}
else
{
Serial.println(F(" (Unknown!)"));
}
}
}
//Query module every 10 seconds so it is easier to monitor the current draw
if (millis() - lastTime > 10000)
{
lastTime = millis(); //Update the timer
byte fixType = myGNSS.getFixType(); // Get the fix type
Serial.print(F("Fix: "));
Serial.print(fixType);
if (fixType == 0)
Serial.print(F("(No fix)"));
else if (fixType == 1)
Serial.print(F("(Dead reckoning)"));
else if (fixType == 2)
Serial.print(F("(2D)"));
else if (fixType == 3)
Serial.print(F("(3D)"));
else if (fixType == 4)
Serial.print(F("(GNSS + Dead reckoning)"));
long latitude = myGNSS.getLatitude();
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
Serial.println();
}
}

View file

@ -0,0 +1,117 @@
/*
Set Dynamic Model
By: Paul Clark (PaulZC)
Date: April 22nd, 2020
Based extensively on Example3_GetPosition
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 change the u-blox module's dynamic platform model and then
query its lat/long/altitude. We also turn off the NMEA output on the I2C port.
This decreases the amount of I2C traffic dramatically.
Possible values for the dynamic model are: PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE,
SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// If we are going to change the dynamic platform model, let's do it here.
// Possible values are:
// PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
if (myGNSS.setDynamicModel(DYN_MODEL_PORTABLE) == false) // Set the dynamic model to PORTABLE
{
Serial.println(F("*** Warning: setDynamicModel failed ***"));
}
else
{
Serial.println(F("Dynamic platform model changed successfully!"));
}
// Let's read the new dynamic model to see if it worked
uint8_t newDynamicModel = myGNSS.getDynamicModel();
if (newDynamicModel == DYN_MODEL_UNKNOWN)
{
Serial.println(F("*** Warning: getDynamicModel failed ***"));
}
else
{
Serial.print(F("The new dynamic model is: "));
Serial.println(newDynamicModel);
}
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
Serial.println();
}
}

View file

@ -0,0 +1,54 @@
/*
Read NMEA sentences over I2C using u-blox module SAM-M8Q, NEO-M8P, ZED-F9P, etc
By: Nathan Seidle
SparkFun Electronics
Date: August 22nd, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example reads the NMEA setences from the u-blox module over I2c and outputs
them to the serial port
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 GNSS 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 <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;
void setup()
{
Serial.begin(115200);
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
//This will pipe all NMEA sentences to the serial port so we can see them
myGNSS.setNMEAOutputPort(Serial);
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
delay(250); //Don't pound too hard on the I2C bus
}

View file

@ -0,0 +1,172 @@
/*
Send Custom Command
By: Paul Clark (PaulZC)
Date: April 20th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how you can create and send a custom UBX packet
using the SparkFun u-blox library.
Previously it was possible to create and send a custom packet
through the library but it would always appear to timeout as
some of the internal functions referred to the internal private
struct packetCfg.
The most recent version of the library allows sendCommand to
use a custom packet as if it were packetCfg and so:
- sendCommand will return a sfe_ublox_status_e enum as if
it had been called from within the library
- the custom packet will be updated with data returned by the module
(previously this was not possible from outside the library)
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 GNSS 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
*/
#define NAV_RATE 5 // The new navigation rate in Hz (measurements per second)
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200); // You may need to increase this for high navigation rates!
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Let's configure the module's navigation rate as if we were using setNavigationFrequency
// Let's create our custom packet
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes. MAX_PAYLOAD_SIZE defaults to 256. The CFG_RATE payload is only 6 bytes!
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
// It is more memory-efficient to call setPacketCfgPayloadSize before .begin (to avoid creating a new buffer, copying across
// the contents of the old buffer and then deleting the old buffer). But let's call it here just to prove that we can.
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
// The next line creates and initialises the packet information which wraps around the payload
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
// The structure of ubxPacket is:
// uint8_t cls : The message Class
// uint8_t id : The message ID
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
// uint8_t *payload : The payload
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
// uint8_t checksumB
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
// sendCommand will return:
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
// the navigation rate is configured using the UBX-CFG-RATE message. So let's load our
// custom packet with the correct information so we can read (poll / get) the current settings.
customCfg.cls = UBX_CLASS_CFG; // This is the message Class
customCfg.id = UBX_CFG_RATE; // This is the message ID
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
// We also need to tell sendCommand how long it should wait for a reply
uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)
// Now let's read the current navigation rate. The results will be loaded into customCfg.
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
{
Serial.println(F("sendCommand (poll / get) failed! Freezing..."));
while (1)
;
}
// Referring to the message definition for UBX-CFG-RATE we see that the measurement rate
// is stored in payload bytes 0 and 1 as a uint16_t in LSB-first (little endian) format
uint16_t rate = (customPayload[1] << 8) | customPayload[0]; // Extract the current rate (ms)
float f_rate = 1000.0 / ((float)rate); // Convert the navigation rate to Hz (measurements per second)
// Print the current measurement rate
Serial.print(F("The current measurement rate is: "));
Serial.println(f_rate, 1);
// Let's change it
rate = 1000 / NAV_RATE; // Load the new value into rate
customPayload[0] = rate & 0xFF; // Store it in the payload
customPayload[1] = rate >> 8;
// Print the new measurement rate
Serial.print(F("The new measurement rate will be: "));
Serial.println(NAV_RATE);
// We don't need to update customCfg.len as it will have been set to 6
// when sendCommand read the data
// Now we write the custom packet back again to change the setting
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK
{
Serial.println(F("sendCommand (set) failed! Freezing."));
while (1)
;
}
else
{
Serial.println(F("Navigation rate updated. Here we go..."));
}
myGNSS.setAutoPVT(true); // Enable AutoPVT. The module will generate measurements automatically without being polled.
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR
}
void loop()
{
//Query the module as fast as possible
int32_t latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
int32_t longitude = myGNSS.getLongitude();
Serial.print(F(" Lon: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
int32_t altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
uint16_t milliseconds = myGNSS.getMillisecond();
Serial.print(F(" Milliseconds: "));
Serial.print(milliseconds);
Serial.println();
}

View file

@ -0,0 +1,197 @@
/*
Module Info - extracts and prints the full module information from UBX_MON_VER
using a custom command.
By: @mayopan
Date: May 9th, 2020
Based on:
Send Custom Command
By: Paul Clark (PaulZC)
Date: April 20th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Previously it was possible to create and send a custom packet
through the library but it would always appear to timeout as
some of the internal functions referred to the internal private
struct packetCfg.
The most recent version of the library allows sendCommand to
use a custom packet as if it were packetCfg and so:
- sendCommand will return a sfe_ublox_status_e enum as if
it had been called from within the library
- the custom packet will be updated with data returned by the module
(previously this was not possible from outside the library)
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#define MAX_PAYLOAD_SIZE 384 // Override MAX_PAYLOAD_SIZE for getModuleInfo which can return up to 348 bytes
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
// Extend the class for getModuleInfo
class SFE_UBLOX_GPS_ADD : public SFE_UBLOX_GNSS
{
public:
bool getModuleInfo(uint16_t maxWait = 1100); //Queries module, texts
struct minfoStructure // Structure to hold the module info (uses 341 bytes of RAM)
{
char swVersion[30];
char hwVersion[10];
uint8_t extensionNo = 0;
char extension[10][30];
} minfo;
};
SFE_UBLOX_GPS_ADD myGNSS;
void setup()
{
Serial.begin(115200); // You may need to increase this for high navigation rates!
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
// If we call it after the .begin, the library will attempt to resize the existing 256 byte payload buffer
// by creating a new buffer, copying across the contents of the old buffer, and then delete the old buffer.
// This uses a lot of RAM and causes the code to fail on the ATmega328P. (We are also allocating another 341 bytes for minfo.)
// To keep the code ATmega328P compliant - don't call setPacketCfgPayloadSize after .begin. Call it here instead.
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
Serial.print(F("Polling module info"));
if (myGNSS.getModuleInfo(1100) == false) // Try to get the module info
{
Serial.print(F("getModuleInfo failed! Freezing..."));
while (1)
;
}
Serial.println();
Serial.println();
Serial.println(F("Module Info : "));
Serial.print(F("Soft version: "));
Serial.println(myGNSS.minfo.swVersion);
Serial.print(F("Hard version: "));
Serial.println(myGNSS.minfo.hwVersion);
Serial.print(F("Extensions:"));
Serial.println(myGNSS.minfo.extensionNo);
for (int i = 0; i < myGNSS.minfo.extensionNo; i++)
{
Serial.print(" ");
Serial.println(myGNSS.minfo.extension[i]);
}
Serial.println();
Serial.println(F("Done!"));
}
void loop()
{
}
bool SFE_UBLOX_GPS_ADD::getModuleInfo(uint16_t maxWait)
{
myGNSS.minfo.hwVersion[0] = 0;
myGNSS.minfo.swVersion[0] = 0;
for (int i = 0; i < 10; i++)
myGNSS.minfo.extension[i][0] = 0;
myGNSS.minfo.extensionNo = 0;
// Let's create our custom packet
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
// If we call it here, after the .begin, the library will attempt to resize the existing 256 byte payload buffer
// by creating a new buffer, copying across the contents of the old buffer, and then delete the old buffer.
// This uses a lot of RAM and causes the code to fail on the ATmega328P. (We are also allocating another 341 bytes for minfo.)
// To keep the code ATmega328P compliant - don't call setPacketCfgPayloadSize here. Call it before .begin instead.
//myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
// The next line creates and initialises the packet information which wraps around the payload
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
// The structure of ubxPacket is:
// uint8_t cls : The message Class
// uint8_t id : The message ID
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
// uint8_t *payload : The payload
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
// uint8_t checksumB
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
// sendCommand will return:
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
// the module information can be read using the UBX-MON-VER message. So let's load our
// custom packet with the correct information so we can read (poll / get) the module information.
customCfg.cls = UBX_CLASS_MON; // This is the message Class
customCfg.id = UBX_MON_VER; // This is the message ID
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
// Now let's send the command. The module info is returned in customPayload
if (sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED)
return (false); //If command send fails then bail
// Now let's extract the module info from customPayload
uint16_t position = 0;
for (int i = 0; i < 30; i++)
{
minfo.swVersion[i] = customPayload[position];
position++;
}
for (int i = 0; i < 10; i++)
{
minfo.hwVersion[i] = customPayload[position];
position++;
}
while (customCfg.len >= position + 30)
{
for (int i = 0; i < 30; i++)
{
minfo.extension[minfo.extensionNo][i] = customPayload[position];
position++;
}
minfo.extensionNo++;
if (minfo.extensionNo > 9)
break;
}
return (true); //Success!
}

View file

@ -0,0 +1,88 @@
/*
Powering off a ublox GNSS module
By: bjorn
unsurv.org
Date: July 20th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows you how to turn off the ublox module to lower the power consumption.
There are two functions: one just specifies a duration in milliseconds the other also specifies a pin on the GNSS device to wake it up with.
By driving a voltage from LOW to HIGH or HIGH to LOW on the chosen module pin you wake the device back up.
Note: Doing so on the INT0 pin when using the regular powerOff(durationInMs) function will wake the device anyway. (tested on SAM-M8Q)
Note: While powered off, you should not query the device for data or it might wake up. This can be used to wake the device but is not recommended.
Works best when also putting your microcontroller to sleep.
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 GNSS and a BlackBoard.
To force the device to wake up you need to connect to a pin (for example INT0) seperately on the module.
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// define a digital pin capable of driving HIGH and LOW
#define WAKEUP_PIN 5
// Possible GNSS interrupt pins for powerOffWithInterrupt are:
// VAL_RXM_PMREQ_WAKEUPSOURCE_UARTRX = uartrx
// VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0 = extint0 (default)
// VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT1 = extint1
// VAL_RXM_PMREQ_WAKEUPSOURCE_SPICS = spics
// These values can be or'd (|) together to enable interrupts on multiple pins
void wakeUp() {
Serial.print("-- waking up module via pin " + String(WAKEUP_PIN));
Serial.println(" on your microcontroller --");
digitalWrite(WAKEUP_PIN, LOW);
delay(1000);
digitalWrite(WAKEUP_PIN, HIGH);
delay(1000);
digitalWrite(WAKEUP_PIN, LOW);
}
void setup() {
pinMode(WAKEUP_PIN, OUTPUT);
digitalWrite(WAKEUP_PIN, LOW);
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
// Powering off for 20s, you should see the power consumption drop.
Serial.println("-- Powering off module for 20s --");
myGNSS.powerOff(20000);
//myGNSS.powerOffWithInterrupt(20000, VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0);
delay(10000);
// After 10 seconds wake the device via the specified pin on your microcontroller and module.
wakeUp();
}
void loop() {
//Do nothing
}

View file

@ -0,0 +1,120 @@
/*
Time Pulse Parameters - Bullet Time (https://en.wikipedia.org/wiki/Bullet_time)
By: Paul Clark (PaulZC)
Date: January 13th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
pin to produce a pulse once per second but with an adjustable delay. You could use this to
trigger multiple cameras and replicate the "bullet time" effect.
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
accurate timelapse camera shutter signal? This is the product for you!
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Create storage for the time pulse parameters
UBX_CFG_TP5_data_t timePulseParameters;
// Get the time pulse parameters
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("getTimePulseParameters failed! Freezing..."));
while (1) ; // Do nothing more
}
// Print the CFG TP5 version
Serial.print(F("UBX_CFG_TP5 version: "));
Serial.println(timePulseParameters.version);
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
// We can configure the time pulse pin to produce a defined frequency or period
// Here is how to set the period:
// Let's say that we want our pulse-per-second to be as accurate as possible. So, let's tell the module
// to generate no signal while it is _locking_ to GNSS time. We want the signal to start only when the module is
// _locked_ to GNSS time.
timePulseParameters.freqPeriod = 0; // Set the frequency/period to zero
timePulseParameters.pulseLenRatio = 0; // Set the pulse ratio to zero
// When the module is _locked_ to GNSS time, make it generate a 0.1 second pulse once per second
timePulseParameters.freqPeriodLock = 1000000; // Set the period to 1,000,000 us
timePulseParameters.pulseLenRatioLock = 100000; // Set the pulse length to 0.1s (100,000 us)
timePulseParameters.flags.bits.polarity = 1; // Set the polarity to "1" (high for 0.1s, low for 0.9s, rising edge at top of second)
// We can use userConfigDelay to delay the pulse for each camera. The delay needs to be negative for this example.
// We can delay the pulse by +/- 2^31 nanoseconds (+/- 2.147 seconds)
//timePulseParameters.userConfigDelay = 0; // Camera 1: delay the pulse by 0ns
//timePulseParameters.userConfigDelay = -100000000; // Camera 2: delay the pulse by 0.1s (100,000,000 ns)
//timePulseParameters.userConfigDelay = -200000000; // Camera 3: delay the pulse by 0.2s (200,000,000 ns)
timePulseParameters.userConfigDelay = -300000000; // Camera 4: delay the pulse by 0.3s (300,000,000 ns)
//timePulseParameters.userConfigDelay = -400000000; // Camera 5: delay the pulse by 0.4s (400,000,000 ns)
//timePulseParameters.userConfigDelay = -500000000; // Camera 6: delay the pulse by 0.5s (500,000,000 ns)
//timePulseParameters.userConfigDelay = -600000000; // Camera 7: delay the pulse by 0.6s (600,000,000 ns)
//timePulseParameters.userConfigDelay = -700000000; // Camera 8: delay the pulse by 0.7s (700,000,000 ns)
//timePulseParameters.userConfigDelay = -800000000; // Camera 9: delay the pulse by 0.8s (800,000,000 ns)
//timePulseParameters.userConfigDelay = -900000000; // Camera 10: delay the pulse by 0.9s (900,000,000 ns)
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
timePulseParameters.flags.bits.isFreq = 0; // Tell the module that we want to set the period (not the frequency)
timePulseParameters.flags.bits.isLength = 1; // Tell the module that pulseLenRatio is a length (in us) - not a duty cycle
// Now set the time pulse parameters
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("setTimePulseParameters failed!"));
}
else
{
Serial.println(F("Success!"));
}
// Finally, save the time pulse parameters in battery-backed memory so the pulse will automatically restart at power on
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); // Save the configuration
}
void loop()
{
// Nothing to do here
}

View file

@ -0,0 +1,101 @@
/*
Time Pulse Parameters - Frequency
By: Paul Clark (PaulZC)
Date: January 13th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
pin to produce a 1kHz squarewave
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
accurate frequency or clock source for your latest project? This is the product for you!
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Create storage for the time pulse parameters
UBX_CFG_TP5_data_t timePulseParameters;
// Get the time pulse parameters
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("getTimePulseParameters failed! Freezing..."));
while (1) ; // Do nothing more
}
// Print the CFG TP5 version
Serial.print(F("UBX_CFG_TP5 version: "));
Serial.println(timePulseParameters.version);
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
// We can configure the time pulse pin to produce a defined frequency or period
// Here is how to set the frequency:
// While the module is _locking_ to GNSS time, make it generate 2kHz
timePulseParameters.freqPeriod = 2000; // Set the frequency/period to 2000Hz
timePulseParameters.pulseLenRatio = 0x55555555; // Set the pulse ratio to 1/3 * 2^32 to produce 33:67 mark:space
// When the module is _locked_ to GNSS time, make it generate 1kHz
timePulseParameters.freqPeriodLock = 1000; // Set the frequency/period to 1000Hz
timePulseParameters.pulseLenRatioLock = 0x80000000; // Set the pulse ratio to 1/2 * 2^32 to produce 50:50 mark:space
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
timePulseParameters.flags.bits.isFreq = 1; // Tell the module that we want to set the frequency (not the period)
timePulseParameters.flags.bits.isLength = 0; // Tell the module that pulseLenRatio is a ratio / duty cycle (* 2^-32) - not a length (in us)
timePulseParameters.flags.bits.polarity = 1; // Tell the module that we want the rising edge at the top of second. (Set to 0 for falling edge.)
// Now set the time pulse parameters
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("setTimePulseParameters failed!"));
}
else
{
Serial.println(F("Success!"));
}
}
void loop()
{
// Nothing to do here
}

View file

@ -0,0 +1,108 @@
/*
Time Pulse Parameters - Period
By: Paul Clark (PaulZC)
Date: January 13th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to change the time pulse parameters and configure the TIMEPULSE (PPS)
pin to produce a 1 second pulse every 30 seconds. What's really cool is that if you run this
example on two GNSS boards, the pulses are precisely synchronised!
The SparkFun GPS-RTK-SMA Breakout - ZED-F9P (Qwiic) (https://www.sparkfun.com/products/16481)
has solder pads which will let you connect an SMA connector to the TIMEPULSE signal. Need an
accurate timelapse camera shutter signal? This is the product for you!
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Create storage for the time pulse parameters
UBX_CFG_TP5_data_t timePulseParameters;
// Get the time pulse parameters
if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("getTimePulseParameters failed! Freezing..."));
while (1) ; // Do nothing more
}
// Print the CFG TP5 version
Serial.print(F("UBX_CFG_TP5 version: "));
Serial.println(timePulseParameters.version);
timePulseParameters.tpIdx = 0; // Select the TIMEPULSE pin
//timePulseParameters.tpIdx = 1; // Or we could select the TIMEPULSE2 pin instead, if the module has one
// We can configure the time pulse pin to produce a defined frequency or period
// Here is how to set the period:
// Let's say that we want our 1 pulse every 30 seconds to be as accurate as possible. So, let's tell the module
// to generate no signal while it is _locking_ to GNSS time. We want the signal to start only when the module is
// _locked_ to GNSS time.
timePulseParameters.freqPeriod = 0; // Set the frequency/period to zero
timePulseParameters.pulseLenRatio = 0; // Set the pulse ratio to zero
// When the module is _locked_ to GNSS time, make it generate a 1 second pulse every 30 seconds
// (Although the period can be a maximum of 2^32 microseconds (over one hour), the upper limit appears to be around 33 seconds)
timePulseParameters.freqPeriodLock = 30000000; // Set the period to 30,000,000 us
timePulseParameters.pulseLenRatioLock = 1000000; // Set the pulse length to 1,000,000 us
timePulseParameters.flags.bits.active = 1; // Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.)
timePulseParameters.flags.bits.lockedOtherSet = 1; // Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time
timePulseParameters.flags.bits.isFreq = 0; // Tell the module that we want to set the period (not the frequency)
timePulseParameters.flags.bits.isLength = 1; // Tell the module that pulseLenRatio is a length (in us) - not a duty cycle
timePulseParameters.flags.bits.polarity = 1; // Tell the module that we want the rising edge at the top of second. (Set to 0 for falling edge.)
// Now set the time pulse parameters
if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
{
Serial.println(F("setTimePulseParameters failed!"));
}
else
{
Serial.println(F("Success!"));
}
// Finally, save the time pulse parameters in battery-backed memory so the pulse will automatically restart at power on
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); // Save the configuration
}
void loop()
{
// Nothing to do here
}

View file

@ -0,0 +1,117 @@
/*
Getting Unix Epoch Time and micros using u-blox commands
By: UT2UH
Date: March 31th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to query a u-blox module for the current time and date as Unix Epoch uint32_t type to avoid time.h dependency.
We also turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic dramatically.
Note: this example works best on modules like the ZED_F9P. Modules like the ZOE_M8Q do not support confirmedTime.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Uncomment the next line if you need to completely reset your module
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
Serial.println(F("Compare Unix Epoch given with reference one from https://www.epochconverter.com/"));
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
// getUnixEpoch marks the PVT data as stale so you will get Unix time and PVT time on alternate seconds
uint32_t us; //microseconds returned by getUnixEpoch()
uint32_t epoch = myGNSS.getUnixEpoch();
Serial.print(F("Unix Epoch rounded: "));
Serial.print(epoch, DEC);
epoch = myGNSS.getUnixEpoch(us);
Serial.print(F(" Exact Unix Epoch: "));
Serial.print(epoch, DEC);
Serial.print(F(" micros: "));
Serial.println(us, DEC);
Serial.print(myGNSS.getYear());
Serial.print(F("-"));
Serial.print(myGNSS.getMonth());
Serial.print(F("-"));
Serial.print(myGNSS.getDay());
Serial.print(F(" "));
Serial.print(myGNSS.getHour());
Serial.print(F(":"));
Serial.print(myGNSS.getMinute());
Serial.print(F(":"));
Serial.print(myGNSS.getSecond());
Serial.print(F(" Time is "));
if (myGNSS.getTimeFullyResolved() == false)
{
Serial.print(F("not fully resolved but "));
} else {
Serial.print(F("fully resolved and "));
}
if (myGNSS.getTimeValid() == false)
{
Serial.print(F("not "));
}
Serial.print(F("valid "));
if (myGNSS.getConfirmedTime() == false)
{
Serial.print(F("but not "));
} else {
Serial.print(F("and "));
}
Serial.print(F("confirmed"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.println(SIV);
}
}

View file

@ -0,0 +1,120 @@
/*
Demonstrate get/setMeasurementRate and get/setNavigationRate
By: Paul Clark
SparkFun Electronics
Date: March 30th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to slow down the measurement and navigation rates.
This should run on any GNSS module but has only been tested on the ZED_F9P and ZOE_M8Q.
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
unsigned long lastTime = 0; //Simple local timer. Used to calc the message interval.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
// Uncomment the next line if you need to completely reset your module
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
// Begin by printing the current measurement rate and navigation rate
uint16_t rate = myGNSS.getMeasurementRate(); //Get the measurement rate of this module
Serial.print("Current measurement interval (ms): ");
Serial.println(rate);
rate = myGNSS.getNavigationRate(); //Get the navigation rate of this module
Serial.print("Current navigation ratio (cycles): ");
Serial.println(rate);
// The measurement rate is the elapsed time between GNSS measurements, which defines the rate
// e.g. 100 ms => 10 Hz, 1000 ms => 1 Hz, 10000 ms => 0.1 Hz.
// Let's set the measurement rate (interval) to 5 seconds = 5000 milliseconds
if (myGNSS.setMeasurementRate(5000) == false)
{
Serial.println(F("Could not set the measurement rate. Freezing."));
while (1);
}
// setMeasurementRate will set i2cPollingWait to a quarter of the interval
// Let's override that so we can poll the module more frequently and avoid timeouts
myGNSS.setI2CpollingWait(25); // Set i2cPollingWait to 25ms
// The navigation rate is the ratio between the number of measurements and the number of navigation solutions
// e.g. 5 means five measurements for every navigation solution. Maximum value is 127
// Let's set the navigation rate (ratio) to 12 to produce a solution every minute
if (myGNSS.setNavigationRate(12) == false)
{
Serial.println(F("Could not set the navigation rate. Freezing."));
while (1);
}
// Read and print the updated measurement rate and navigation rate
rate = myGNSS.getMeasurementRate(); //Get the measurement rate of this module
Serial.print("New measurement interval (ms): ");
Serial.println(rate);
rate = myGNSS.getNavigationRate(); //Get the navigation rate of this module
Serial.print("New navigation ratio (cycles): ");
Serial.println(rate);
lastTime = millis();
}
void loop()
{
// i2cPollingWait will prevent us from thrashing the I2C bus
if (myGNSS.getPVT()) //Check for new Position, Velocity, Time data. getPVT returns true if new data is available.
{
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
//Calculate the interval since the last message
Serial.print(F(" Interval: "));
Serial.print(((float)(millis() - lastTime)) / 1000.0, 2);
Serial.print(F("s"));
Serial.println();
lastTime = millis(); //Update lastTime
}
}

View file

@ -0,0 +1,91 @@
/*
Demonstrating how to use "end"
By: Paul Clark
SparkFun Electronics
Date: April 1st, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to use the end function.
End will stop all automatic message processing and free (nearly) all used RAM.
The file buffer is deleted (if it exists).
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
myGNSS.end(); // Call end now just because we can - it won't do much as we haven't used any automatic messages
}
void loop()
{
// Allocate 128 bytes for file storage - this checks that issue #20 has been resolved
// Allocating only 128 bytes will let this code run on the ATmega328P
// If your processor has plenty of RAM, you can increase this to something useful like 16KB
myGNSS.setFileBufferSize(128);
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected. Freezing."));
while (1);
}
Serial.print(F("The file buffer size is: "));
Serial.println(myGNSS.getFileBufferSize());
// Request Position, Velocity, Time
// RAM will be allocated for PVT message processing
// getPVT will return true is fresh PVT data was received and processed
if (myGNSS.getPVT())
{
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
}
// Calling end will free the RAM allocated for file storage and PVT processing
// Calling end is optional. You can comment the next line if you want to.
myGNSS.end();
}

View file

@ -0,0 +1,106 @@
/*
Configuring the GNSS to produce multiple messages at different rates
By: Paul Clark
SparkFun Electronics
Date: April 1st, 2021
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 GNSS to output multiple messages at different rates:
PVT is output every second;
POSECEF is output every five seconds;
VELNED is output every ten seconds.
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setMeasurementRate(1000); //Produce a measurement every 1000ms
myGNSS.setNavigationRate(1); //Produce a navigation solution every measurement
myGNSS.setAutoPVTrate(1); //Tell the GNSS to send the PVT solution every measurement
myGNSS.setAutoNAVPOSECEFrate(5); //Tell the GNSS to send each POSECEF solution every 5th measurement
myGNSS.setAutoNAVVELNEDrate(10); //Tell the GNSS to send each VELNED solution every 10th measurement
//myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
}
void loop()
{
// Calling getPVT returns true if there actually is a fresh navigation solution available.
if (myGNSS.getPVT())
{
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
}
// Calling getNAVPOSECEF returns true if there actually is a fresh position solution available.
if (myGNSS.getNAVPOSECEF())
{
Serial.print(F("ecefX: "));
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefX / 100.0, 2); // convert ecefX to m
Serial.print(F(" ecefY: "));
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefY / 100.0, 2); // convert ecefY to m
Serial.print(F(" ecefZ: "));
Serial.print((float)myGNSS.packetUBXNAVPOSECEF->data.ecefZ / 100.0, 2); // convert ecefY to m
Serial.println(F(" (m)"));
myGNSS.flushNAVPOSECEF(); //Mark all the data as read/stale so we get fresh data next time
}
// Calling getNAVVELNED returns true if there actually is fresh velocity data available.
if (myGNSS.getNAVVELNED())
{
Serial.print(F("velN: "));
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velN / 100.0, 2); // convert velN to m/s
Serial.print(F(" velE: "));
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velE / 100.0, 2); // convert velE to m/s
Serial.print(F(" velD: "));
Serial.print((float)myGNSS.packetUBXNAVVELNED->data.velD / 100.0, 2); // convert velD to m/s
Serial.println(F(" (m/s)"));
myGNSS.flushNAVVELNED(); //Mark all the data as read/stale so we get fresh data next time
}
}

View file

@ -0,0 +1,151 @@
/*
Getting leap second event info as SNTP Leap Indicator, time to a leap second event and the number of leap seconds since GPS epoch
By: UT2UH
Date: April 14th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to query a u-blox module for the leap second event info to cast to SNTP Leap Indicator enumeration.
We also turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic dramatically.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
typedef enum {
LI_NO_WARNING, //Time leaping not scheduled
LI_LAST_MINUTE_61_SEC, //Last minute has 61 seconds
LI_LAST_MINUTE_59_SEC, //Last minute has 59 seconds
LI_ALARM_CONDITION //The NTP server's clock not synchronized
} ntp_LI_e;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Uncomment the next line if you need to completely reset your module
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
Serial.println(F("Compare Unix Epoch given with reference one from https://www.epochconverter.com/"));
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
// getUnixEpoch marks the PVT data as stale so you will get Unix time and PVT time on alternate seconds
uint32_t us; //microseconds returned by getUnixEpoch()
uint32_t epoch = myGNSS.getUnixEpoch();
Serial.print(F("Unix Epoch rounded: "));
Serial.print(epoch, DEC);
epoch = myGNSS.getUnixEpoch(us);
Serial.print(F(" Exact Unix Epoch: "));
Serial.print(epoch, DEC);
Serial.print(F(" micros: "));
Serial.println(us, DEC);
int32_t timeToLeapSecEvent;
ntp_LI_e leapIndicator = (ntp_LI_e)myGNSS.getLeapIndicator(timeToLeapSecEvent);
Serial.print(F("NTP LI: "));
Serial.print(leapIndicator, DEC);
switch (leapIndicator){
case LI_NO_WARNING:
Serial.print(F(" - No event scheduled"));
break;
case LI_LAST_MINUTE_61_SEC:
Serial.print(F(" - last minute will end at 23:60"));
break;
case LI_LAST_MINUTE_59_SEC:
Serial.print(F(" - last minute will end at 23:58"));
break;
case LI_ALARM_CONDITION:
default:
Serial.print(F(" - Unknown (clock not synchronized)"));
break;
}
if (timeToLeapSecEvent < 0)
{
Serial.print(F(". Time since the last leap second event: "));
Serial.println(timeToLeapSecEvent * -1, DEC);
}
else
{
Serial.print(F(". Time to the next leap second event: "));
Serial.println(timeToLeapSecEvent, DEC);
}
sfe_ublox_ls_src_e leapSecSource;
Serial.print(F("Leap seconds since GPS Epoch (Jan 6th, 1980): "));
Serial.print(myGNSS.getCurrentLeapSeconds(leapSecSource), DEC);
switch (leapSecSource){
case SFE_UBLOX_LS_SRC_DEFAULT:
Serial.print(F(" - hardcoded"));
break;
case SFE_UBLOX_LS_SRC_GLONASS:
Serial.print(F(" - derived from GPS and GLONASS time difference"));
break;
case SFE_UBLOX_LS_SRC_GPS:
Serial.print(F(" - according to GPS"));
break;
case SFE_UBLOX_LS_SRC_SBAS:
Serial.print(F(" - according to SBAS"));
break;
case SFE_UBLOX_LS_SRC_BEIDOU:
Serial.print(F(" - according to BeiDou"));
break;
case SFE_UBLOX_LS_SRC_GALILEO:
Serial.print(F(" - according to Galileo"));
break;
case SFE_UBLOX_LS_SRC_AIDED:
Serial.print(F(" - last minute will end at 23:58"));
break;
case SFE_UBLOX_LS_SRC_CONFIGURED:
Serial.print(F(" - as configured)"));
break;
case SFE_UBLOX_LS_SRC_UNKNOWN:
default:
Serial.print(F(" - source unknown"));
break;
}
Serial.println();
}
Serial.println();
}

View file

@ -0,0 +1,144 @@
/*
Get the jamming state and indication
By: Paul Clark
SparkFun Electronics
Date: March 2nd, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to enable the jamming / interference monitor and read the
jamming state and information.
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 GNSS and a RedBoard
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 <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;
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Enable the jamming / interference monitor
UBX_CFG_ITFM_data_t jammingConfig; // Create storage for the jamming configuration
if (myGNSS.getJammingConfiguration(&jammingConfig)) // Read the jamming configuration
{
Serial.print(F("The jamming / interference monitor is "));
if (jammingConfig.config.bits.enable == 0) // Check if the monitor is already enabled
Serial.print(F("not "));
Serial.println(F("enabled"));
if (jammingConfig.config.bits.enable == 0) // Check if the monitor is already enabled
{
Serial.print(F("Enabling the jamming / interference monitor: "));
(jammingConfig.config.bits.enable = 1); // Enable the monitor
if (myGNSS.setJammingConfiguration(&jammingConfig)) // Set the jamming configuration
Serial.println(F("success"));
else
Serial.println(F("failed!"));
}
}
}
void loop()
{
// Create storage to hold the hardware status
// See the definition of UBX_MON_HW_data_t in u-blox_structs.h for more details
UBX_MON_HW_data_t hwStatus;
if (myGNSS.getHWstatus(&hwStatus)) // Read the hardware status
{
Serial.println(F("Hardware status (UBX_MON_HW):"));
Serial.print(F("Jamming state: "));
Serial.print(hwStatus.flags.bits.jammingState);
if (hwStatus.flags.bits.jammingState == 0)
Serial.println(F(" = unknown / disabled"));
else if (hwStatus.flags.bits.jammingState == 1)
Serial.println(F(" = ok"));
else if (hwStatus.flags.bits.jammingState == 2)
Serial.println(F(" = warning"));
else // if (hwStatus.flags.bits.jammingState == 3)
Serial.println(F(" = critical!"));
Serial.print(F("Noise level: "));
Serial.println(hwStatus.noisePerMS);
Serial.print(F("AGC monitor: "));
Serial.println(hwStatus.agcCnt);
Serial.print(F("CW jamming indicator: "));
Serial.println(hwStatus.jamInd);
Serial.println();
}
// Create storage to hold the RF information from a ZED-F9
// See the definition of UBX_MON_RF_data_t in u-blox_structs.h for more details
UBX_MON_RF_data_t rfInformation;
// Read the RF information from the ZED-F9n. Allow 2 seconds for the data to be returned. Will time out on M8 modules
if (myGNSS.getRFinformation(&rfInformation, 2000))
{
Serial.print(F("The UBX_MON_RF message contains "));
Serial.print(rfInformation.header.nBlocks); // Print how many information blocks were returned. Should be 0, 1 or 2
Serial.println(F(" information blocks"));
for (uint8_t block = 0; block < rfInformation.header.nBlocks; block++)
{
Serial.print(F("Block ID: "));
Serial.print(rfInformation.blocks[block].blockId);
if (rfInformation.blocks[block].blockId == 0)
Serial.println(F(" = L1"));
else // if (rfInformation.blocks[block].blockId == 1)
Serial.println(F(" = L2 / L5"));
Serial.print(F("Jamming state: "));
Serial.print(rfInformation.blocks[block].flags.bits.jammingState);
if (rfInformation.blocks[block].flags.bits.jammingState == 0)
Serial.println(F(" = unknown / disabled"));
else if (rfInformation.blocks[block].flags.bits.jammingState == 1)
Serial.println(F(" = ok"));
else if (rfInformation.blocks[block].flags.bits.jammingState == 2)
Serial.println(F(" = warning"));
else // if (rfInformation.blocks[block].flags.bits.jammingState == 3)
Serial.println(F(" = critical!"));
Serial.print(F("Noise level: "));
Serial.println(rfInformation.blocks[block].noisePerMS);
Serial.print(F("AGC monitor: "));
Serial.println(rfInformation.blocks[block].agcCnt);
Serial.print(F("CW jamming indicator: "));
Serial.println(rfInformation.blocks[block].jamInd);
}
Serial.println();
}
}

View file

@ -0,0 +1,90 @@
/*
Read NMEA sentences over I2C using u-blox module SAM-M8Q, NEO-M8P, etc
By: Nathan Seidle
SparkFun Electronics
Date: August 22nd, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example reads the NMEA characters over I2C and pipes them to MicroNMEA
This example will output your current long/lat and satellites in view
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
For more MicroNMEA info see https://github.com/stevemarple/MicroNMEA
Hardware Connections:
Plug a Qwiic cable into the GNSS 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
Go outside! Wait ~25 seconds and you should see your lat/long
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#include <MicroNMEA.h> //http://librarymanager/All#MicroNMEA
char nmeaBuffer[100];
MicroNMEA nmea(nmeaBuffer, sizeof(nmeaBuffer));
void setup()
{
Serial.begin(115200);
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_ALL); // Make sure the library is passing all NMEA messages to processNMEA
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_GGA); // Or, we can be kind to MicroNMEA and _only_ pass the GGA messages to it
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
if(nmea.isValid() == true)
{
long latitude_mdeg = nmea.getLatitude();
long longitude_mdeg = nmea.getLongitude();
Serial.print("Latitude (deg): ");
Serial.println(latitude_mdeg / 1000000., 6);
Serial.print("Longitude (deg): ");
Serial.println(longitude_mdeg / 1000000., 6);
nmea.clear(); // Clear the MicroNMEA storage to make sure we are getting fresh data
}
else
{
Serial.println("Waiting for fresh data");
}
delay(250); //Don't pound too hard on the I2C bus
}
//This function gets called from the SparkFun u-blox Arduino Library
//As each NMEA character comes in you can specify what to do with it
//Useful for passing to other libraries like tinyGPS, MicroNMEA, or even
//a buffer, radio, etc.
void SFE_UBLOX_GNSS::processNMEA(char incoming)
{
//Take the incoming char from the u-blox I2C port and pass it on to the MicroNMEA lib
//for sentence cracking
nmea.process(incoming);
}

View file

@ -0,0 +1,128 @@
/*
NEO-D9S L-Band receiver example
By: SparkFun Electronics / Paul Clark
Date: March 7th, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to display the NEO-D9S's received signal imbalance and magnitude, plus a summary of any received PMP data.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
NEO-D9S Correction Data Receiver: https://www.sparkfun.com/products/19390
Hardware Connections:
Use a Qwiic cable to connect the NEO-D9S L-Band corection data receiver to your board
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myLBand; // NEO-D9S
const uint32_t myLBandFreq = 1556290000; // Uncomment this line to use the US SPARTN 1.8 service
//const uint32_t myLBandFreq = 1545260000; // Uncomment this line to use the EU SPARTN 1.8 service
#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printRXMPMP will be called when new PMP data arrives
// See u-blox_structs.h for the full definition of UBX_RXM_PMP_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setRXMPMPcallbackPtr
// / _____ This _must_ be UBX_RXM_PMP_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printRXMPMP(UBX_RXM_PMP_data_t *pmpData)
{
Serial.println(F("New PMP data received:"));
Serial.print(F("PMP message version: "));
Serial.println(pmpData->version);
Serial.print(F("numBytesUserData : "));
Serial.println(pmpData->numBytesUserData);
Serial.print(F("serviceIdentifier: 0x"));
Serial.println(pmpData->serviceIdentifier, HEX);
Serial.print(F("uniqueWordBitErrors: "));
Serial.println(pmpData->uniqueWordBitErrors);
Serial.print(F("fecBits: "));
Serial.println(pmpData->fecBits);
Serial.print(F("ebno (dB): "));
Serial.println((double)pmpData->ebno / 8, 3); //Convert ebno to dB
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
Serial.println(F("NEO-D9S Example"));
Wire.begin(); //Start I2C
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the NEO-D9S L-Band receiver
//myLBand.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
while (myLBand.begin(Wire, 0x43) == false) //Connect to the u-blox NEO-D9S using Wire port. The D9S default I2C address is 0x43 (not 0x42)
{
Serial.println(F("u-blox NEO-D9S not detected at default I2C address. Please check wiring."));
delay(2000);
}
Serial.println(F("u-blox NEO-D9S connected"));
uint8_t ok = myLBand.setVal32(UBLOX_CFG_PMP_CENTER_FREQUENCY, myLBandFreq); // Default 1539812500 Hz
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SEARCH_WINDOW, 2200); // Default 2200 Hz
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_SERVICE_ID, 0); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SERVICE_ID, 21845); // Default 50821
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DATA_RATE, 2400); // Default 2400 bps
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_DESCRAMBLER, 1); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DESCRAMBLER_INIT, 26969); // Default 23560
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_PRESCRAMBLING, 0); // Default 0
if (ok) ok = myLBand.setVal64(UBLOX_CFG_PMP_UNIQUE_WORD, 16238547128276412563ull);
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on the I2C port
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 1); // Output UBX-RXM-PMP on UART1
if (ok) ok = myLBand.setVal8(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
if (ok) ok = myLBand.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // match baudrate with ZED default
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // match baudrate with ZED default
Serial.print(F("L-Band: configuration "));
Serial.println(OK(ok));
myLBand.softwareResetGNSSOnly(); // Do a restart
myLBand.setRXMPMPcallbackPtr(&printRXMPMP); // Call printRXMPMP when new PMP data arrives
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myLBand.checkUblox(); // Check for the arrival of new PMP data and process it.
myLBand.checkCallbacks(); // Check if any LBand callbacks are waiting to be processed.
UBX_MON_HW2_data_t hwStatus; // Create storage for the HW2 extended hardware status
if (myLBand.getHW2status(&hwStatus)) // Request the extended hardware status
{
// Print the signal imbalance and magnitude
Serial.print(F("Signal imbalance and magnitude: ofsI: "));
Serial.print(hwStatus.ofsI);
Serial.print(F(" magI: "));
Serial.print(hwStatus.magI);
Serial.print(F(" ofsQ: "));
Serial.print(hwStatus.ofsQ);
Serial.print(F(" magQ: "));
Serial.println(hwStatus.magQ);
}
}

View file

@ -0,0 +1,152 @@
/*
Calculating the Great Circle Distance and Course to a target position
By: Paul Clark
SparkFun Electronics
Date: September 21st, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to query a u-blox module for its latitude/longitude and then
calculate the Great Circle Distance and Course to a target location.
Thanks! distanceBetween and courseTo were taken from Mikal Hart's TinyGPSPlus:
https://github.com/mikalhart/TinyGPSPlus/blob/ca29434514a5c5172bd807af0608df7f296582a2/src/TinyGPS%2B%2B.cpp#L285-L328
Note: Lat/Long are large numbers because they are degrees * 10^-7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
//#include <math.h> //Uncomment if required. May be needed for sqrt, atan2, etc..
double distanceBetween(long lat1_l, long long1_l, long lat2_l, long long2_l)
{
// returns distance in meters between two positions, both specified
// as signed decimal-degrees latitude and longitude. Uses great-circle
// distance computation for hypothetical sphere of radius 6372795 meters.
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
// Courtesy of Maarten Lamers
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
double long1 = (double)long1_l / 10000000.0;
double lat2 = (double)lat2_l / 10000000.0;
double long2 = (double)long2_l / 10000000.0;
double delta = radians(long1-long2);
double sdlong = sin(delta);
double cdlong = cos(delta);
lat1 = radians(lat1);
lat2 = radians(lat2);
double slat1 = sin(lat1);
double clat1 = cos(lat1);
double slat2 = sin(lat2);
double clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = sq(delta);
delta += sq(clat2 * sdlong);
delta = sqrt(delta);
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
return delta * 6372795;
}
double courseTo(long lat1_l, long long1_l, long lat2_l, long long2_l)
{
// returns course in degrees (North=0, West=270) from position 1 to position 2,
// both specified as signed decimal-degrees latitude and longitude.
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
// Courtesy of Maarten Lamers
double lat1 = (double)lat1_l / 10000000.0; // Convert lat and long to degrees
double long1 = (double)long1_l / 10000000.0;
double lat2 = (double)lat2_l / 10000000.0;
double long2 = (double)long2_l / 10000000.0;
double dlon = radians(long2-long1);
lat1 = radians(lat1);
lat2 = radians(lat2);
double a1 = sin(dlon) * cos(lat2);
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
a2 = cos(lat1) * sin(lat2) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
return degrees(a2);
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.println(F(" (degrees * 10^-7)"));
static const long TARGET_LAT = 400909142, TARGET_LON = -1051849833; // SparkFun's location: degrees * 10^-7 (40.091 N, 105.185 W)
double distanceToTarget = distanceBetween(
latitude,
longitude,
TARGET_LAT,
TARGET_LON);
Serial.print(F("Distance to target: "));
Serial.print(distanceToTarget, 2);
Serial.print(F(" (m) "));
double courseToTarget = courseTo(
latitude,
longitude,
TARGET_LAT,
TARGET_LON);
Serial.print(F("Course to target: "));
Serial.print(courseToTarget, 1);
Serial.println(F(" (degrees)"));
}
}

View file

@ -0,0 +1,136 @@
/*
NEO-D9C QZSS-L6 receiver example
By: SparkFun Electronics / Paul Clark
Date: September 23rd, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to display a summary of the NEO-D9C's UBX-RXM-QZSSL6 data.
It also enables UBX-RXM-QZSSL6 message output on both UART1 and UART2 at 38400 baud
so you can feed the corrections directly to (e.g.) a ZED-F9P.
We believe the NEO-D9C's I2C address should be 0x43 (like the NEO-D9S). But, reported by users in Japan,
the initial NEO-D9C's use address 0x42 - which is the same as the ZED-F9P.
If you have one of the initial NEO-D9C's, the address 0x42 should work for you.
If you have a newer or upgraded NEO-D9C, then you may need to change to 0x43. See line 100.
Also, again reported by users in Japan, the initial NEO-D9C's do not support UBX-CFG-PRT.
The library uses UBX-CFG-PRT inside .begin (.isConnected) to check if the module is connected.
This then fails with the initial NEO-D9C's.
The work-around is to set the .begin assumeSuccess parameter to true.
With newer NEO-D9C's this work-around may not be necessary. Again see line 100.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
NEO-D9S L-Band Correction Data Receiver: https://www.sparkfun.com/products/19390
Hardware Connections:
Use a Qwiic cable to connect the NEO-D9C QZSS-L6 corection data receiver to your board
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myQZSS; // NEO-D9C
#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printRXMQZSSL6 will be called when new QZSS-L6 data arrives
// See u-blox_structs.h for the full definition of UBX_RXM_QZSSL6_message_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setRXMQZSSL6messageCallbackPtr
// / _____ This _must_ be UBX_RXM_QZSSL6_message_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printRXMQZSSL6(UBX_RXM_QZSSL6_message_data_t *qzssL6Data)
{
Serial.println(F("New QZSS-L6 data received:"));
Serial.print(F("Message version: "));
Serial.println(qzssL6Data->payload[0]);
Serial.print(F("Satellite Identifier: "));
Serial.println(qzssL6Data->payload[1]);
Serial.print(F("Carrier / Noise: "));
double cno = (0.00390625 * ((double)qzssL6Data->payload[2])) + ((double)qzssL6Data->payload[3]);
Serial.println(cno, 1);
Serial.print(F("Bit Errors Corrected: "));
Serial.println(qzssL6Data->payload[9]);
uint16_t chInfo = (((uint16_t)qzssL6Data->payload[11]) << 8) | qzssL6Data->payload[10];
uint16_t errStatus = ((chInfo >> 12) & 0x3);
Serial.print(F("Receiver Channel: "));
Serial.println((chInfo >> 8) & 0x3);
Serial.print(F("Message Name: L6"));
Serial.println(((chInfo >> 10) & 0x1) == 0 ? F("D") : F("E"));
Serial.print(F("Error Status: "));
if (errStatus == 1)
Serial.println("error-free");
else if (errStatus == 2)
Serial.println("erroneous");
else
Serial.println("unknown");
Serial.print(F("Channel Name: "));
Serial.println(((chInfo >> 14) & 0x3) == 0 ? F("A") : F("B"));
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
Serial.println(F("NEO-D9C Example"));
Wire.begin(); //Start I2C
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the NEO-D9C QZSS-L6 receiver
//myQZSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
// For the initial NEO-D9C's: connect using address 0x42; set the assumeSuccess parameter to true
while (myQZSS.begin(Wire, 0x42, 1100, true) == false)
// For newer NEO-D9C's: use address 0x43; leave assumeSuccess set to false (default)
//while (myQZSS.begin(Wire, 0x43) == false)
{
Serial.println(F("u-blox NEO-D9C not detected at selected I2C address. Please check wiring and I2C address."));
delay(2000);
}
Serial.println(F("u-blox NEO-D9C connected"));
uint8_t ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C, 1); // Output QZSS-L6 message on the I2C port
Serial.print(F("QZSS-L6: I2C configuration "));
Serial.println(OK(ok));
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART1, 1); // Output QZSS-L6 message on UART1
if (ok) ok = myQZSS.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // Match UART1 baudrate with ZED
Serial.print(F("QZSS-L6: UART1 configuration "));
Serial.println(OK(ok));
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
if (ok) ok = myQZSS.setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART2, 1); // Output QZSS-L6 message on UART2
if (ok) ok = myQZSS.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // Match UART2 baudrate with ZED
Serial.print(F("QZSS-L6: UART2 configuration "));
Serial.println(OK(ok));
myQZSS.setRXMQZSSL6messageCallbackPtr(&printRXMQZSSL6); // Call printRXMQZSSL6 when new QZSS-L6 data arrives
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myQZSS.checkUblox(); // Check for the arrival of new QZSS-L6 data and process it.
myQZSS.checkCallbacks(); // Check if any QZSS-L6 callbacks are waiting to be processed.
}

View file

@ -0,0 +1,207 @@
/*
Configure Time & Frequency Sync manager (UBX-CFG-SMGR)
By: Danylo Ulianych
SparkFun Electronics
Date: March 6th, 2024
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example reads / sets UBX-CFG-SMGR configuration and prints UBX-TIM-SMEAS messages.
Works only with Time & Frequency Sync products like LEA-M8F, etc.
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 GNSS 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 <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;
// Callback: printTIMSMEASdata will be called when new TIM SMEA data arrives
// See u-blox_structs.h for the full definition of UBX_TIM_SMEAS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
// / _____ This _must_ be UBX_TIM_SMEAS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printTIMSMEASdata(UBX_TIM_SMEAS_data_t smea)
{
Serial.print("UBX-TIM-SMEAS:");
Serial.printf("\n version: %u", smea.version);
Serial.printf("\n numMeas: %u", smea.numMeas);
Serial.printf("\n iTOW: %lu", smea.iTOW);
for (int i = 0; i < smea.numMeas; i++) {
Serial.printf("\n sourceId %u:", smea.data[i].sourceId);
Serial.printf("\n flags:");
Serial.printf("\n freqValid %u", smea.data[i].flags.bits.freqValid);
Serial.printf("\n phaseValid %u", smea.data[i].flags.bits.phaseValid);
Serial.printf("\n phaseOffsetFrac %d", smea.data[i].phaseOffsetFrac);
Serial.printf("\n phaseUncFrac %u", smea.data[i].phaseUncFrac);
Serial.printf("\n phaseOffset %ld", smea.data[i].phaseOffset);
Serial.printf("\n phaseUnc %lu", smea.data[i].phaseUnc);
Serial.printf("\n freqOffset %ld", smea.data[i].freqOffset);
Serial.printf("\n freqUnc %lu", smea.data[i].freqUnc);
}
}
UBX_CFG_SMGR_data_t convertRawBufToCfgSmgr(const ubxPacket* msg) {
UBX_CFG_SMGR_data_t smgr;
if (msg->len < sizeof(UBX_CFG_SMGR_data_t)) {
Serial.printf("Payload message size (%zu) is too small to be converted to UBX_CFG_SMGR_data_t\n", msg->len);
return smgr;
}
smgr.version = SFE_UBLOX_GNSS::extractByte(msg, 0);
smgr.minGNSSFix = SFE_UBLOX_GNSS::extractByte(msg, 1);
smgr.maxFreqChangeRate = SFE_UBLOX_GNSS::extractInt(msg, 2);
smgr.maxPhaseCorrRate = SFE_UBLOX_GNSS::extractInt(msg, 4);
smgr.freqTolerance = SFE_UBLOX_GNSS::extractInt(msg, 8);
smgr.timeTolerance = SFE_UBLOX_GNSS::extractInt(msg, 10);
smgr.messageCfg.all = SFE_UBLOX_GNSS::extractInt(msg, 12);
smgr.maxSlewRate = SFE_UBLOX_GNSS::extractInt(msg, 14);
smgr.flags.all = SFE_UBLOX_GNSS::extractLong(msg, 16);
return smgr;
}
void printUbxCfgSmgr(const UBX_CFG_SMGR_data_t& smgr) {
Serial.printf("\nUBX-CFG-SMGR:");
Serial.printf("\n version %u (0x%02x)", smgr.version, smgr.version);
Serial.printf("\n minGNSSFix %u (0x%02x)", smgr.minGNSSFix, smgr.minGNSSFix);
Serial.printf("\n maxFreqChangeRate %u (0x%02x)", smgr.maxFreqChangeRate, smgr.maxFreqChangeRate);
Serial.printf("\n maxPhaseCorrRate %u (0x%02x)", smgr.maxPhaseCorrRate, smgr.maxPhaseCorrRate);
Serial.printf("\n freqTolerance %u (0x%02x)", smgr.freqTolerance, smgr.freqTolerance);
Serial.printf("\n timeTolerance %u (0x%02x)", smgr.timeTolerance, smgr.timeTolerance);
Serial.printf("\n messageCfg:");
Serial.printf("\n measInternal: %u", smgr.messageCfg.bits.measInternal);
Serial.printf("\n measGNSS: %u", smgr.messageCfg.bits.measGNSS);
Serial.printf("\n measEXTINT0: %u", smgr.messageCfg.bits.measEXTINT0);
Serial.printf("\n measEXTINT1: %u", smgr.messageCfg.bits.measEXTINT1);
Serial.printf("\n maxSlewRate %u (0x%02x)", smgr.maxSlewRate, smgr.maxSlewRate);
Serial.printf("\n flags:");
Serial.printf("\n disableInternal: %u", smgr.flags.bits.disableInternal);
Serial.printf("\n disableExternal: %u", smgr.flags.bits.disableExternal);
Serial.printf("\n preferenceMode: %u", smgr.flags.bits.preferenceMode);
Serial.printf("\n enableGNSS: %u", smgr.flags.bits.enableGNSS);
Serial.printf("\n enableEXTINT0: %u", smgr.flags.bits.enableEXTINT0);
Serial.printf("\n enableEXTINT1: %u", smgr.flags.bits.enableEXTINT1);
Serial.printf("\n enableHostMeasInt: %u", smgr.flags.bits.enableHostMeasInt);
Serial.printf("\n enableHostMeasExt: %u", smgr.flags.bits.enableHostMeasExt);
Serial.printf("\n useAnyFix: %u", smgr.flags.bits.useAnyFix);
Serial.printf("\n disableMaxSlewRate: %u", smgr.flags.bits.disableMaxSlewRate);
Serial.printf("\n issueFreqWarn: %u", smgr.flags.bits.issueFreqWarn);
Serial.printf("\n issueTimeWarn: %u", smgr.flags.bits.issueTimeWarn);
Serial.printf("\n TPCoherent: %u", smgr.flags.bits.TPCoherent);
Serial.printf("\n disableOffset: %u", smgr.flags.bits.disableOffset);
Serial.println("\n");
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial ready
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); // ignore NMEA messages
// setPacketCfgPayloadSize tells the library how many bytes our customPayload can hold.
// It is more memory-efficient to call setPacketCfgPayloadSize before .begin (to avoid creating a new buffer, copying across
// the contents of the old buffer and then deleting the old buffer). But let's call it here just to prove that we can.
myGNSS.setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes. MAX_PAYLOAD_SIZE defaults to 256. The CFG_RATE payload is only 6 bytes!
// The next line creates and initialises the packet information which wraps around the payload
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
// The structure of ubxPacket is:
// uint8_t cls : The message Class
// uint8_t id : The message ID
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
// uint8_t *payload : The payload
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
// uint8_t checksumB
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
// sendCommand will return:
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
// the navigation rate is configured using the UBX-CFG-RATE message. So let's load our
// custom packet with the correct information so we can read (poll / get) the current settings.
customCfg.cls = UBX_CLASS_CFG; // This is the message Class
customCfg.id = UBX_CFG_SMGR; // This is the message ID
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
// We also need to tell sendCommand how long it should wait for a reply
uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)
// Now let's read the current UBX-CFG-SMGR settings. The results will be loaded into customCfg.
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
{
Serial.println(F("sendCommand (poll / get) failed! Freezing..."));
while (1)
;
}
UBX_CFG_SMGR_data_t cfgSmgrPayload = convertRawBufToCfgSmgr(&customCfg);
printUbxCfgSmgr(cfgSmgrPayload);
cfgSmgrPayload.minGNSSFix = 5; // update the min no. of GNSS fixes to start freq/phase sync
cfgSmgrPayload.flags.bits.useAnyFix = 1; // use any fix
// update the raw payload buffer
memmove(customPayload, &cfgSmgrPayload, sizeof(UBX_CFG_SMGR_data_t));
// Now let's set the updated settings.
if (myGNSS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // We are expecting data and an ACK
{
Serial.println(F("sendCommand set failed! Freezing..."));
while (1)
;
}
Serial.println("UBX-CFG-SMGR successfully updated");
myGNSS.setAutoTIMSMEAcallback(&printTIMSMEASdata);
// Enable info/warns messages
// myGNSS.setVal8(UBLOX_CFG_INFMSG_UBX_I2C, 1);
}
void loop()
{
myGNSS.checkUblox(); //See if new UBX data is available. Process bytes as they come in.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
delay(250); //Don't pound too hard on the I2C bus
}

View file

@ -0,0 +1,86 @@
/*
Reading lat and long via UBX binary commands - no more NMEA parsing!
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for its lat/long/altitude. We also
turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
dramatically.
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
}

View file

@ -0,0 +1,96 @@
/*
Get fix type and RTK fix type if available
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for fix type and RTK fix type.
The fix type is as follows:
0 = no fix
1 = dead reckoning (requires external sensors)
2 = 2D (not quite enough satellites in view)
3 = 3D (the standard fix)
4 = GNSS + dead reckoning (requires external sensors)
5 = Time fix only
Additionally, if we are doing RTK, we can figure out if we have a floating
RTK solution or if we have been able to resolve a fixec solution (better precision).
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//Wire.setClock(400000); //Optional. Increase I2C clock speed to 400kHz.
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
byte RTK = myGNSS.getCarrierSolutionType();
Serial.print(" RTK: ");
Serial.print(RTK);
if (RTK == 0) Serial.print(F(" (No solution)"));
else if (RTK == 1) Serial.print(F(" (High precision floating fix)"));
else if (RTK == 2) Serial.print(F(" (High precision fix)"));
Serial.println();
}
}

View file

@ -0,0 +1,83 @@
/*
Get Speed/Heading and dilution of precision via UBX binary commands - no more NMEA parsing!
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for its lat/long/altitude.
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 1,000,000. We
do this so that we don't have to use floating point numbers.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
long speed = myGNSS.getGroundSpeed();
Serial.print(F(" Speed: "));
Serial.print(speed);
Serial.print(F(" (mm/s)"));
long heading = myGNSS.getHeading();
Serial.print(F(" Heading: "));
Serial.print(heading);
Serial.print(F(" (degrees * 10^-5)"));
int pDOP = myGNSS.getPDOP();
Serial.print(F(" pDOP: "));
Serial.print(pDOP / 100.0, 2); // Convert pDOP scaling from 0.01 to 1
Serial.println();
}
}

View file

@ -0,0 +1,79 @@
/*
Turn on/off various NMEA sentences.
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 turn on/off the NMEA sentences being output
over UART1. We use the I2C interface on the u-blox module for configuration
but you won't see any output from this sketch. You'll need to hook up
a Serial Basic or other USB to Serial device to UART1 on your u-blox module
to see the output.
This example turns off all sentences except for the GPGGA and GPVTG sentences.
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 GNSS and a RedBoard
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
Hookup a Serial Basic (https://www.sparkfun.com/products/15096) to UART1 on the u-blox module. Open a terminal at 57600bps
and see GPGGA and GPVTG sentences.
*/
#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;
unsigned long lastGNSSsend = 0;
void setup()
{
Serial.begin(115200); // Serial debug output over USB visible from Arduino IDE
Serial.println("Example showing how to enable/disable certain NMEA sentences");
Wire.begin();
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//Disable or enable various NMEA sentences over the UART1 interface
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.disableNMEAMessage(UBX_NMEA_RMC, 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);
//Here's the advanced configure method
//Some of the other examples in this library enable the PVT message so let's disable it
myGNSS.configureMessage(UBX_CLASS_NAV, UBX_NAV_PVT, COM_PORT_UART1, 0); //Message Class, ID, and port we want to configure, sendRate of 0 (disable).
myGNSS.setUART1Output(COM_TYPE_NMEA); //Turn off UBX and RTCM sentences on the UART1 interface
myGNSS.setSerialRate(57600); //Set UART1 to 57600bps.
//myGNSS.saveConfiguration(); //Optional: Save these settings to NVM
Serial.println(F("Messages configured. NMEA now being output over the UART1 port on the u-blox module at 57600bps."));
}
void loop()
{
if (millis() - lastGNSSsend > 200)
{
myGNSS.checkUblox(); //See if new data is available, but we don't want to get NMEA here. Go check UART1.
lastGNSSsend = millis();
}
}

View file

@ -0,0 +1,94 @@
/*
Set update rate to 10Hz
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 increase the output of the module from 1Hz to 4Hz.
The max output rate various from model to model. RTFM! But you cannot do harm
to the module.
We also disable NMEA output on the I2C bus and use only UBX. This dramatically
decreases the amount of data that needs to be transmitted.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
unsigned long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
unsigned long startTime = 0; //Used to calc the actual update rate.
unsigned long updateCount = 0; //Used to calc the actual update rate.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
// Increase I2C clock speed to 400kHz to cope with the high navigation rate
// (We normally recommend running the bus at 100kHz)
Wire.setClock(400000);
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setNavigationFrequency(5); //Set output to 5 times a second
uint8_t rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
Serial.print("Current update rate: ");
Serial.println(rate);
startTime = millis();
}
void loop()
{
//Query module every 25 ms. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available. This is defined
//by the update freq.
if (millis() - lastTime > 25)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
updateCount++;
//Calculate the actual update rate based on the sketch start time and the
//number of updates we've received.
Serial.print(F(" Rate: "));
Serial.print( updateCount / ((millis() - startTime) / 1000.0), 2);
Serial.print(F("Hz"));
Serial.println();
}
}

View file

@ -0,0 +1,61 @@
/*
Reading the protocol version of a u-blox module
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for its protocol version.
Various modules have various protocol version. We've seen v18 up to v27. Depending
on the protocol version there are different commands available. This is a handy
way to predict which commands will or won't work.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.print(F("Version: "));
byte versionHigh = myGNSS.getProtocolVersionHigh();
Serial.print(versionHigh);
Serial.print(".");
byte versionLow = myGNSS.getProtocolVersionLow();
Serial.print(versionLow);
}
void loop()
{
//Do nothing
}

View file

@ -0,0 +1,81 @@
/*
Reading the protocol version of a u-blox module
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 query a u-blox module for its protocol version.
Note: this may fail on boards like the UNO (ATmega328P) with modules like the ZED-F9P
because getProtocolVersion returns a lot of data - more than the UNO's serial buffer can hold
Various modules have various protocol version. We've seen v18 up to v27. Depending
on the protocol version there are different commands available. This is a handy
way to predict which commands will or won't work.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <SoftwareSerial.h>
#define mySerial Serial1 // Uncomment this line to connect via Serial1
// - or -
//SoftwareSerial mySerial(10, 11); // Uncomment this line to connect via SoftwareSerial(RX, TX). Connect pin 10 to GNSS TX pin.
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Serial.println("Trying 38400 baud");
mySerial.begin(38400);
if (myGNSS.begin(mySerial))
{
Serial.println("GNSS connected at 38400 baud");
}
else
{
Serial.println("Trying 9600 baud");
mySerial.begin(9600);
if (myGNSS.begin(mySerial))
{
Serial.println("GNSS connected at 9600 baud");
}
else
{
Serial.println("Could not connect to GNSS. Freezing...");
while(1); // Do nothing more
}
}
Serial.print(F("Version: "));
byte versionHigh = myGNSS.getProtocolVersionHigh();
Serial.print(versionHigh);
Serial.print(".");
byte versionLow = myGNSS.getProtocolVersionLow();
Serial.print(versionLow);
}
void loop()
{
//Do nothing
}

View file

@ -0,0 +1,116 @@
/*
Change the I2C address of a u-blox module using I2C
By: Nathan Seidle
SparkFun Electronics
Date: January 3rd, 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 change the I2C address of a u-blox module
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Tracks the passing of 2000ms (2 seconds)
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
byte oldAddress = 0x42; //The default address for u-blox modules is 0x42
byte newAddress = 0x3F; //Address you want to change to. Valid is 0x08 to 0x77.
while (Serial.available()) Serial.read(); //Trash any incoming chars
Serial.print("Press a key to change address to 0x");
Serial.println(newAddress, HEX);
while (Serial.available() == false) ; //Wait for user to send character
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin(Wire, oldAddress) == true) //Connect to the u-blox module using Wire port and the old address
{
Serial.print("GNSS found at address 0x");
Serial.println(oldAddress, HEX);
myGNSS.setI2CAddress(newAddress); //Change I2C address of this device
//Device's I2C address is stored to memory and loaded on each power-on
delay(2000); // Allow time for the change to take
if (myGNSS.begin(Wire, newAddress) == true)
{
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
Serial.print("Address successfully changed to 0x");
Serial.println(newAddress, HEX);
Serial.print("Now load another example sketch using .begin(Wire, 0x");
Serial.print(newAddress, HEX);
Serial.println(") to use this GPS module");
Serial.println("Freezing...");
while (1);
}
}
//Something went wrong, begin looking for the I2C device
Serial.println("Address change probably failed. Beginning an I2C scan.");
Wire.begin();
}
void loop() {
byte address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
// else if (error == 4)
// {
// Serial.print("Unknown error at address 0x");
// if (address < 16)
// Serial.print("0");
// Serial.println(address, HEX);
// }
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}

View file

@ -0,0 +1,77 @@
/*
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P module
By: Nathan Seidle
SparkFun Electronics
Date: September 7th, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example sends the command to enable the four RTCM messages needed for RTK. This
is the first part of a larger tutorial and example to setup an RTK base station.
These commands are only accepted by the NEO-M8P module.
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while(!Serial); //Wait for user to open terminal
Serial.println(F("u-blox RTCM Enable Example"));
Wire.begin();
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
while(Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
Serial.println(F("Press any key to send commands to enable RTCM 3.x"));
while(Serial.available() == 0) ; //Wait for user to press a key
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
bool response = true;
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
if (response == true)
{
Serial.println(F("RTCM messages enabled"));
}
else
{
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
while(1); //Freeze
}
//RTCM is now enabled but we haven't done a 'survey-in'
//See example 4 for the full Base RTK setup
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
delay(250); //Don't pound too hard on the I2C bus
}

View file

@ -0,0 +1,164 @@
/*
Note: compiles OK with v2.0 but is currently untested
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P-2 module
By: Nathan Seidle
SparkFun Electronics
Date: September 7th, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example does all steps to configure and enable a NEO-M8P-2 as a base station:
Begin Survey-In
Once we've achieved 2m accuracy and 300s have passed, survey is complete
Enable four RTCM messages
Begin outputting RTCM bytes
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("u-blox NEO-M8P-2 base station example"));
Wire.begin();
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
while (Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
Serial.println(F("Press any key to send commands to begin Survey-In"));
while (Serial.available() == 0) ; //Wait for user to press a key
bool response;
//Check if Survey is in Progress before initiating one
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (request can take a long time)
if (response == false) // Check if fresh data was received
{
Serial.println(F("Failed to get Survey In status. Freezing..."));
while (1); //Freeze
}
if (myGNSS.getSurveyInActive() == true) // Use the helper function
{
Serial.print(F("Survey already in progress."));
}
else
{
//Start survey
response = myGNSS.enableSurveyMode(300, 2.000); //Enable Survey in, 300 seconds, 2.0m
if (response == false)
{
Serial.println(F("Survey start failed. Freezing..."));
while (1);
}
Serial.println(F("Survey started. This will run until 300s has passed and less than 2m accuracy is achieved."));
}
while(Serial.available()) Serial.read(); //Clear buffer
//Begin waiting for survey to complete
while (myGNSS.getSurveyInValid() == false) // Call the helper function
{
if(Serial.available())
{
byte incoming = Serial.read();
if(incoming == 'x')
{
//Stop survey mode
response = myGNSS.disableSurveyMode(); //Disable survey
Serial.println(F("Survey stopped"));
break;
}
}
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (req can take a long time)
if (response == true) // Check if fresh data was received
{
Serial.print(F("Press x to end survey - "));
Serial.print(F("Time elapsed: "));
Serial.print((String)myGNSS.getSurveyInObservationTime());
Serial.print(F(" Accuracy: "));
Serial.print((String)myGNSS.getSurveyInMeanAccuracy());
Serial.println();
}
else
{
Serial.println(F("SVIN request failed"));
}
delay(1000);
}
Serial.println(F("Survey valid!"));
response = true;
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
if (response == true)
{
Serial.println(F("RTCM messages enabled"));
}
else
{
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
while (1); //Freeze
}
Serial.println(F("Base survey complete! RTCM now broadcasting."));
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
delay(250); //Don't pound too hard on the I2C bus
}
//This function gets called from the SparkFun u-blox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
{
//Let's just pretty-print the HEX values for now
if (myGNSS.rtcmFrameCounter % 16 == 0) Serial.println();
Serial.print(F(" "));
if (incoming < 0x10) Serial.print(F("0"));
Serial.print(incoming, HEX);
}

View file

@ -0,0 +1,168 @@
/*
Note: compiles OK with v2.0 but is currently untested
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P-2 module
By: Nathan Seidle
SparkFun Electronics
Date: September 7th, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example does all steps to configure and enable a NEO-M8P-2 as a base station:
Begin Survey-In
Once we've achieved 2m accuracy and 300s have passed, survey is complete
Enable four RTCM messages
Begin outputting RTCM bytes
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 GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
class MY_SFE_UBLOX_GNSS : public SFE_UBLOX_GNSS
{
//This function gets called from the SparkFun u-blox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
virtual void processRTCM_v(uint8_t incoming)
{
//Let's just pretty-print the HEX values for now
if (rtcmFrameCounter % 16 == 0) Serial.println();
Serial.print(F(" "));
if (incoming < 0x10) Serial.print(F("0"));
Serial.print(incoming, HEX);
}
};
MY_SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("u-blox NEO-M8P-2 base station example"));
Wire.begin();
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
while (Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
Serial.println(F("Press any key to send commands to begin Survey-In"));
while (Serial.available() == 0) ; //Wait for user to press a key
bool response;
//Check if Survey is in Progress before initiating one
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (request can take a long time)
if (response == false) // Check if fresh data was received
{
Serial.println(F("Failed to get Survey In status. Freezing..."));
while (1); //Freeze
}
if (myGNSS.getSurveyInActive() == true) // Use the helper function
{
Serial.print(F("Survey already in progress."));
}
else
{
//Start survey
response = myGNSS.enableSurveyMode(300, 2.000); //Enable Survey in, 300 seconds, 2.0m
if (response == false)
{
Serial.println(F("Survey start failed. Freezing..."));
while (1);
}
Serial.println(F("Survey started. This will run until 300s has passed and less than 2m accuracy is achieved."));
}
while(Serial.available()) Serial.read(); //Clear buffer
//Begin waiting for survey to complete
while (myGNSS.getSurveyInValid() == false) // Call the helper function
{
if(Serial.available())
{
byte incoming = Serial.read();
if(incoming == 'x')
{
//Stop survey mode
response = myGNSS.disableSurveyMode(); //Disable survey
Serial.println(F("Survey stopped"));
break;
}
}
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (req can take a long time)
if (response == true) // Check if fresh data was received
{
Serial.print(F("Press x to end survey - "));
Serial.print(F("Time elapsed: "));
Serial.print((String)myGNSS.getSurveyInObservationTime());
Serial.print(F(" Accuracy: "));
Serial.print((String)myGNSS.getSurveyInMeanAccuracy());
Serial.println();
}
else
{
Serial.println(F("SVIN request failed"));
}
delay(1000);
}
Serial.println(F("Survey valid!"));
response = true;
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
if (response == true)
{
Serial.println(F("RTCM messages enabled"));
}
else
{
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
while (1); //Freeze
}
Serial.println(F("Base survey complete! RTCM now broadcasting."));
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
delay(250); //Don't pound too hard on the I2C bus
}

View file

@ -0,0 +1,198 @@
/*
Note: compiles OK with v2.0 but is currently untested
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P-2 module
By: Nathan Seidle
SparkFun Electronics
Date: September 7th, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example does all steps to configure and enable a NEO-M8P-2 as a base station:
Begin Survey-In
Once we've achieved 2m accuracy and 300s have passed, survey is complete
Enable four RTCM messages
Begin outputting RTCM bytes
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 GNSS and a BlackBoard
Plug a SerLCD onto the Qwiic bus
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Watch the output on the LCD or open the serial monitor at 115200 baud to see the output
*/
#define STAT_LED 13
#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;
#include <SerLCD.h> //Click here to get the library: http://librarymanager/All#SparkFun_SerLCD
SerLCD lcd; // Initialize the library with default I2C address 0x72
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("u-blox GNSS I2C Test"));
Wire.begin();
pinMode(STAT_LED, OUTPUT);
digitalWrite(STAT_LED, LOW);
lcd.begin(Wire); //Set up the LCD for Serial communication at 9600bps
lcd.setBacklight(0x4B0082); //indigo, a kind of dark purplish blue
lcd.clear();
lcd.print(F("LCD Ready"));
myGNSS.begin(Wire);
if (myGNSS.isConnected() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
lcd.setCursor(0, 1);
lcd.print(F("No GNSS detected"));
while (1);
}
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
lcd.setCursor(0, 1);
lcd.print("GNSS Detected");
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
//Check if Survey is in Progress before initiating one
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
bool response;
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (request can take a long time)
if (response == false)
{
Serial.println(F("Failed to get Survey In status"));
while (1); //Freeze
}
if (myGNSS.getSurveyInActive() == true) // Use the helper function
{
Serial.print(F("Survey already in progress."));
lcd.setCursor(0, 2);
lcd.print(F("Survey already going"));
}
else
{
//Start survey
response = myGNSS.enableSurveyMode(300, 2.000); //Enable Survey in, 300 seconds, 2.0m
if (response == false)
{
Serial.println(F("Survey start failed"));
lcd.setCursor(0, 3);
lcd.print(F("Survey start failed"));
while (1);
}
Serial.println(F("Survey started. This will run until 300s has passed and less than 2m accuracy is achieved."));
}
while (Serial.available()) Serial.read(); //Clear buffer
lcd.clear();
lcd.print(F("Survey in progress"));
//Begin waiting for survey to complete
while (myGNSS.getSurveyInValid() == false) // Call the helper function
{
if (Serial.available())
{
byte incoming = Serial.read();
if (incoming == 'x')
{
//Stop survey mode
response = myGNSS.disableSurveyMode(); //Disable survey
Serial.println(F("Survey stopped"));
break;
}
}
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
// You can either read the data from packetUBXNAVSVIN directly
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (req can take a long time)
if (response == true)
{
Serial.print(F("Press x to end survey - "));
Serial.print(F("Time elapsed: "));
Serial.print((String)myGNSS.getSurveyInObservationTime());
lcd.setCursor(0, 1);
lcd.print(F("Elapsed: "));
lcd.print((String)myGNSS.getSurveyInObservationTime());
Serial.print(F(" Accuracy: "));
Serial.print((String)myGNSS.getSurveyInMeanAccuracy());
Serial.println();
lcd.setCursor(0, 2);
lcd.print(F("Accuracy: "));
lcd.print((String)myGNSS.getSurveyInMeanAccuracy());
}
else
{
Serial.println(F("SVIN request failed"));
}
delay(1000);
}
Serial.println(F("Survey valid!"));
response = true;
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
if (response == true)
{
Serial.println(F("RTCM messages enabled"));
}
else
{
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
while (1); //Freeze
}
Serial.println(F("Base survey complete! RTCM now broadcasting."));
lcd.clear();
lcd.print(F("Transmitting RTCM"));
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
//Do anything you want. Call checkUblox() every second. NEO-M8P-2 has TX buffer of 4k bytes.
delay(250); //Don't pound too hard on the I2C bus
}
//This function gets called from the SparkFun u-blox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
{
//Let's just pretty-print the HEX values for now
if (myGNSS.rtcmFrameCounter % 16 == 0) Serial.println();
Serial.print(" ");
if (incoming < 0x10) Serial.print("0");
Serial.print(incoming, HEX);
}

View file

@ -0,0 +1,74 @@
/*
Configure the NEO-M8P-2 as a "moving base"
By: Paul Clark
SparkFun Electronics
Date: March 20th, 2023
License: MIT. See license file for more information.
This example configures the NEO-M8P-2 as a moving base.
It will output RTCM3 1077, 1087, 1230 and 4072.0 messages on UART1.
Connect UART1 TX to UART1 RX on a NEO-M8P rover. Also connect GND to GND.
The next example shows how to display the relative position of the rover.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8P RTK: https://www.sparkfun.com/products/15005
Hardware Connections:
Plug a Qwiic cable into the GNSS 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)
Connect UART1 TX to UART1 RX on a NEO-M8P rover. Also connect GND to GND.
Open the serial monitor at 115200 baud to see the output
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
delay(1000);
Serial.begin(115200);
while(!Serial); //Wait for user to open terminal
Serial.println(F("u-blox NEO-M8P Moving Base Example"));
Wire.begin();
while (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring."));
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setUART1Output(COM_TYPE_RTCM3); // Configure UART1 to output RTCM3 only. Disable NMEA.
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
bool response = true;
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_UART1, 1); //Enable message 1077 on UART1
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_UART1, 1); //Enable message 1087 on UART1
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_UART1, 1); //Enable message 1230 on UART1
response &= myGNSS.enableRTCMmessage(UBX_RTCM_4072_0, COM_PORT_UART1, 1); //Enable message 4072.0 on UART1
response &= myGNSS.disableSurveyMode(); //Essential - we need to set TMODE3 to Disabled to allow 4072.0 to be output
if (response == true)
{
Serial.println(F("RTCM messages enabled"));
}
else
{
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
}
}
void loop()
{
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
delay(250); //Don't pound too hard on the I2C bus
}

View file

@ -0,0 +1,117 @@
/*
Display the relative position of a NEO-M8P-2 rover
By: Paul Clark
SparkFun Electronics
Date: March 20th, 2023
License: MIT. See license file for more information.
This example shows how to query the module for RELPOS information in the NED frame.
It assumes you already have RTCM correction data being fed to the receiver on UART1.
Connect UART1 TX on the base to UART1 RX on the rover. Also connect GND to GND.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-M8P RTK: https://www.sparkfun.com/products/15005
Hardware Connections:
Plug a Qwiic cable into the GNSS and a RedBoard Qwiic or BlackBoard
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Connect UART1 TX on the base to UART1 RX on the rover. Also connect GND to GND.
Open the serial monitor at 115200 baud to see the output
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
delay(1000);
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("u-blox NEO-M8P Rover Example");
Wire.begin();
while (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring."));
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
//myGNSS.factoryDefault(); delay(5000);
// By default, UART1 Protocol In is set to NMEA + UBX + RTCM3. No changes are necessary. But we can manually configure the port if required.
Serial.print(myGNSS.setPortInput(COM_PORT_UART1, COM_TYPE_UBX | COM_TYPE_RTCM3)); //Enable UBX and RTCM3 input on UART1
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save the communications port settings to flash and BBR
}
void loop()
{
// The data from getRELPOSNED (UBX-NAV-RELPOSNED) is returned in UBX_NAV_RELPOSNED_t packetUBXNAVRELPOSNED
// Please see u-blox_structs.h for the full definition of UBX_NAV_RELPOSNED_t
// You can either read the data from packetUBXNAVRELPOSNED directly
// or can use the helper functions: getRelPosN/E/D; getRelPosAccN/E/D
// Note that NEO-M8P RELPOSNED is different to ZED-F9P. It does not contain the relative length and heading.
if (myGNSS.getRELPOSNED() == true)
{
Serial.print("relPosN: ");
Serial.println(myGNSS.getRelPosN(), 4); // Use the helper functions to get the rel. pos. as m
Serial.print("relPosE: ");
Serial.println(myGNSS.getRelPosE(), 4);
Serial.print("relPosD: ");
Serial.println(myGNSS.getRelPosD(), 4);
Serial.print("relPosHPN: ");
Serial.println((float)myGNSS.packetUBXNAVRELPOSNED->data.relPosHPN / 10, 1); //High-precision component. Convert to mm
Serial.print("relPosHPE: ");
Serial.println((float)myGNSS.packetUBXNAVRELPOSNED->data.relPosHPE / 10, 1);
Serial.print("relPosHPD: ");
Serial.println((float)myGNSS.packetUBXNAVRELPOSNED->data.relPosHPD / 10, 1);
Serial.print("accN: ");
Serial.println(myGNSS.getRelPosAccN(), 4); // Use the helper functions to get the rel. pos. accuracy as m
Serial.print("accE: ");
Serial.println(myGNSS.getRelPosAccE(), 4);
Serial.print("accD: ");
Serial.println(myGNSS.getRelPosAccD(), 4);
Serial.print("gnssFixOk: ");
if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.gnssFixOK == true)
Serial.println("x");
else
Serial.println("");
Serial.print("diffSolution: ");
if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.diffSoln == true)
Serial.println("x");
else
Serial.println("");
Serial.print("relPosValid: ");
if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.relPosValid == true)
Serial.println("x");
else
Serial.println("");
Serial.print("carrier Solution Type: ");
if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.carrSoln == 0)
Serial.println("None");
else if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.carrSoln == 1)
Serial.println("Float");
else if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.carrSoln == 2)
Serial.println("Fixed");
Serial.print("isMoving: ");
if (myGNSS.packetUBXNAVRELPOSNED->data.flags.bits.isMoving == true)
Serial.println("x");
else
Serial.println("");
}
else
Serial.println("RELPOS request failed");
Serial.println("");
}

View file

@ -0,0 +1,123 @@
/*
Reading lat and long via UBX binary commands over SPI
By: Andrew Berridge
Date: 27th June 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to query a u-blox module for its lat/long/altitude over SPI. We also
turn off the NMEA output on the SPI port. This decreases the amount of SPI traffic
dramatically.
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
to something google maps understands simply divide the numbers by 10,000,000. We
do this so that we don't have to use floating point numbers.
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
NEO-M8U: https://www.sparkfun.com/products/16329
NEO-M9N: https://www.sparkfun.com/products/17285
Hardware Connections:
You need to connect the SPI pins from your microcontroller to the specific pins on your SparkFun product.
Connections will vary based on your microcontroller, but for reference please refer to this tutorial on SPI:
https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all
Most new boards now use the terms:
CS - Chip Select
COPI - Controller Out, Peripheral In
CIPO - Controller in, Peripheral Out
SCK - Serial Clock
You can choose any pin for Chip Select, but the others are likely either defined by the library you are using
(see here for the standard Arduino one: https://www.arduino.cc/en/reference/SPI) or the microcontroller. The
ESP32 has two standard, selectable SPI ports, for example.
To enable SPI communication, you will need to solder the DSEL/SPI jumper closed on your u-blox board.
IMPORTANT: there have been reports that some u-blox devices do not respond to the UBX protocol over SPI
with the factory settings. You may find you need to connect to the device via USB and u-center and set
the incoming protocol to UBX only. Make sure you disable all other protocols as inputs if you can't
get things to work! Hopefully this is just a bug in the u-blox firmware that will be fixed soon ;-)
*/
#include <SPI.h> //Needed for SPI to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// #########################################
// Instantiate an instance of the SPI class.
// Your configuration may be different, depending on the microcontroller you are using!
#define spiPort SPI // This is the SPI port on standard Ardino boards. Comment this line if you want to use a different port.
//SPIClass spiPort (HSPI); // This is the default SPI interface on some ESP32 boards. Uncomment this line if you are using ESP32.
// #########################################
const uint8_t csPin = 10; // On ATmega328 boards, SPI Chip Select is usually pin 10. Change this to match your board.
// #########################################
long lastTime = 0; //Simple local timer. Limits amount of SPI traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
spiPort.begin(); // begin the SPI port
//myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial
// Connect to the u-blox module using SPI port, csPin and speed setting
// ublox devices generally work up to 5MHz. We'll use 4MHz for this example:
if (myGNSS.begin(spiPort, csPin, 4000000) == false)
{
Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring. Freezing."));
while (1);
}
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults
myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause SPI traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
Serial.println();
}
}

View file

@ -0,0 +1,179 @@
/*
Configuring the GNSS to automatically send position reports over SPI
Based on code by: Nathan Seidle and Thorsten von Eicken
SparkFun Electronics
Date: January 3rd, 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 GNSS the send navigation reports automatically
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS
produces a fresh navigation solution at the expense of returning a slighly old solution.
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
NEO-M8U: https://www.sparkfun.com/products/16329
NEO-M9N: https://www.sparkfun.com/products/17285
Hardware Connections:
You need to connect the SPI pins from your microcontroller to the specific pins on your SparkFun product.
Connections will vary based on your microcontroller, but for reference please refer to this tutorial on SPI:
https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all
Most new boards now use the terms:
CS - Chip Select
COPI - Controller Out, Peripheral In
CIPO - Controller in, Peripheral Out
SCK - Serial Clock
You can choose any pin for Chip Select, but the others are likely either defined by the library you are using
(see here for the standard Arduino one: https://www.arduino.cc/en/reference/SPI) or the microcontroller. The
ESP32 has two standard, selectable SPI ports, for example.
To enable SPI communication, you will need to solder the DSEL/SPI jumper closed on your u-blox board.
IMPORTANT: there have been reports that some u-blox devices do not respond to the UBX protocol over SPI
with the factory settings. You may find you need to connect to the device via USB and u-center and set
the incoming protocol to UBX only. Make sure you disable all other protocols as inputs if you can't
get things to work! Hopefully this is just a bug in the u-blox firmware that will be fixed soon ;-)
*/
#include <SPI.h> //Needed for SPI to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// #########################################
// Instantiate an instance of the SPI class.
// Your configuration may be different, depending on the microcontroller you are using!
#define spiPort SPI // This is the SPI port on standard Ardino boards. Comment this line if you want to use a different port.
//SPIClass spiPort (HSPI); // This is the default SPI interface on some ESP32 boards. Uncomment this line if you are using ESP32.
// #########################################
const uint8_t csPin = 10; // On ATmega328 boards, SPI Chip Select is usually pin 10. Change this to match your board.
// #########################################
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
spiPort.begin(); // begin the SPI port
//myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial
// Connect to the u-blox module using SPI port, csPin and speed setting
// ublox devices generally work up to 5MHz. We'll use 4MHz for this example:
if (myGNSS.begin(spiPort, csPin, 4000000) == false)
{
Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring. Freezing."));
while (1);
}
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults
myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
//myGNSS.saveConfiguration(); //Optional: Save _all_ the current settings to flash and BBR
}
void loop()
{
// Calling getPVT returns true if there actually is a fresh navigation solution available.
// Start the reading only when valid LLH is available
if (myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false))
{
Serial.println();
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
int PDOP = myGNSS.getPDOP();
Serial.print(F(" PDOP: "));
Serial.print(PDOP);
Serial.print(F(" (10^-2)"));
int nedNorthVel = myGNSS.getNedNorthVel();
Serial.print(F(" VelN: "));
Serial.print(nedNorthVel);
Serial.print(F(" (mm/s)"));
int nedEastVel = myGNSS.getNedEastVel();
Serial.print(F(" VelE: "));
Serial.print(nedEastVel);
Serial.print(F(" (mm/s)"));
int nedDownVel = myGNSS.getNedDownVel();
Serial.print(F(" VelD: "));
Serial.print(nedDownVel);
Serial.print(F(" (mm/s)"));
int verticalAccEst = myGNSS.getVerticalAccEst();
Serial.print(F(" VAccEst: "));
Serial.print(verticalAccEst);
Serial.print(F(" (mm)"));
int horizontalAccEst = myGNSS.getHorizontalAccEst();
Serial.print(F(" HAccEst: "));
Serial.print(horizontalAccEst);
Serial.print(F(" (mm)"));
int speedAccEst = myGNSS.getSpeedAccEst();
Serial.print(F(" SpeedAccEst: "));
Serial.print(speedAccEst);
Serial.print(F(" (mm/s)"));
int headAccEst = myGNSS.getHeadingAccEst();
Serial.print(F(" HeadAccEst: "));
Serial.print(headAccEst);
Serial.print(F(" (degrees * 10^-5)"));
if (myGNSS.getHeadVehValid() == true) {
int headVeh = myGNSS.getHeadVeh();
Serial.print(F(" HeadVeh: "));
Serial.print(headVeh);
Serial.print(F(" (degrees * 10^-5)"));
int magDec = myGNSS.getMagDec();
Serial.print(F(" MagDec: "));
Serial.print(magDec);
Serial.print(F(" (degrees * 10^-2)"));
int magAcc = myGNSS.getMagAcc();
Serial.print(F(" MagAcc: "));
Serial.print(magAcc);
Serial.print(F(" (degrees * 10^-2)"));
}
Serial.println();
} else {
Serial.print(".");
delay(50);
}
}

View file

@ -0,0 +1,172 @@
/*
Get the high precision geodetic solution for latitude and longitude
By: Nathan Seidle
Modified by: Steven Rowland and Paul Clark
SparkFun Electronics
Date: April 17th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to inspect the accuracy of the high-precision
positional solution. Please see below for information about the units.
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
Hardware Connections:
Plug a Qwiic cable into the GNSS 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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Wire.begin();
//myGNSS.enableDebugging(Serial);
if (myGNSS.begin(Wire) == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setNavigationFrequency(20); //Set output to 20 times a second
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
Serial.print("Current update rate: ");
Serial.println(rate);
//myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
// getHighResLatitude: returns the latitude from HPPOSLLH as an int32_t in degrees * 10^-7
// getHighResLatitudeHp: returns the high resolution component of latitude from HPPOSLLH as an int8_t in degrees * 10^-9
// getHighResLongitude: returns the longitude from HPPOSLLH as an int32_t in degrees * 10^-7
// getHighResLongitudeHp: returns the high resolution component of longitude from HPPOSLLH as an int8_t in degrees * 10^-9
// getElipsoid: returns the height above ellipsoid as an int32_t in mm
// getElipsoidHp: returns the high resolution component of the height above ellipsoid as an int8_t in mm * 10^-1
// getMeanSeaLevel: returns the height above mean sea level as an int32_t in mm
// getMeanSeaLevelHp: returns the high resolution component of the height above mean sea level as an int8_t in mm * 10^-1
// getHorizontalAccuracy: returns the horizontal accuracy estimate from HPPOSLLH as an uint32_t in mm * 10^-1
// If you want to use the high precision latitude and longitude with the full 9 decimal places
// you will need to use a 64-bit double - which is not supported on all platforms
// To allow this example to run on standard platforms, we cheat by converting lat and lon to integer and fractional degrees
// The high resolution altitudes can be converted into standard 32-bit float
// First, let's collect the position data
int32_t latitude = myGNSS.getHighResLatitude();
int8_t latitudeHp = myGNSS.getHighResLatitudeHp();
int32_t longitude = myGNSS.getHighResLongitude();
int8_t longitudeHp = myGNSS.getHighResLongitudeHp();
int32_t ellipsoid = myGNSS.getElipsoid();
int8_t ellipsoidHp = myGNSS.getElipsoidHp();
int32_t msl = myGNSS.getMeanSeaLevel();
int8_t mslHp = myGNSS.getMeanSeaLevelHp();
uint32_t accuracy = myGNSS.getHorizontalAccuracy();
// Defines storage for the lat and lon units integer and fractional parts
int32_t lat_int; // Integer part of the latitude in degrees
int32_t lat_frac; // Fractional part of the latitude
int32_t lon_int; // Integer part of the longitude in degrees
int32_t lon_frac; // Fractional part of the longitude
// Calculate the latitude and longitude integer and fractional parts
lat_int = latitude / 10000000; // Convert latitude from degrees * 10^-7 to Degrees
lat_frac = latitude - (lat_int * 10000000); // Calculate the fractional part of the latitude
lat_frac = (lat_frac * 100) + latitudeHp; // Now add the high resolution component
if (lat_frac < 0) // If the fractional part is negative, remove the minus sign
{
lat_frac = 0 - lat_frac;
}
lon_int = longitude / 10000000; // Convert latitude from degrees * 10^-7 to Degrees
lon_frac = longitude - (lon_int * 10000000); // Calculate the fractional part of the longitude
lon_frac = (lon_frac * 100) + longitudeHp; // Now add the high resolution component
if (lon_frac < 0) // If the fractional part is negative, remove the minus sign
{
lon_frac = 0 - lon_frac;
}
// Print the lat and lon
Serial.print("Lat (deg): ");
Serial.print(lat_int); // Print the integer part of the latitude
Serial.print(".");
printFractional(lat_frac, 9); // Print the fractional part of the latitude with leading zeros
Serial.print(", Lon (deg): ");
Serial.print(lon_int); // Print the integer part of the latitude
Serial.print(".");
printFractional(lon_frac, 9); // Print the fractional part of the latitude with leading zeros
Serial.println();
// Now define float storage for the heights and accuracy
float f_ellipsoid;
float f_msl;
float f_accuracy;
// Calculate the height above ellipsoid in mm * 10^-1
f_ellipsoid = (ellipsoid * 10) + ellipsoidHp;
// Now convert to m
f_ellipsoid = f_ellipsoid / 10000.0; // Convert from mm * 10^-1 to m
// Calculate the height above mean sea level in mm * 10^-1
f_msl = (msl * 10) + mslHp;
// Now convert to m
f_msl = f_msl / 10000.0; // Convert from mm * 10^-1 to m
// Convert the horizontal accuracy (mm * 10^-1) to a float
f_accuracy = accuracy;
// Now convert to m
f_accuracy = f_accuracy / 10000.0; // Convert from mm * 10^-1 to m
// Finally, do the printing
Serial.print("Ellipsoid (m): ");
Serial.print(f_ellipsoid, 4); // Print the ellipsoid with 4 decimal places
Serial.print(", Mean Sea Level(m): ");
Serial.print(f_msl, 4); // Print the mean sea level with 4 decimal places
Serial.print(", Accuracy (m): ");
Serial.println(f_accuracy, 4); // Print the accuracy with 4 decimal places
}
}
// Pretty-print the fractional part with leading zeros - without using printf
// (Only works with positive numbers)
void printFractional(int32_t fractional, uint8_t places)
{
if (places > 1)
{
for (uint8_t place = places - 1; place > 0; place--)
{
if (fractional < pow(10, place))
{
Serial.print("0");
}
}
}
Serial.print(fractional);
}

View file

@ -0,0 +1,146 @@
/*
Get the high precision geodetic solution for latitude and longitude using double
By: Nathan Seidle
Modified by: Paul Clark (PaulZC)
SparkFun Electronics
Date: April 17th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to inspect the accuracy of the high-precision
positional solution. Please see below for information about the units.
** This example will only work correctly on platforms which support 64-bit double **
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
Hardware Connections:
Plug a Qwiic cable into the GNSS and (e.g.) a Redboard Artemis https://www.sparkfun.com/products/15444
or an Artemis Thing Plus https://www.sparkfun.com/products/15574
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 <Wire.h> // Needed for I2C to GNSS
#define myWire Wire // This will work on the Redboard Artemis and the Artemis Thing Plus using Qwiic
//#define myWire Wire1 // Uncomment this line if you are using the extra SCL1/SDA1 pins (D17 and D16) on the Thing Plus
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
myWire.begin();
//myGNSS.enableDebugging(Serial); // Uncomment this line to enable debug messages
if (myGNSS.begin(myWire) == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Check that this platform supports 64-bit (8 byte) double
if (sizeof(double) < 8)
{
Serial.println(F("Warning! Your platform does not support 64-bit double."));
Serial.println(F("The latitude and longitude will be inaccurate."));
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.setNavigationFrequency(20); //Set output to 20 times a second
byte rate = myGNSS.getNavigationFrequency(); //Get the update rate of this module
Serial.print("Current update rate: ");
Serial.println(rate);
//myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
}
void loop()
{
//Query module only every second.
//The module only responds when a new position is available.
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
// getHighResLatitude: returns the latitude from HPPOSLLH as an int32_t in degrees * 10^-7
// getHighResLatitudeHp: returns the high resolution component of latitude from HPPOSLLH as an int8_t in degrees * 10^-9
// getHighResLongitude: returns the longitude from HPPOSLLH as an int32_t in degrees * 10^-7
// getHighResLongitudeHp: returns the high resolution component of longitude from HPPOSLLH as an int8_t in degrees * 10^-9
// getElipsoid: returns the height above ellipsoid as an int32_t in mm
// getElipsoidHp: returns the high resolution component of the height above ellipsoid as an int8_t in mm * 10^-1
// getMeanSeaLevel: returns the height above mean sea level as an int32_t in mm
// getMeanSeaLevelHp: returns the high resolution component of the height above mean sea level as an int8_t in mm * 10^-1
// getHorizontalAccuracy: returns the horizontal accuracy estimate from HPPOSLLH as an uint32_t in mm * 10^-1
// First, let's collect the position data
int32_t latitude = myGNSS.getHighResLatitude();
int8_t latitudeHp = myGNSS.getHighResLatitudeHp();
int32_t longitude = myGNSS.getHighResLongitude();
int8_t longitudeHp = myGNSS.getHighResLongitudeHp();
int32_t ellipsoid = myGNSS.getElipsoid();
int8_t ellipsoidHp = myGNSS.getElipsoidHp();
int32_t msl = myGNSS.getMeanSeaLevel();
int8_t mslHp = myGNSS.getMeanSeaLevelHp();
uint32_t accuracy = myGNSS.getHorizontalAccuracy();
// Defines storage for the lat and lon as double
double d_lat; // latitude
double d_lon; // longitude
// Assemble the high precision latitude and longitude
d_lat = ((double)latitude) / 10000000.0; // Convert latitude from degrees * 10^-7 to degrees
d_lat += ((double)latitudeHp) / 1000000000.0; // Now add the high resolution component (degrees * 10^-9 )
d_lon = ((double)longitude) / 10000000.0; // Convert longitude from degrees * 10^-7 to degrees
d_lon += ((double)longitudeHp) / 1000000000.0; // Now add the high resolution component (degrees * 10^-9 )
// Print the lat and lon
Serial.print("Lat (deg): ");
Serial.print(d_lat, 9);
Serial.print(", Lon (deg): ");
Serial.print(d_lon, 9);
// Now define float storage for the heights and accuracy
float f_ellipsoid;
float f_msl;
float f_accuracy;
// Calculate the height above ellipsoid in mm * 10^-1
f_ellipsoid = (ellipsoid * 10) + ellipsoidHp;
// Now convert to m
f_ellipsoid = f_ellipsoid / 10000.0; // Convert from mm * 10^-1 to m
// Calculate the height above mean sea level in mm * 10^-1
f_msl = (msl * 10) + mslHp;
// Now convert to m
f_msl = f_msl / 10000.0; // Convert from mm * 10^-1 to m
// Convert the horizontal accuracy (mm * 10^-1) to a float
f_accuracy = accuracy;
// Now convert to m
f_accuracy = f_accuracy / 10000.0; // Convert from mm * 10^-1 to m
// Finally, do the printing
Serial.print(", Ellipsoid (m): ");
Serial.print(f_ellipsoid, 4); // Print the ellipsoid with 4 decimal places
Serial.print(", Mean Sea Level (m): ");
Serial.print(f_msl, 4); // Print the mean sea level with 4 decimal places
Serial.print(", Accuracy (m): ");
Serial.println(f_accuracy, 4); // Print the accuracy with 4 decimal places
}
}

Some files were not shown because too many files have changed in this diff Show more