|
| 1 | +/* |
| 2 | + u-blox Example: ESF MEAS (Wheel Ticks) |
| 3 | + By: Paul Clark |
| 4 | + SparkFun Electronics |
| 5 | + Date: September 8th, 2022 |
| 6 | + License: MIT. See license file for more information but you can |
| 7 | + basically do whatever you want with this code. |
| 8 | +
|
| 9 | + This example configures the External Sensor Fusion MEAS sensor messages on the NEO-M8U / ZED-F9R and |
| 10 | + shows how to access the ESF data in the loop - without using the callback. |
| 11 | +
|
| 12 | + Please make sure your NEO-M8U is running UDR firmware >= 1.31. Please update using u-center if necessary: |
| 13 | + https://www.u-blox.com/en/product/neo-m8u-module#tab-documentation-resources |
| 14 | +
|
| 15 | + Feel like supporting open source hardware? |
| 16 | + Buy a board from SparkFun! |
| 17 | + NEO-M8U: https://www.sparkfun.com/products/16329 |
| 18 | +
|
| 19 | + Hardware Connections: |
| 20 | + Plug a Qwiic cable into the GPS and a Redboard Qwiic |
| 21 | + If you don't have a platform with a Qwiic connection use the |
| 22 | + SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) |
| 23 | + Open the serial monitor at 115200 baud to see the output |
| 24 | +
|
| 25 | +*/ |
| 26 | + |
| 27 | +#include <Wire.h> //Needed for I2C to GPS |
| 28 | + |
| 29 | +#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS |
| 30 | +SFE_UBLOX_GNSS myGNSS; |
| 31 | + |
| 32 | +// Callback: printESFMEASdata will be called when new ESF MEAS data arrives |
| 33 | +// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t |
| 34 | +// _____ You can use any name you like for the callback. Use the same name when you call setAutoESFMEAScallback |
| 35 | +// / _____ This _must_ be UBX_ESF_MEAS_data_t |
| 36 | +// | / _____ You can use any name you like for the struct |
| 37 | +// | | / |
| 38 | +// | | | |
| 39 | +void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct) |
| 40 | +{ |
| 41 | + Serial.println(F("Hey! The ESF MEAS callback has been called!")); |
| 42 | +} |
| 43 | + |
| 44 | +void setup() |
| 45 | +{ |
| 46 | + Serial.begin(230400); // <-- Use a fast baud rate to avoid the Serial prints slowing the code |
| 47 | + |
| 48 | + while (!Serial); //Wait for user to open terminal |
| 49 | + Serial.println(F("SparkFun u-blox Example")); |
| 50 | + |
| 51 | + Wire.begin(); |
| 52 | + Wire.setClock(400000); // <-- Use 400kHz I2C |
| 53 | + |
| 54 | + //myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial |
| 55 | + |
| 56 | + if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port |
| 57 | + { |
| 58 | + Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing.")); |
| 59 | + while (1); |
| 60 | + } |
| 61 | + |
| 62 | + myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) |
| 63 | + myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR |
| 64 | + |
| 65 | + if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata |
| 66 | + Serial.println(F("setAutoESFMEAScallback successful")); |
| 67 | +} |
| 68 | + |
| 69 | +void loop() |
| 70 | +{ |
| 71 | + myGNSS.checkUblox(); // Check for the arrival of new data and process it. |
| 72 | + |
| 73 | + // Check if new ESF MEAS data has arrived: |
| 74 | + // If myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid is true, it indicates new ESF MEAS data has been received and has been copied. |
| 75 | + // automaticFlags.flags.bits.callbackCopyValid will be cleared automatically when the callback is called. |
| 76 | + |
| 77 | + if (myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid == true) |
| 78 | + { |
| 79 | + // But, we can manually clear the callback flag too. This will prevent the callback from being called! |
| 80 | + myGNSS.packetUBXESFMEAS->automaticFlags.flags.bits.callbackCopyValid = false; // Comment this line if you still want the callback to be called |
| 81 | + |
| 82 | + // Print the timeTag |
| 83 | + Serial.print(F("Time: ")); |
| 84 | + Serial.println(myGNSS.packetUBXESFMEAS->callbackData->timeTag); |
| 85 | + |
| 86 | + // myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas indicates how many sensor groups the UBX_ESF_MEAS_data_t contains. |
| 87 | + for (uint8_t i = 0; i < myGNSS.packetUBXESFMEAS->callbackData->flags.bits.numMeas; i++) |
| 88 | + { |
| 89 | + // Print the sensor data type |
| 90 | + // From the M8 interface description: |
| 91 | + // 0: None |
| 92 | + // 1-4: Reserved |
| 93 | + // 5: z-axis gyroscope angular rate deg/s * 2^-12 signed |
| 94 | + // 6: front-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward) |
| 95 | + // 7: front-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward) |
| 96 | + // 8: rear-left wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward) |
| 97 | + // 9: rear-right wheel ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward) |
| 98 | + // 10: speed ticks: Bits 0-22: unsigned tick value. Bit 23: direction indicator (0=forward, 1=backward) |
| 99 | + // 11: speed m/s * 1e-3 signed |
| 100 | + // 12: gyroscope temperature deg Celsius * 1e-2 signed |
| 101 | + // 13: y-axis gyroscope angular rate deg/s * 2^-12 signed |
| 102 | + // 14: x-axis gyroscope angular rate deg/s * 2^-12 signed |
| 103 | + // 16: x-axis accelerometer specific force m/s^2 * 2^-10 signed |
| 104 | + // 17: y-axis accelerometer specific force m/s^2 * 2^-10 signed |
| 105 | + // 18: z-axis accelerometer specific force m/s^2 * 2^-10 signed |
| 106 | + switch (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType) |
| 107 | + { |
| 108 | + case 5: |
| 109 | + Serial.print(F("Z Gyro: ")); |
| 110 | + break; |
| 111 | + case 6: |
| 112 | + Serial.print(F("Front Left: ")); |
| 113 | + break; |
| 114 | + case 7: |
| 115 | + Serial.print(F("Front Right: ")); |
| 116 | + break; |
| 117 | + case 8: |
| 118 | + Serial.print(F("Rear Left: ")); |
| 119 | + break; |
| 120 | + case 9: |
| 121 | + Serial.print(F("Rear Right: ")); |
| 122 | + break; |
| 123 | + case 10: |
| 124 | + Serial.print(F("Speed Ticks: ")); |
| 125 | + break; |
| 126 | + case 11: |
| 127 | + Serial.print(F("Speed: ")); |
| 128 | + break; |
| 129 | + case 12: |
| 130 | + Serial.print(F("Temp: ")); |
| 131 | + break; |
| 132 | + case 13: |
| 133 | + Serial.print(F("Y Gyro: ")); |
| 134 | + break; |
| 135 | + case 14: |
| 136 | + Serial.print(F("X Gyro: ")); |
| 137 | + break; |
| 138 | + case 16: |
| 139 | + Serial.print(F("X Accel: ")); |
| 140 | + break; |
| 141 | + case 17: |
| 142 | + Serial.print(F("Y Accel: ")); |
| 143 | + break; |
| 144 | + case 18: |
| 145 | + Serial.print(F("Z Accel: ")); |
| 146 | + break; |
| 147 | + default: |
| 148 | + break; |
| 149 | + } |
| 150 | + |
| 151 | + // Tick data |
| 152 | + if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType >= 6) && (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType <= 10)) |
| 153 | + { |
| 154 | + if ((myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & (1 << 23)) > 0) |
| 155 | + Serial.print(F("-")); // Backward |
| 156 | + else |
| 157 | + Serial.print(F("+")); // Forward |
| 158 | + Serial.println(myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField & 0x007FFFFF); |
| 159 | + } |
| 160 | + // Speed |
| 161 | + else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 11) |
| 162 | + { |
| 163 | + union |
| 164 | + { |
| 165 | + int32_t signed32; |
| 166 | + uint32_t unsigned32; |
| 167 | + } signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t |
| 168 | + // The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t |
| 169 | + signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data |
| 170 | + float speed = signedUnsigned.signed32; // Extract the signed data. Convert to float |
| 171 | + speed /= 256.0; // Divide by 256 to undo the shift |
| 172 | + speed *= 0.001; // Convert from m/s * 1e-3 to m/s |
| 173 | + Serial.println(speed, 3); |
| 174 | + } |
| 175 | + // Gyro data |
| 176 | + 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)) |
| 177 | + { |
| 178 | + union |
| 179 | + { |
| 180 | + int32_t signed32; |
| 181 | + uint32_t unsigned32; |
| 182 | + } signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t |
| 183 | + // The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t |
| 184 | + signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data |
| 185 | + float rate = signedUnsigned.signed32; // Extract the signed data. Convert to float |
| 186 | + rate /= 256.0; // Divide by 256 to undo the shift |
| 187 | + rate *= 0.000244140625; // Convert from deg/s * 2^-12 to deg/s |
| 188 | + Serial.println(rate); |
| 189 | + } |
| 190 | + // Accelerometer data |
| 191 | + 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)) |
| 192 | + { |
| 193 | + union |
| 194 | + { |
| 195 | + int32_t signed32; |
| 196 | + uint32_t unsigned32; |
| 197 | + } signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t |
| 198 | + // The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t |
| 199 | + signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data |
| 200 | + float force = signedUnsigned.signed32; // Extract the signed data. Convert to float |
| 201 | + force /= 256.0; // Divide by 256 to undo the shift |
| 202 | + force *= 0.0009765625; // Convert from m/s^2 * 2^-10 to m/s^2 |
| 203 | + Serial.println(force); |
| 204 | + } |
| 205 | + // Gyro Temperature |
| 206 | + else if (myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataType == 12) |
| 207 | + { |
| 208 | + union |
| 209 | + { |
| 210 | + int32_t signed32; |
| 211 | + uint32_t unsigned32; |
| 212 | + } signedUnsigned; // Avoid any ambiguity casting uint32_t to int32_t |
| 213 | + // The dataField is 24-bit signed, stored in the 24 LSBs of a uint32_t |
| 214 | + signedUnsigned.unsigned32 = myGNSS.packetUBXESFMEAS->callbackData->data[i].data.bits.dataField << 8; // Shift left by 8 bits to correctly align the data |
| 215 | + float temperature = signedUnsigned.signed32; // Extract the signed data. Convert to float |
| 216 | + temperature /= 256.0; // Divide by 256 to undo the shift |
| 217 | + temperature *= 0.01; // Convert from C * 1e-2 to C |
| 218 | + Serial.println(temperature); |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + 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 |
| 224 | +} |
0 commit comments