Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit 96c226d

Browse files
committed
Add support for auto-reporting of navigation solutions using UBX_NAV_PVT
1 parent 9d71472 commit 96c226d

File tree

3 files changed

+173
-53
lines changed

3 files changed

+173
-53
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Configuring the GPS to automatically send position reports over I2C
3+
By: Nathan Seidle
4+
SparkFun Electronics
5+
Date: January 3rd, 2019
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 shows how to configure the U-Blox GPS the send navigation reports automatically
10+
and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GPS
11+
produces a fresh navigation solution at the expense of returning a slighly old solution.
12+
13+
This can be used over serial or over I2C, this example shows the I2C use. With serial the GPS
14+
simply outputs the UBX_NAV_PVT packet. With I2C it queues it into its internal I2C buffer (4KB in
15+
size?) where it can be retrieved in the next I2C poll.
16+
17+
Feel like supporting open source hardware?
18+
Buy a board from SparkFun!
19+
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
20+
NEO-M8P RTK: https://www.sparkfun.com/products/15005
21+
SAM-M8Q: https://www.sparkfun.com/products/15106
22+
23+
Hardware Connections:
24+
Plug a Qwiic cable into the GPS and a BlackBoard
25+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
26+
Open the serial monitor at 115200 baud to see the output
27+
*/
28+
29+
#include <Particle.h>
30+
#include <Wire.h> //Needed for I2C to GPS
31+
32+
#include <SparkFun_Ublox_Arduino_Library.h> //http://librarymanager/All#SparkFun_Ublox_GPS
33+
SFE_UBLOX_GPS myGPS;
34+
35+
void setup()
36+
{
37+
Serial.begin(115200);
38+
while (!Serial); //Wait for user to open terminal
39+
Serial.println("SparkFun Ublox Example");
40+
41+
Wire.begin();
42+
43+
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
44+
{
45+
Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
46+
while (1);
47+
}
48+
49+
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
50+
myGPS.setNavigationFrequency(2); //Produce two solutions per second
51+
myGPS.setAutoPVT(true); //Tell the GPS to "send" each solution
52+
myGPS.saveConfiguration(); //Save the current settings to flash and BBR
53+
}
54+
55+
void loop()
56+
{
57+
// Calling getPVT returns true if there actually is a fresh navigation solution available.
58+
if (myGPS.getPVT())
59+
{
60+
Serial.println();
61+
long latitude = myGPS.getLatitude();
62+
Serial.print(F("Lat: "));
63+
Serial.print(latitude);
64+
65+
long longitude = myGPS.getLongitude();
66+
Serial.print(F(" Long: "));
67+
Serial.print(longitude);
68+
Serial.print(F(" (degrees * 10^-7)"));
69+
70+
long altitude = myGPS.getAltitude();
71+
Serial.print(F(" Alt: "));
72+
Serial.print(altitude);
73+
Serial.print(F(" (mm)"));
74+
75+
byte SIV = myGPS.getSIV();
76+
Serial.print(F(" SIV: "));
77+
Serial.print(SIV);
78+
79+
Serial.println();
80+
} else {
81+
Serial.print(".");
82+
delay(50);
83+
}
84+
}

src/SparkFun_Ublox_Arduino_Library.cpp

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C()
188188
debug.println("No bytes available");
189189
#endif
190190
lastCheck = millis(); //Put off checking to avoid I2C bus traffic
191+
return true;
191192
}
192193

