diff --git a/.gitignore b/.gitignore index e4eedb2..484d3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,8 @@ $RECYCLE.BIN/ Network Trash Folder Temporary Items .apdisk + +# VIM backup files +*~ +[._]*.un~ +*.swp diff --git a/examples/Dead Reckoning/Example1_calibrateSensor/Example1_calibrateSensor.ino b/examples/Dead Reckoning/Example1_calibrateSensor/Example1_calibrateSensor.ino new file mode 100644 index 0000000..cb19a97 --- /dev/null +++ b/examples/Dead Reckoning/Example1_calibrateSensor/Example1_calibrateSensor.ino @@ -0,0 +1,66 @@ +/* + 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 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 + + To take advantage of the internal IMU of either the Dead Reckoning GPS + boards (ZED-F9R, NEO-M8U), you must first calibrate it. This includes securing the GPS 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 + not-calibrated - 0, or calibrated - 1. +*/ + +#include //Needed for I2C to GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println(F("SparkFun Ublox Example")); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) +} + +void loop() +{ + + if (myGPS.getEsfInfo()){ + Serial.print(F("Fusion Mode: ")); + Serial.println(myGPS.imuMeas.fusionMode); + if (myGPS.imuMeas.fusionMode == 1) + Serial.println(F("Sensor is calibrated!")); + } + + delay(250); +} diff --git a/examples/Dead Reckoning/Example2_getIMUData/Example2_getIMUData.ino b/examples/Dead Reckoning/Example2_getIMUData/Example2_getIMUData.ino new file mode 100644 index 0000000..f7c62a0 --- /dev/null +++ b/examples/Dead Reckoning/Example2_getIMUData/Example2_getIMUData.ino @@ -0,0 +1,84 @@ +/* + 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 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 + + 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 //Needed for I2C to GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println(F("SparkFun Ublox Example")); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + if (myGPS.getEsfInfo()){ + + Serial.print(F("Fusion Mode: ")); + Serial.println(myGPS.imuMeas.fusionMode); + + if (myGPS.imuMeas.fusionMode == 1){ + Serial.println(F("Fusion Mode is Initialized!")); + } + else { + Serial.println(F("Fusion Mode is either disabled or not initialized - Freezing!")); + Serial.println(F("Please see Example 1 description at top for more information.")); + } + } +} + +void loop() +{ + + if (myGPS.getEsfIns()) + { + Serial.print(F("X: ")); + Serial.println(myGPS.imuMeas.xAngRate); + Serial.print(F("Y: ")); + Serial.println(myGPS.imuMeas.yAngRate); + Serial.print(F("Z: ")); + Serial.println(myGPS.imuMeas.zAngRate); + Serial.print(F("X Acceleration: ")); + Serial.println(myGPS.imuMeas.xAccel); + Serial.print(F("Y Acceleration: ")); + Serial.println(myGPS.imuMeas.yAccel); + Serial.print(F("Z Acceleration: ")); + Serial.println(myGPS.imuMeas.zAccel); + // These values also have "validity checks" that can be provided by the + // ublox library, add "Vald" to values: e.g. xAngRateVald or xAccelVald. + } + + delay(250); +} + diff --git a/examples/Dead Reckoning/Example3_getSensorStatus/Example3_getSensorStatus.ino b/examples/Dead Reckoning/Example3_getSensorStatus/Example3_getSensorStatus.ino new file mode 100644 index 0000000..ba89587 --- /dev/null +++ b/examples/Dead Reckoning/Example3_getSensorStatus/Example3_getSensorStatus.ino @@ -0,0 +1,97 @@ +/* + 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 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 + + 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 //Needed for I2C to GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println(F("SparkFun Ublox Example")); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + // 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 (myGPS.getEsfInfo()){ + + Serial.print(F("Fusion Mode: ")); + Serial.println(myGPS.imuMeas.fusionMode); + + if (myGPS.imuMeas.fusionMode == 1){ + Serial.println(F("Fusion Mode is Initialized!")); + } + else { + Serial.println(F("Fusion Mode is either disabled or not initialized - Freezing!")); + Serial.println(F("Please see Example 1 description at top for more information.")); + } + } +} + +void loop() +{ + + for(int i=1; i<=myGPS.ubloxSen.numSens; i++){ + myGPS.getSensState(i); // Give the sensor you want to check on. + Serial.print(F("Sensor Data Type: ")); //See ublox receiver description + //or our hookup guide for information on the + //return value. + Serial.println(myGPS.ubloxSen.senType); + Serial.print(F("Being Used: ")); + Serial.println(myGPS.ubloxSen.isUsed); + Serial.print(F("Is Ready: ")); + Serial.println(myGPS.ubloxSen.isReady); + Serial.print(F("Calibration Status: ")); + Serial.println(myGPS.ubloxSen.calibStatus); + Serial.print(F("Time Status: ")); + Serial.println(myGPS.ubloxSen.timeStatus); + Serial.print(F("Bad Measure: ")); + Serial.println(myGPS.ubloxSen.timeStatus); + Serial.print(F("Bad Time Tag: ")); + Serial.println(myGPS.ubloxSen.badTag); + Serial.print(F("Missed Measure : ")); + Serial.println(myGPS.ubloxSen.missMeas); + Serial.print(F("Noisy Measure: ")); + Serial.println(myGPS.ubloxSen.noisyMeas); + } + +} + + diff --git a/examples/Dead Reckoning/Example4_vehicleDynamics/Example4_vehicleDynamics.ino b/examples/Dead Reckoning/Example4_vehicleDynamics/Example4_vehicleDynamics.ino new file mode 100644 index 0000000..562632c --- /dev/null +++ b/examples/Dead Reckoning/Example4_vehicleDynamics/Example4_vehicleDynamics.ino @@ -0,0 +1,82 @@ +/* + 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 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 + + 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. You can also check the + accuracy of those readings. + +*/ + +#include //Needed for I2C to GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println(F("SparkFun Ublox Example")); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + if (myGPS.getEsfInfo()){ + + Serial.print(F("Fusion Mode: ")); + Serial.println(myGPS.imuMeas.fusionMode); + + if (myGPS.imuMeas.fusionMode == 1){ + Serial.println(F("Fusion Mode is Initialized!")); + } + else { + Serial.println(F("Fusion Mode is either disabled or not initialized - Freezing!")); + Serial.println(F("Please see Example 1 description at top for more information.")); + } + } +} + +void loop() +{ + myGPS.getVehAtt(); // Give the sensor you want to check on. + Serial.print(F("Roll: ")); + Serial.println(myGPS.vehAtt.roll); + Serial.print(F("Pitch: ")); + Serial.println(myGPS.vehAtt.pitch); + Serial.print(F("Heading: ")); + Serial.println(myGPS.vehAtt.heading); + Serial.print(F("Roll Accuracy: ")); + Serial.println(myGPS.vehAtt.accRoll); + Serial.print(F("Pitch Accuracy: ")); + Serial.println(myGPS.vehAtt.accPitch); + Serial.print(F("Heading Accuracy: ")); + Serial.println(myGPS.vehAtt.accHeading); + + delay(250); +} + + diff --git a/keywords.txt b/keywords.txt index 7562d61..c2745cc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -144,6 +144,13 @@ disableMessage KEYWORD2 enableNMEAMessage KEYWORD2 disableNMEAMessage KEYWORD2 +getEsfInfo KEYWORD2 +getEsfIns KEYWORD2 +getEsfDataInfo KEYWORD2 +getEsfRawDataInfo KEYWORD2 + +getSensState KEYWORD2 +getVehAtt KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### @@ -211,3 +218,8 @@ DYN_MODEL_AIRBORNE2g LITERAL1 DYN_MODEL_AIRBORNE4g LITERAL1 DYN_MODEL_WRIST LITERAL1 DYN_MODEL_BIKE LITERAL1 + +UBX_ESF_STATUS LITERAL1 +UBX_ESF_RAW LITERAL1 +UBX_ESF_MEAS LITERAL1 +UBX_ESF_INS LITERAL1 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 2b05dd0..56b64ae 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -3167,3 +3167,190 @@ boolean SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) return (true); } +boolean SFE_UBLOX_GPS::getEsfInfo(uint16_t maxWait) +{ + // Requesting Data from the receiver + packetCfg.cls = UBX_CLASS_ESF; + packetCfg.id = UBX_ESF_STATUS; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + checkUblox(); + + // payload should be loaded. + imuMeas.version = extractByte(4); + imuMeas.fusionMode = extractByte(12); + ubloxSen.numSens = extractByte(15); + + // Individual Status Sensor in different function + return(true); +} + +// +boolean SFE_UBLOX_GPS::getEsfIns(uint16_t maxWait) +{ + packetCfg.cls = UBX_CLASS_ESF; + packetCfg.id = UBX_ESF_INS; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + checkUblox(); + + // Validity of each sensor value below + uint32_t validity = extractLong(0); + + imuMeas.xAngRateVald = (validity && 0x0080) >> 8; + imuMeas.yAngRateVald = (validity && 0x0100) >> 9; + imuMeas.zAngRateVald = (validity && 0x0200) >> 10; + imuMeas.xAccelVald = (validity && 0x0400) >> 11; + imuMeas.yAccelVald = (validity && 0x0800) >> 12; + imuMeas.zAccelVald = (validity && 0x1000) >> 13; + + imuMeas.xAngRate = extractLong(12); // deg/s + imuMeas.yAngRate = extractLong(16); // deg/s + imuMeas.zAngRate = extractLong(20); // deg/s + + imuMeas.xAccel = extractLong(24); // m/s + imuMeas.yAccel = extractLong(28); // m/s + imuMeas.zAccel = extractLong(32); // m/s + + return(true); +} + +// +boolean SFE_UBLOX_GPS::getEsfDataInfo(uint16_t maxWait) +{ + + packetCfg.cls = UBX_CLASS_ESF; + packetCfg.id = UBX_ESF_MEAS; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + checkUblox(); + + uint32_t timeStamp = extractLong(0); + uint32_t flags = extractInt(4); + + uint8_t timeSent = (flags && 0x01) >> 1; + uint8_t timeEdge = (flags && 0x02) >> 2; + uint8_t tagValid = (flags && 0x04) >> 3; + uint8_t numMeas = (flags && 0x1000) >> 15; + + if (numMeas > DEF_NUM_SENS) + numMeas = DEF_NUM_SENS; + + uint8_t byteOffset = 4; + + for(uint8_t i=0; i> 23; + imuMeas.data[i] = (bitField && 0xFFFFFF); + imuMeas.dataTStamp[i] = extractLong(8 + byteOffset * i); + + } + + return(true); + +} + +boolean SFE_UBLOX_GPS::getEsfRawDataInfo(uint16_t maxWait) +{ + + // Need to know the number of sensor to get the correct data + // Rate selected in UBX-CFG-MSG is not respected + packetCfg.cls = UBX_CLASS_ESF; + packetCfg.id = UBX_ESF_RAW; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + checkUblox(); + + uint32_t bitField = extractLong(4); + imuMeas.rawDataType = (bitField && 0xFF000000) >> 23; + imuMeas.rawData = (bitField && 0xFFFFFF); + imuMeas.rawTStamp = extractLong(8); + + return(true); +} + +sfe_ublox_status_e SFE_UBLOX_GPS::getSensState(uint8_t sensor, uint16_t maxWait) +{ + + packetCfg.cls = UBX_CLASS_ESF; + packetCfg.id = UBX_ESF_STATUS; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail + + ubloxSen.numSens = extractByte(15); + + if (sensor > ubloxSen.numSens) + return (SFE_UBLOX_STATUS_OUT_OF_RANGE); + + checkUblox(); + + uint8_t offset = 4; + + // Only the last sensor value checked will remain. + for(uint8_t i=0; i> 5; + ubloxSen.isUsed = (sensorFieldOne && 0x20) >> 6; + ubloxSen.isReady = (sensorFieldOne && 0x30) >> 7; + + ubloxSen.calibStatus = sensorFieldTwo && 0x03; + ubloxSen.timeStatus = (sensorFieldTwo && 0xC) >> 2; + + ubloxSen.badMeas = (sensorFieldThr && 0x01); + ubloxSen.badTag = (sensorFieldThr && 0x02) >> 1; + ubloxSen.missMeas = (sensorFieldThr && 0x04) >> 2; + ubloxSen.noisyMeas = (sensorFieldThr && 0x08) >> 3; + } + + return (SFE_UBLOX_STATUS_SUCCESS); + +} + +boolean SFE_UBLOX_GPS::getVehAtt(uint16_t maxWait){ + + packetCfg.cls = UBX_CLASS_NAV; + packetCfg.id = UBX_NAV_ATT; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail + + checkUblox(); + + vehAtt.roll = extractLong(8); + vehAtt.pitch = extractLong(12); + vehAtt.heading = extractLong(16); + + vehAtt.accRoll = extractLong(20); + vehAtt.accPitch = extractLong(24); + vehAtt.accHeading = extractLong(28); + + return (true); + +} diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 894262f..97bc353 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -274,6 +274,7 @@ const uint8_t UBX_MON_TXBUF = 0x08; //Transmitter Buffer Status. Used for query const uint8_t UBX_MON_VER = 0x04; //Receiver/Software Version. Used for obtaining Protocol Version. //The following are used to configure the NAV UBX messages (navigation results messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 35-36) +const uint8_t UBX_NAV_ATT = 0x05; //Vehicle "Attitude" Solution const uint8_t UBX_NAV_CLOCK = 0x22; //Clock Solution const uint8_t UBX_NAV_DOP = 0x04; //Dilution of precision const uint8_t UBX_NAV_EOE = 0x61; //End of Epoch @@ -334,6 +335,14 @@ const uint8_t UBX_ACK_NACK = 0x00; const uint8_t UBX_ACK_ACK = 0x01; const uint8_t UBX_ACK_NONE = 0x02; //Not a real value +// The following constants are used to get External Sensor Measurements and Status +// Information. +const uint8_t UBX_ESF_MEAS = 0x02; +const uint8_t UBX_ESF_RAW = 0x03; +const uint8_t UBX_ESF_STATUS = 0x10; +const uint8_t UBX_ESF_INS = 0x15; //36 bytes + + const uint8_t SVIN_MODE_DISABLE = 0x00; const uint8_t SVIN_MODE_ENABLE = 0x01; @@ -623,6 +632,13 @@ class SFE_UBLOX_GPS boolean setDynamicModel(dynModel newDynamicModel = DYN_MODEL_PORTABLE, uint16_t maxWait = 1100); uint8_t getDynamicModel(uint16_t maxWait = 1100); // Get the dynamic model - returns 255 if the sendCommand fails + boolean getEsfInfo(uint16_t maxWait = 1100); + boolean getEsfIns(uint16_t maxWait = 1100); + boolean getEsfDataInfo(uint16_t maxWait = 1100); + boolean getEsfRawDataInfo(uint16_t maxWait = 1100); + sfe_ublox_status_e getSensState(uint8_t sensor, uint16_t maxWait = 1100); + boolean getVehAtt(uint16_t maxWait = 1100); + //Survey-in specific controls struct svinStructure { @@ -700,6 +716,67 @@ class SFE_UBLOX_GPS uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame +#define DEF_NUM_SENS 7 + struct deadReckData + { + uint8_t version; + uint8_t fusionMode; + + uint8_t xAngRateVald; + uint8_t yAngRateVald; + uint8_t zAngRateVald; + uint8_t xAccelVald; + uint8_t yAccelVald; + uint8_t zAccelVald; + + int32_t xAngRate; + int32_t yAngRate; + int32_t zAngRate; + + int32_t xAccel; + int32_t yAccel; + int32_t zAccel; + + // The array size is based on testing directly on M8U and F9R + uint32_t rawData; + uint32_t rawDataType; + uint32_t rawTStamp; + + uint32_t data[DEF_NUM_SENS]; + uint32_t dataType[DEF_NUM_SENS]; + uint32_t dataTStamp[DEF_NUM_SENS]; + } imuMeas; + + struct indivImuData + { + + uint8_t numSens; + + uint8_t senType; + boolean isUsed; + boolean isReady; + uint8_t calibStatus; + uint8_t timeStatus; + + uint8_t freq; // Hz + + boolean badMeas; + boolean badTag; + boolean missMeas; + boolean noisyMeas; + } ubloxSen; + + struct vehicleAttitude + { + // All values in degrees + int32_t roll; + int32_t pitch; + int32_t heading; + uint32_t accRoll; + uint32_t accPitch; + uint32_t accHeading; + } vehAtt; + private: //Depending on the sentence type the processor will load characters into different arrays enum SentenceTypes