See below the output at Serial monitor from my code. Although I have setNavigationFrequency to 2 solutions/second it often takes over 2 seconds to respond, and even then it only updates the GPS coordinates every 5 - 10 seconds. (NB: the ms value in square brackets at end of each line is time spent in that loop)
Also it sometimes respond really quick, even < 100ms.
What am I doing wrong? (TIA)
I doubt that. The only instuctions that are slow are getLatittude() and getLongitude(). If I comment them out, I have to enable the if (t1-t0) >= 1000) { test, to slow the loop to a readable speed.
The question is why are these two requests to the ZED adding over 2 seconds delay on most occasions, but not always? I should be able to get a current Lat/Lon readings twice a second, since Iāve set up for 2 solutions per second.
The time output isnāt exactly consistent either, with the supposed elapsed time.
So either somethings blocking, or there are secondary issues.
Youāll have to debug the library, and see what pumps the data, or if you have to spin on the getPVT().
Observing whatās coming out the ZEDās UART1 would be instructive as to whether youāre fighting an issue with the receiver, or your application of the library.
I agree with @clive1, I think the slow rate is all due to the way you have structured your code. Your use of 1ms timeouts is unusual and unlikely to work the way you expect it to. By default, the library polls (requests) the PVT message. Making it periodic (setting it to āAutoā) helps a lot and changes the way getPVT works. getPVT will then return true if fresh PVT data has arrived since the last call, otherwise it returns false.
For the ZED-F9P, Iād recommend using v3 of the library. It looks like you already are. Cliveās link is to a v2 example. For v3, the simplest āAuto PVTā example is below.
Well it turns out clive1ās early hunch about secondary issues was right. For some reason the ZED-F9P doesnāt like to use 921600 baud. If I reduce back to 115200 it works much better, although not ideal yet.
(Why 921600 I hear you say. Prior to this discussion I was developing a reliable feed from a public RTCM3 correction data stream into the ESP32 over WiFi, and forwarded over Serial into the Teensy for forwarding onto the ZED-F9P. This proved unreliable at first so I tried several fixes including buffering and the 921600 baud rates. In the end buffering was enough, even at 115200 to the ZED)
Hereās my code and output now. It curious that it starts out with < 500ms between readings (i.e. 2 solutions/sec) but settles at around 1 solution / sec.
That rate is OK for my purposes but Iād like to know why doesnāt it stay at 2/sec?
Note there are no calls to getPVT() or autoPVT() at all now:
#include <Streaming.h>
#include <TimeLib.h>
#include <SparkFun_u-blox_GNSS_v3.h>
SFE_UBLOX_GNSS_SERIAL gnss;
#define ZED Serial1 // for TX of RTCM3 corrections + RX of GNS status data
time_t timeU; // UTC
uint32_t t0,t1,t2; // timestamps
int32_t latitude, longitude, accuracy; // GPS coords
int32_t offset = 0;
void setup() {
Serial.begin(115200); // not needed teensy
while (!Serial && millis() < 1000);
delay(1000);
Serial << "\n\n======= ZED_online =======\n";
initGNS();
processGPStime(); // UTC time
reportDateTime(timeU);
t0 = millis();
Serial << "\n --- setup() done ---\n";
}
uint loops = 0;
void loop() {
t1 = millis();
//if (t1 - t0 >= 500) {
Serial << _WIDTHZ(++loops,3) << ": ";
processGPStime();
reportDateTime(timeU);
latitude = gnss.getLatitude();
longitude = gnss.getLongitude();
accuracy = gnss.getPositionAccuracy();
Serial << " Lat/Lon " << latitude+offset
<< " / " << longitude-offset
<< " +/-" << accuracy << " (mm)";
t0 = millis();
Serial << " [" << (t0-t1) << " ms]\n";
//}
}
void initGNS(){
Serial << "* initialise GNSS : ";
ZED.begin(115200); // ditto
//ZED.begin(921600); // doesn't work!
while (!gnss.begin(ZED)) { // Connect to ZED-F9P over Serial
Serial << ".";
delay (1000);
}
gnss.setUART1Output(COM_TYPE_UBX); // same, for Serial/UART1 connections
gnss.setNavigationFrequency(2); // set for 2 solutions/second
Serial << "OK [2 sol/sec]\n";
Serial << "* Wait for GPS Fix : ";
while (!gnss.getGnssFixOk()) { // Connect to the u-blox module
Serial << ".";
delay (1000);
}
Serial << "OK\n";
}
void processGPStime(){
tmElements_t tm;
tm.Year = gnss.getYear(1) - 1970; // load UTC time elements
tm.Month = gnss.getMonth(1);
tm.Day = gnss.getDay(1);
tm.Hour = gnss.getHour(1);
tm.Minute = gnss.getMinute(1);
tm.Second = gnss.getSecond(1);
timeU = makeTime(tm); // UTC = GPS time (as unixtime)
}
void reportDateTime(time_t t){
if (t >= 946684800 && t < 2524608000){ // if in valid years (1/1/2000 to 31/12/2049)
Serial << "* UTC ";
Serial << _WIDTHZ( hour(t),2) << ":"
<< _WIDTHZ(minute(t),2) << ":"
<< _WIDTHZ(second(t),2) << " ";
Serial << dayShortStr(weekday(t)) << " "
<< _WIDTHZ( day(t),2) << "/"
<< _WIDTHZ(month(t),2) << "/"
<< year(t);
}
else Serial << " *** time invalid (2) ***";
}
As Clive says, making PVT periodic (setAutoPVT) will help a lot. Also, you need to restructure your code. Move all of the getYear() ⦠getSecond() and getLatitude(), getLongitude() and getPositionAccuracy() inside a single if (gnss.getPVT()) { ... } statement. Remove those 1 millisecond timeouts: use getYear() not getYear(1).
Thanks Paul ( & Clive), Iām happy to do those changes but Iād like to know why Iām doing them ⦠since AFAIK the output Iām seeing is working fine, so what difference will re-instating getPVT() make? Is there a Wiki or similar explaining how to use this library? From the AutoPVT example you shared I can see thereās a lot of capability, and Iād like to understand better.
PS: you keep mentioning 1 ms timeouts, sorry but I donāt know what you mean? I donāt have any in this code, and the line //if (t1 - t0 >= 500) { is commented out/disabled.
Perhaps you mean the delay(1000) instructions inside the while loops?
Because you are polling the PVT message, instead of it being periodic, the library polls (requests) each PVT message and waits (stalls) until it arrives. That can take up to the full navigation cycle to be delivered, 500ms in your case, depending on when the poll takes place.
Something in your code is causing the message to be polled twice in each cycle. I canāt see exactly where that is happening, but it is happening. It usually happens if you call (e.g.) getLatitude twice in one cycle. The library recognises that the Latitude is āstaleā - has been read before - and so sends a fresh poll and waits for fresh data.
If you restructure your code, and make PVT periodic, you will get better results.
The (1) in getYear(1) sets the timeout to 1ms. That is probably having undesirable side-effectsā¦
Ah! Got it! getPositionAccuracy polls the NAV-HPPOSECEF message, not the NAV-PVT message. It returns the HPPOSECEF pAcc (position accuracy) value. So, you are polling two messages each cycle: PVT and HPPOSECEF. Each will take (up to) 500ms to be returned.
If you replace getPositionAccuracy with getHorizontalAccEst, you will see a big improvement. getHorizontalAccEst returns the hAcc (horizontal accuracy estimate) from the PVT message.
And I just proved your theory/discovery correct! using my version of the AutoPVT example clive1 pointed to earlier. It has all your suggestions in the code, including even this:
if (gnss.getPVT() && (!gnss.getInvalidLlh())) {
(I donāt know what getInvalidLlh() does. But it looks impressive)
Following are 2 snapshots of the output from my AutoPVT code.
In the first I am calling both getHorizontalAccEst() and getPositionAccuracy in each loop(). Their values appear in the HAcc and Pos.Acc columns. Note the time gaps in the last 3 columns, summing to ~ 1 second or half the rate of 2 solutions/second I chose (as you predict)
In the Second I removed getPositionAccuracy while still calling getHorizontalAccEst()
Now the time gaps in the last 3 columns, summing to ~ 500ms, matching 2 solutions/second (again as you predicted)
Here is the loop() section of my code, after getPositionAccuracy was commented out. Iād like to know what all these mean ⦠I can guess a few, but SIV has me stumped:
void loop(){
if (gnss.getPVT() && (!gnss.getInvalidLlh())) {
t1 = millis();
int32_t latitude = gnss.getLatitude() ;
int32_t longitude = gnss.getLongitude();
int32_t altitude = gnss.getAltitude();
//int32_t accuracy = gnss.getPositionAccuracy();
int PDOP = gnss.getPDOP();
int nedNorthVel = gnss.getNedNorthVel();
int nedEastVel = gnss.getNedEastVel();
int nedDownVel = gnss.getNedDownVel();
int verticalAccEst = gnss.getVerticalAccEst();
int horizontalAccEst= gnss.getHorizontalAccEst();
int speedAccEst = gnss.getSpeedAccEst();
int headAccEst = gnss.getHeadingAccEst();
byte SIV = gnss.getSIV();
Serial << latitude << "/" << longitude << '\t'
<< altitude << '\t'
<< SIV << '\t'
<< PDOP << '\t'
<< nedNorthVel << '\t'
<< nedEastVel << '\t'
<< nedDownVel << '\t'
<< verticalAccEst << '\t'
<< horizontalAccEst << '\t'
<< speedAccEst << '\t'
<< headAccEst; // << '\t'
//<< accuracy;
if (gnss.getHeadVehValid()) {
int headVeh = gnss.getHeadVeh();
int magDec = gnss.getMagDec();
int magAcc = gnss.getMagAcc();
Serial << "\tHeadVeh: " << headVeh << " ° (*10^-5)";
Serial << "\tMagDec: " << magDec << " ° (*10^-2)";
Serial << "\tMagAcc: " << magAcc << " ° (*10^-2)";
} // getHeadVehValid()
//else Serial << " (XX)";
t2 = millis();
Serial << " [" << _WIDTH((t1-t0),4)
<< " +" << _WIDTH((t2-t1),4)
<< " = " << _WIDTH((t2-t0),4) << " ms ]\n";
t0 = millis();
} // if
}
BTW note that if (gnss.getHeadVehValid()) { is never true (i.e headVeh, magDec and magAcc are never reported). compass readings perhaps?
āSIVā means āSatellites In Viewā. Itās the wrong name. We kept it only for backward compatibility with older code. Itās actually numSV - the number of Space Vehicles used in the navigation solution.
Youāre heading into Automotive Dead Reckoning territory there. Thatās only applicable on some modules:
Is there an equivalent to autoPVT/getPVT for the NAV-HPPOSECEF message? I would like to use getPositionAccuracy as it seems to be a single 3D value, whereas getHorizontalAccEst is only 1D. Is it possible to get this info without the time penalty? Or is the normal usage to only poll it every, say, 10 seconds?
Yes, the Interface Description is the ultimate reference.
Yes, NAV-HPPOSECEF has full āAutoā support in the library too: setAutoNAVHPPOSECEF etc.. There isnāt an example for āAutoā HPPOSECEF, but there is a polling example.
For best results, call getPositionAccuracy from inside if (getNAVHPPOSECEF()) { ... }.
Thereās no time penalty if you switch to periodic messages. getPVT() and getNAVHPPOSECEF() will independently return true when new data arrives. You can set the message rates independently to whatever you need. setAutoNAVHPPOSECEFrate(20) would set the message rate to one message every 20 navigation intervals: 10s in your case.
You might find the callbacks useful. They keep your code loop really clean and compact. See CallbackExample1_NAV_PVT.
Iām sorry thereās no wiki. The examples are the wiki - and thereās a ton of themā¦