193194
while (bytesAvailable)
@@ -455,27 +456,50 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX)
455456
//Once a packet has been received and validated, identify this packet's class/id and update internal flags
456457
void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg)
457458
{
458-
if (msg->cls == UBX_CLASS_ACK)
459-
{
460-
//We don't want to store ACK packets, just set commandAck flag
461-
if (msg->id == UBX_ACK_ACK)
462-
{
463-
if (msg->payload[0] == packetCfg.cls && msg->payload[1] == packetCfg.id)
464-
{
465-
//The ack we just received matched the CLS/ID of last packetCfg sent
459+
switch (msg->cls) {
460+
case UBX_CLASS_ACK:
461+
//We don't want to store ACK packets, just set commandAck flag
462+
if (msg->id == UBX_ACK_ACK && msg->payload[0] == packetCfg.cls && msg->payload[1] == packetCfg.id)
463+
{
464+
//The ack we just received matched the CLS/ID of last packetCfg sent
466465
#ifdef DEBUG
467-
debug.println("Command sent/ack'd successfully");
466+
debug.println("Command sent/ack'd successfully");
468467
#endif
468+
commandAck = true;
469+
}
470+
break;
469471

470-
commandAck = true;
471-
}
472+
case UBX_CLASS_NAV:
473+
Serial.println("**************************************************");
474+
if (msg->id == UBX_NAV_PVT && msg->len == 92)
475+
{
476+
//Parse various byte fields into global vars
477+
fixType = extractByte(20 - packetCfg.startingSpot);
478+
carrierSolution = extractByte(21 - packetCfg.startingSpot) >> 6; //Get 6th&7th bits of this byte
479+
SIV = extractByte(23 - packetCfg.startingSpot);
480+
longitude = extractLong(24 - packetCfg.startingSpot);
481+
latitude = extractLong(28 - packetCfg.startingSpot);
482+
altitude = extractLong(32 - packetCfg.startingSpot);
483+
altitudeMSL = extractLong(36 - packetCfg.startingSpot);
484+
groundSpeed = extractLong(60 - packetCfg.startingSpot);
485+
headingOfMotion = extractLong(64 - packetCfg.startingSpot);
486+
pDOP = extractLong(76 - packetCfg.startingSpot);
487+
488+
//Mark all datums as fresh (not read before)
489+
moduleQueried.all = true;
490+
moduleQueried.longitude = true;
491+
moduleQueried.latitude = true;
492+
moduleQueried.altitude = true;
493+
moduleQueried.altitudeMSL = true;
494+
moduleQueried.SIV = true;
495+
moduleQueried.fixType = true;
496+
moduleQueried.carrierSolution = true;
497+
moduleQueried.groundSpeed = true;
498+
moduleQueried.headingOfMotion = true;
499+
moduleQueried.pDOP = true;
500+
}
501+
break;
472502
}
473-
//else
474-
//{
475-
//Serial.println("Command send fail");
476-
//module.ackReceived = false;
477-
//}
478-
}
479503
}
480504

481505
//Given a packet and payload, send everything including CRC bytes via I2C port
@@ -1035,6 +1059,24 @@ uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait)
10351059
return (measurementRate);
10361060
}
10371061

1062+
//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT
1063+
//works.
1064+
boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, uint16_t maxWait)
1065+
{
1066+
packetCfg.cls = UBX_CLASS_CFG;
1067+
packetCfg.id = UBX_CFG_MSG;
1068+
packetCfg.len = 3;
1069+
packetCfg.startingSpot = 0;
1070+
payloadCfg[0] = UBX_CLASS_NAV;
1071+
payloadCfg[1] = UBX_NAV_PVT;
1072+
payloadCfg[2] = enable ? 1 : 0; // rate relative to navigation freq.
1073+
1074+
bool ok = sendCommand(packetCfg, maxWait);
1075+
if (ok) autoPVT = enable;
1076+
moduleQueried.all = false;
1077+
return ok;
1078+
}
1079+
10381080
//Given a spot in the payload array, extract four bytes and build a long
10391081
uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart)
10401082
{
@@ -1064,42 +1106,22 @@ uint8_t SFE_UBLOX_GPS::extractByte(uint8_t spotToStart)
10641106
//Get the latest Position/Velocity/Time solution and fill all global variables
10651107
boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait)
10661108
{
1067-
//Query the module for the latest lat/long
1068-
packetCfg.cls = UBX_CLASS_NAV;
1069-
packetCfg.id = UBX_NAV_PVT;
1070-
packetCfg.len = 0;
1071-
packetCfg.startingSpot = 20; //Begin listening at spot 20 so we can record up to 20+MAX_PAYLOAD_SIZE = 84 bytes
1072-
1073-
if(sendCommand(packetCfg, maxWait) == false)
1074-
return(false); //If command send fails then bail
1109+
if (autoPVT) {
1110+
//The GPS is automatically reporting, we just check whether we got unread data
1111+
checkUblox();
1112+
return moduleQueried.all;
1113+
} else {
1114+
//The GPS is not automatically reporting navigation position so we have to poll explicitly
1115+
packetCfg.cls = UBX_CLASS_NAV;
1116+
packetCfg.id = UBX_NAV_PVT;
1117+
packetCfg.len = 0;
1118+
packetCfg.startingSpot = 20; //Begin listening at spot 20 so we can record up to 20+MAX_PAYLOAD_SIZE = 84 bytes
10751119

1076-
//Parse various byte fields into global vars
1077-
fixType = extractByte(20 - packetCfg.startingSpot);
1078-
carrierSolution = extractByte(21 - packetCfg.startingSpot) >> 6; //Get 6th&7th bits of this byte
1079-
SIV = extractByte(23 - packetCfg.startingSpot);
1080-
longitude = extractLong(24 - packetCfg.startingSpot);
1081-
latitude = extractLong(28 - packetCfg.startingSpot);
1082-
altitude = extractLong(32 - packetCfg.startingSpot);
1083-
altitudeMSL = extractLong(36 - packetCfg.startingSpot);
1084-
groundSpeed = extractLong(60 - packetCfg.startingSpot);
1085-
headingOfMotion = extractLong(64 - packetCfg.startingSpot);
1086-
pDOP = extractLong(76 - packetCfg.startingSpot);
1087-
1088-
//Mark all datums as fresh (not read before)
1089-
//moduleQueried ThisStruct;
1090-
//memset(&ThisStruct, 0, sizeof(moduleQueried));
1091-
moduleQueried.longitude = true;
1092-
moduleQueried.latitude = true;
1093-
moduleQueried.altitude = true;
1094-
moduleQueried.altitudeMSL = true;
1095-
moduleQueried.SIV = true;
1096-
moduleQueried.fixType = true;
1097-
moduleQueried.carrierSolution = true;
1098-
moduleQueried.groundSpeed = true;
1099-
moduleQueried.headingOfMotion = true;
1100-
moduleQueried.pDOP = true;
1120+
//The data is parsed as part of processing the response
1121+
return sendCommand(packetCfg, maxWait);
1122+
return(false); //If command send fails then bail
1123+
}
11011124

1102-
return(true);
11031125
}
11041126

