From 4578550eee4a2262d37f0ef9f3bd3462f703e916 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 22 Dec 2019 23:43:21 +0000 Subject: [PATCH] Added setDynamicModel (and made some minor corrections) --- .../Example20_DynamicModel.ino | 102 ++++++++++++++++++ keywords.txt | 2 + src/SparkFun_Ublox_Arduino_Library.cpp | 48 ++++++++- src/SparkFun_Ublox_Arduino_Library.h | 19 ++++ 4 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 examples/Example20_DynamicModel/Example20_DynamicModel.ino diff --git a/examples/Example20_DynamicModel/Example20_DynamicModel.ino b/examples/Example20_DynamicModel/Example20_DynamicModel.ino new file mode 100644 index 0000000..7619e0b --- /dev/null +++ b/examples/Example20_DynamicModel/Example20_DynamicModel.ino @@ -0,0 +1,102 @@ +/* + Set Dynamic Model + By: Paul Clark (PaulZC) + Date: December 18th, 2019 + + Based extensively on Example3_GetPosition + By: Nathan Seidle + SparkFun Electronics + Date: January 3rd, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to change the Ublox module's dynamic platform model and then + query its lat/long/altitude. We also turn off the NMEA output on the I2C port. + This decreases the amount of I2C traffic dramatically. + + Possible values for the dynamic model are: PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, + SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE + + Note: Long/lat are large numbers because they are * 10^7. To convert lat/long + to something google maps understands simply divide the numbers by 10,000,000. We + do this so that we don't have to use floating point numbers. + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + //myGPS.enableDebugging(); // Uncomment this line to enable debug messages + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + // If we are going to change the dynamic platform model, let's do it here. + // Possible values are: + // PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE + + if (!myGPS.setDynamicModel(myGPS.PORTABLE)) // Set the dynamic model to PORTABLE + { + Serial.println("***!!! Warning: setDynamicModel failed !!!***"); + } + else + { + Serial.println("Dynamic platform model changed successfully!"); + } + + //myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR +} + +void loop() +{ + //Query module only every second. Doing it more often will just cause I2C traffic. + //The module only responds when a new position is available + if (millis() - lastTime > 1000) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + Serial.println(); + } +} diff --git a/keywords.txt b/keywords.txt index f0d1ed7..e600619 100644 --- a/keywords.txt +++ b/keywords.txt @@ -125,6 +125,8 @@ addGeofence KEYWORD2 clearGeofences KEYWORD2 getGeofenceState KEYWORD2 +setDynamicModel KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 5fc9e9d..689c305 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -164,7 +164,7 @@ void SFE_UBLOX_GPS::setSerialRate(uint32_t baudrate, uint8_t uartPort, uint16_t _debugSerial->println(((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); } - sendCommand(packetCfg); + sendCommand(packetCfg, maxWait); } //Changes the I2C address that the Ublox module responds to @@ -172,7 +172,7 @@ void SFE_UBLOX_GPS::setSerialRate(uint32_t baudrate, uint8_t uartPort, uint16_t boolean SFE_UBLOX_GPS::setI2CAddress(uint8_t deviceAddress, uint16_t maxWait) { //Get the current config values for the I2C port - getPortSettings(COM_PORT_I2C); //This will load the payloadCfg array with current port settings + getPortSettings(COM_PORT_I2C, maxWait); //This will load the payloadCfg array with current port settings packetCfg.cls = UBX_CLASS_CFG; packetCfg.id = UBX_CFG_PRT; @@ -1361,7 +1361,7 @@ boolean SFE_UBLOX_GPS::getSurveyMode(uint16_t maxWait) //Control Survey-In for NEO-M8P boolean SFE_UBLOX_GPS::setSurveyMode(uint8_t mode, uint16_t observationTime, float requiredAccuracy, uint16_t maxWait) { - if (getSurveyMode() == false) //Ask module for the current TimeMode3 settings. Loads into payloadCfg. + if (getSurveyMode(maxWait) == false) //Ask module for the current TimeMode3 settings. Loads into payloadCfg. return (false); packetCfg.cls = UBX_CLASS_CFG; @@ -1488,9 +1488,13 @@ boolean SFE_UBLOX_GPS::getPortSettings(uint8_t portID, uint16_t maxWait) boolean SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, uint16_t maxWait) { //Get the current config values for this port ID - if (getPortSettings(portID) == false) + if (getPortSettings(portID, maxWait) == false) return (false); //Something went wrong. Bail. + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing two sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_CFG, UBX_CFG_PRT, 100); // But we'll only wait for 100msec max + //Yes, this is the depreciated way to do it but it's still supported on v27 so it //covers both ZED-F9P (v27) and SAM-M8Q (v18) @@ -1512,9 +1516,13 @@ boolean SFE_UBLOX_GPS::setPortInput(uint8_t portID, uint8_t inStreamSettings, ui { //Get the current config values for this port ID //This will load the payloadCfg array with current port settings - if (getPortSettings(portID) == false) + if (getPortSettings(portID, maxWait) == false) return (false); //Something went wrong. Bail. + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing two sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_CFG, UBX_CFG_PRT, 100); // But we'll only wait for 100msec max + packetCfg.cls = UBX_CLASS_CFG; packetCfg.id = UBX_CFG_PRT; packetCfg.len = 20; @@ -1789,6 +1797,36 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin return(true); } +//Change the dynamic platform model using UBX-CFG-NAV5 +//Possible values are: +//PORTABLE,STATIONARY,PEDESTRIAN,AUTOMOTIVE,SEA, +//AIRBORNE1g,AIRBORNE2g,AIRBORNE4g,WRIST,BIKE +//WRIST is not supported in protocol versions less than 18 +//BIKE is supported in protocol versions 19.2 +boolean SFE_UBLOX_GPS::setDynamicModel(uint8_t newDynamicModel, uint16_t maxWait) +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_NAV5; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current navigation model settings. Loads into payloadCfg. + return (false); + + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing two sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_CFG, UBX_CFG_NAV5, 100); // But we'll only wait for 100msec max + + payloadCfg[0] = 0x01; // mask: set only the dyn bit (0) + payloadCfg[1] = 0x00; // mask + payloadCfg[2] = newDynamicModel; // dynModel + + packetCfg.len = 36; + packetCfg.startingSpot = 0; + + return (sendCommand(packetCfg, maxWait)); //Wait for ack +} + //Given a spot in the payload array, extract four bytes and build a long uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) { diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 9d3c409..2197adb 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -99,6 +99,7 @@ const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics const uint8_t UBX_CFG_RST = 0x04; //Used to reset device const uint8_t UBX_CFG_RATE = 0x08; //Used to set port baud rates const uint8_t UBX_CFG_CFG = 0x09; //Used to save current configuration +const uint8_t UBX_CFG_NAV5 = 0x24; //Used to configure the navigation engine including the dynamic model const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version Ublox modules (ie protocol v27 and above) @@ -344,6 +345,9 @@ class SFE_UBLOX_GPS boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state + //Change the dynamic platform model using UBX-CFG-NAV5 + boolean setDynamicModel(uint8_t newDynamicModel = PEDESTRIAN, uint16_t maxWait = 2000); + //Survey-in specific controls struct svinStructure { @@ -417,6 +421,21 @@ class SFE_UBLOX_GPS uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame + enum dynModel // Possible values for the dynamic platform model + { + PORTABLE = 0, + // 1 is not defined + STATIONARY = 2, + PEDESTRIAN, + AUTOMOTIVE, + SEA, + AIRBORNE1g, + AIRBORNE2g, + AIRBORNE4g, + WRIST, // Not supported in protocol versions less than 18 + BIKE // Supported in protocol versions 19.2 + }; + private: //Depending on the sentence type the processor will load characters into different arrays enum SentenceTypes