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,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);
}