11051127
//Get the current 3D high precision positional accuracy - a fun thing to watch
@@ -1137,6 +1159,7 @@ int32_t SFE_UBLOX_GPS::getLongitude(uint16_t maxWait)
11371159
{
11381160
if(moduleQueried.longitude == false) getPVT();
11391161
moduleQueried.longitude = false; //Since we are about to give this to user, mark this data as stale
1162+
moduleQueried.all = false;
11401163

11411164
return(longitude);
11421165
}
@@ -1146,6 +1169,7 @@ int32_t SFE_UBLOX_GPS::getAltitude(uint16_t maxWait)
11461169
{
11471170
if(moduleQueried.altitude == false) getPVT();
11481171
moduleQueried.altitude = false; //Since we are about to give this to user, mark this data as stale
1172+
moduleQueried.all = false;
11491173

11501174
return(altitude);
11511175
}
@@ -1157,6 +1181,7 @@ int32_t SFE_UBLOX_GPS::getAltitudeMSL(uint16_t maxWait)
11571181
{
11581182
if(moduleQueried.altitudeMSL == false) getPVT();
11591183
moduleQueried.altitudeMSL = false; //Since we are about to give this to user, mark this data as stale
1184+
moduleQueried.all = false;
11601185

11611186
return(altitudeMSL);
11621187
}
@@ -1166,6 +1191,7 @@ uint8_t SFE_UBLOX_GPS::getSIV(uint16_t maxWait)
11661191
{
11671192
if(moduleQueried.SIV == false) getPVT();
11681193
moduleQueried.SIV = false; //Since we are about to give this to user, mark this data as stale
1194+
moduleQueried.all = false;
11691195

11701196
return(SIV);
11711197
}
@@ -1176,6 +1202,7 @@ uint8_t SFE_UBLOX_GPS::getFixType(uint16_t maxWait)
11761202
{
11771203
if(moduleQueried.fixType == false) getPVT();
11781204
moduleQueried.fixType = false; //Since we are about to give this to user, mark this data as stale
1205+
moduleQueried.all = false;
11791206

11801207
return(fixType);
11811208
}
@@ -1187,6 +1214,7 @@ uint8_t SFE_UBLOX_GPS::getCarrierSolutionType(uint16_t maxWait)
11871214
{
11881215
if(moduleQueried.carrierSolution == false) getPVT();
11891216
moduleQueried.carrierSolution = false; //Since we are about to give this to user, mark this data as stale
1217+
moduleQueried.all = false;
11901218

11911219
return(carrierSolution);
11921220
}
@@ -1196,6 +1224,7 @@ int32_t SFE_UBLOX_GPS::getGroundSpeed(uint16_t maxWait)
11961224
{
11971225
if(moduleQueried.groundSpeed == false) getPVT();
11981226
moduleQueried.groundSpeed = false; //Since we are about to give this to user, mark this data as stale
1227+
moduleQueried.all = false;
11991228

12001229
return(groundSpeed);
12011230
}
@@ -1205,6 +1234,7 @@ int32_t SFE_UBLOX_GPS::getHeading(uint16_t maxWait)
12051234
{
12061235
if(moduleQueried.headingOfMotion == false) getPVT();
12071236
moduleQueried.headingOfMotion = false; //Since we are about to give this to user, mark this data as stale
1237+
moduleQueried.all = false;
12081238

12091239
return(headingOfMotion);
12101240
}
@@ -1214,6 +1244,7 @@ uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait)
12141244
{
12151245
if(moduleQueried.pDOP == false) getPVT();
12161246
moduleQueried.pDOP = false; //Since we are about to give this to user, mark this data as stale
1247+
moduleQueried.all = false;
12171248

12181249
return(pDOP);
12191250
}

