diff --git a/examples/ZED-F9P/Example11_setStaticPosition/Example11_setStaticPosition.ino b/examples/ZED-F9P/Example11_setStaticPosition/Example11_setStaticPosition.ino new file mode 100644 index 0000000..51a7e89 --- /dev/null +++ b/examples/ZED-F9P/Example11_setStaticPosition/Example11_setStaticPosition.ino @@ -0,0 +1,73 @@ +/* + Set the static position of the receiver. + By: SparkFun Electronics / Nathan Seidle + Date: September 26th, 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 set the static position of a receiver + using an Earth-Centered, Earth-Fixed (ECEF) location. This is the + output from a long (24 hour+) survey-in. Setting the static position + immediately causes the receiver to begin outputting RTCM data (if + enabled), perfect for setting up your own RTCM NTRIP caster or CORS. + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + + Hardware Connections: + Plug a Qwiic cable into the 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; + +void setup() +{ + Serial.begin(115200); // You may need to increase this for high navigation rates! + while (!Serial) + ; //Wait for user to open terminal + Serial.println(F("SparkFun u-blox Example")); + + Wire.begin(); + + //myGPS.enableDebugging(); // Uncomment this line to enable debug messages + + if (myGPS.begin() == false) //Connect to the u-blox module using Wire port + { + Serial.println(F("u-blox 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) + + //-1280208.308,-4716803.847,4086665.811 is SparkFun HQ so... + + //Units are cm so 1234 = 12.34m + //myGPS.setStaticPosition(-128020831, -471680385, 408666581); + + //Units are cm with a high precision extension so -1234.5678 should be called: (-123456, -78) + myGPS.setStaticPosition(-128020830, -80, -471680384, -70, 408666581, 10); //With high precision 0.1mm parts + + //We can also set via lat/long + //40.09029751,-105.18507900,1560.238 + //myGPS.setStaticPosition(400902975, -1051850790, 156024, true); //True at end enables lat/long input + //myGPS.setStaticPosition(400902975, 10, -1051850790, 0, 156023, 80, true); + + //Now let's use getVals to read back the data + //long ecefX = myGPS.getVal32(0x40030003); + //Serial.print("ecefX: "); + //Serial.println(ecefX); + + Serial.println(F("Done!")); +} + +void loop() +{ +} diff --git a/keywords.txt b/keywords.txt index d5ec567..2d662e7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -159,6 +159,7 @@ getVehAtt KEYWORD2 setI2CTransactionSize KEYWORD2 getI2CTransactionSize KEYWORD2 +setStaticPosition KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index bba8a3e..b51a583 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -3533,3 +3533,62 @@ boolean SFE_UBLOX_GPS::getVehAtt(uint16_t maxWait) return (true); } + +//Set the ECEF or Lat/Long coordinates of a receiver +//This imediately puts the receiver in TIME mode (fixed) and will begin outputting RTCM sentences if enabled +//This is helpful once an antenna's position has been established. See this tutorial: https://learn.sparkfun.com/tutorials/how-to-build-a-diy-gnss-reference-station#gather-raw-gnss-data +// For ECEF the units are: cm, 0.1mm, cm, 0.1mm, cm, 0.1mm +// For Lat/Lon/Alt the units are: degrees^-7, degrees^-9, degrees^-7, degrees^-9, cm, 0.1mm +bool SFE_UBLOX_GPS::setStaticPosition(int32_t ecefXOrLat, int8_t ecefXOrLatHP, int32_t ecefYOrLon, int8_t ecefYOrLonHP, int32_t ecefZOrAlt, int8_t ecefZOrAltHP, bool latLong, uint16_t maxWait) +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_TMODE3; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + //Ask module for the current TimeMode3 settings. Loads into payloadCfg. + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); + + packetCfg.len = 40; + + //Clear packet payload + for (uint8_t x = 0; x < packetCfg.len; x++) + payloadCfg[x] = 0; + + //customCfg should be loaded with poll response. Now modify only the bits we care about + payloadCfg[2] = 2; //Set mode to fixed. Use ECEF (not LAT/LON/ALT). + + if (latLong == true) + payloadCfg[3] = (uint8_t)(1 << 0); //Set mode to fixed. Use LAT/LON/ALT. + + //Set ECEF X or Lat + payloadCfg[4] = (ecefXOrLat >> 8 * 0) & 0xFF; //LSB + payloadCfg[5] = (ecefXOrLat >> 8 * 1) & 0xFF; + payloadCfg[6] = (ecefXOrLat >> 8 * 2) & 0xFF; + payloadCfg[7] = (ecefXOrLat >> 8 * 3) & 0xFF; //MSB + + //Set ECEF Y or Long + payloadCfg[8] = (ecefYOrLon >> 8 * 0) & 0xFF; //LSB + payloadCfg[9] = (ecefYOrLon >> 8 * 1) & 0xFF; + payloadCfg[10] = (ecefYOrLon >> 8 * 2) & 0xFF; + payloadCfg[11] = (ecefYOrLon >> 8 * 3) & 0xFF; //MSB + + //Set ECEF Z or Altitude + payloadCfg[12] = (ecefZOrAlt >> 8 * 0) & 0xFF; //LSB + payloadCfg[13] = (ecefZOrAlt >> 8 * 1) & 0xFF; + payloadCfg[14] = (ecefZOrAlt >> 8 * 2) & 0xFF; + payloadCfg[15] = (ecefZOrAlt >> 8 * 3) & 0xFF; //MSB + + //Set high precision parts + payloadCfg[16] = ecefXOrLatHP; + payloadCfg[17] = ecefYOrLonHP; + payloadCfg[18] = ecefZOrAltHP; + + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK +} + +bool SFE_UBLOX_GPS::setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, int32_t ecefZOrAlt, bool latlong, uint16_t maxWait) +{ + return (setStaticPosition(ecefXOrLat, 0, ecefYOrLon, 0, ecefZOrAlt, 0, latlong, maxWait)); +} \ No newline at end of file diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 2ba24be..3fd84b3 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -461,7 +461,7 @@ class SFE_UBLOX_GPS //Control the size of the internal I2C transaction amount void setI2CTransactionSize(uint8_t bufferSize); uint8_t getI2CTransactionSize(void); - + //Set the max number of bytes set in a given I2C transaction uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit @@ -641,6 +641,12 @@ class SFE_UBLOX_GPS sfe_ublox_status_e getSensState(uint8_t sensor, uint16_t maxWait = 1100); boolean getVehAtt(uint16_t maxWait = 1100); + // Given coordinates, put receiver into static position. Set latlong to true to pass in lat/long values instead of ecef. + // For ECEF the units are: cm, 0.1mm, cm, 0.1mm, cm, 0.1mm + // For Lat/Lon/Alt the units are: degrees^-7, degrees^-9, degrees^-7, degrees^-9, cm, 0.1mm + bool setStaticPosition(int32_t ecefXOrLat, int8_t ecefXOrLatHP, int32_t ecefYOrLon, int8_t ecefYOrLonHP, int32_t ecefZOrAlt, int8_t ecefZOrAltHP, bool latLong = false, uint16_t maxWait = 250); + bool setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, int32_t ecefZOrAlt, bool latLong = false, uint16_t maxWait = 250); + //Survey-in specific controls struct svinStructure {