src/SparkFun_Ublox_Arduino_Library.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ const uint8_t UBX_NAV_HPPOSLLH = 0x14; //Used for obtaining lat/long/alt in high
110110
const uint8_t UBX_NAV_SVIN = 0x3B; //Used for checking Survey In status
111111

112112
const uint8_t UBX_MON_VER = 0x04; //Used for obtaining Protocol Version
113+
const uint8_t UBX_MON_TXBUF = 0x08; //Used for query tx buffer size/state
113114

114115
//The following are used to enable RTCM messages
115116
const uint8_t UBX_CFG_MSG = 0x01;
@@ -200,7 +201,7 @@ class SFE_UBLOX_GPS
200201
void processNMEA(char incoming) __attribute__((weak)); //Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries
201202

202203
void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages
203-
boolean sendCommand(ubxPacket outgoingUBX, uint16_t maxWait = 250); //Given a packet and payload, send everything including CRC bytes
204+
boolean sendCommand(ubxPacket outgoingUBX, uint16_t maxWait = 250); //Given a packet and payload, send everything including CRC bytes, return true if we got a response
204205
boolean sendI2cCommand(ubxPacket outgoingUBX, uint16_t maxWait = 250);
205206
void sendSerialCommand(ubxPacket outgoingUBX);
206207

@@ -220,7 +221,9 @@ class SFE_UBLOX_GPS
220221

221222
boolean waitForResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = 250); //Poll the module until and ack is received
222223

223-
boolean getPVT(uint16_t maxWait = 1000); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc.
224+
boolean setAutoPVT(boolean enabled, uint16_t maxWait = 250); //Enable/disable automatic PVT reports at the navigation frequency
225+
boolean getPVT(uint16_t maxWait = 1000); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available.
226+
224227
int32_t getLatitude(uint16_t maxWait = 250); //Returns the current latitude in degrees * 10^-7. Auto selects between HighPrecision and Regular depending on ability of module.
225228
int32_t getLongitude(uint16_t maxWait = 250); //Returns the current longitude in degrees * 10-7. Auto selects between HighPrecision and Regular depending on ability of module.
226229
int32_t getAltitude(uint16_t maxWait = 250); //Returns the current altitude in mm above ellipsoid
@@ -336,6 +339,7 @@ class SFE_UBLOX_GPS
336339

337340
const uint8_t I2C_POLLING_WAIT_MS = 25; //Limit checking of new characters to every X ms
338341
unsigned long lastCheck = 0;
342+
boolean autoPVT = false; //Whether autoPVT is enabled or not
339343
boolean commandAck = false; //This goes true after we send a command and it's ack'd
340344
uint8_t ubxFrameCounter;
341345

@@ -347,6 +351,7 @@ class SFE_UBLOX_GPS
347351
//This reduces the number of times we have to call getPVT as this can take up to ~1s per read
348352
//depending on update rate
349353
struct {
354+
uint16_t all : 1;
350355
uint16_t longitude : 1;
351356
uint16_t latitude : 1;
352357
uint16_t altitude : 1;

0 commit comments

Comments
 (0)