sparkfun / SparkFun_Ublox_Arduino_Library

Library to control UBX binary protocol and NMEA over I2C on Ublox GPS modules
Other
144 stars 84 forks source link

Efficiently accessing accuracy #131

Closed dotMorten closed 4 years ago

dotMorten commented 4 years ago

Efficiently accessing accuracy

With AutoPVT I can get most of the current values pretty efficiently, and keep my display and button presses quite responsive on a SAMD51 chip. But once I start reading the vertical and horizontal accuracy every time getPVT() returns true, once a second the UI responsiveness stalls for a good .25 seconds or more.

I realized this is because highResModuleQueried isn't updated when you enable AutoPVT.

So I added a similar method to do the same thing as set autopvt to enable sending HPPOSLLH on a regular interval:


boolean SFE_UBLOX_GPS::setAutoHPPOSLLH(boolean enable, uint16_t maxWait)
{
  packetCfg.cls = UBX_CLASS_CFG;
  packetCfg.id = UBX_CFG_MSG;
  packetCfg.len = 3;
  packetCfg.startingSpot = 0;
  payloadCfg[0] = UBX_CLASS_NAV;
  payloadCfg[1] = UBX_NAV_HPPOSLLH;
  payloadCfg[2] = enable ? 1 : 0; // rate relative to navigation freq.

  boolean ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
  if (ok)
  {
    autoHPPOSLLH = enable;
  }
  highResModuleQueried.all = false;
  return ok;
}

The sendCommand does return success, and I do see the messages coming through in the debug log after this, but it doesn't appear to actually parse them.

In getHPPOSLLH() I also added the first 4 lines here to hopefully avoid reading them over and over again, but still no luck:

boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait)
{
+  if(autoHPPOSLLH)
+  {
+    checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_HPPOSLLH);
+    return highResModuleQueried.all;
+  }
  //The GPS is not automatically reporting navigation position so we have to poll explicitly
  packetCfg.cls = UBX_CLASS_NAV;
  packetCfg.id = UBX_NAV_HPPOSLLH;
  packetCfg.len = 0;

  return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK)
}

What am I missing here to make this work?

Your workbench

Here's the log I see. Notice how the message is being ignored:

heckUbloxI2C: Large packet of 144 bytes received
Incoming: Size: 92 Received: CLS:NAV ID:PVT Len: 0x5C Payload: [TRUNCATED]
packetCfg now valid
packetAck now valid
packetCfg classAndIDmatch
packetAck classAndIDmatch
Incoming: Size: 36 Received: CLS:NAV ID:0x14 Len: 0x24 Payload: IGNORED
packetCfg now valid
packetAck now valid
packetAck classAndIDmatch
checkUbloxI2C: OK, zero bytes available
checkUbloxI2C: OK, zero bytes available
checkUbloxI2C: OK, zero bytes available
checkUbloxI2C: OK, zero bytes available
PaulZC commented 4 years ago

Hi Morten,

Thanks for digging in to this!

processsUBXpacket will parse any UBX_NAV_HPPOSLLH messages it receives and will set the highResModuleQueried flags to true: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/src/SparkFun_Ublox_Arduino_Library.cpp#L980-L1006

So, when you call e.g. getHorizontalAccuracy it should return the stored horizontalAccuracy and not poll the module via I2C for the reading.

The trick is to make sure that processsUBXpacket is getting called so the HP data is being parsed automatically when it arrives. And - as you've correctly figured out - that gets called by checkUbloxInternal -> checkUbloxI2C -> process -> processUBX -> processUBXpacket.

The code you've added to getHPPOSLLH looks correct...

Looking at why the HPPOS message is being ignored. That would happen if the ignoreThisPayload flag is being set to true. And that would happen if this condition is not true: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/src/SparkFun_Ublox_Arduino_Library.cpp#L543-L556

So, the code is not expecting this class and ID. Why? I suspect it is something to do with the two calls to checkUbloxInternal. You are calling this twice, once for the PVT message and again for the HPPOSLLH message. I suspect what is happening is that the HPPOSLLH message is being parsed as a result of checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_PVT); in getPVT: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/src/SparkFun_Ublox_Arduino_Library.cpp#L2905 Hence the ID does not match and so the message is ignored.

I need to think about this. The obvious solution is to only use autoPVT or autoHPPOSLLH, not both.

Maybe you could try that? Does the code work correctly if you only have autoHPPOSLLH enabled?

Best wishes,

Paul

dotMorten commented 4 years ago

The obvious solution is to only use autoPVT or autoHPPOSLLH, not both.

That won't really help though because I need data from both (and soon even more messages). As a test though for troubleshooting I can try it out...

dotMorten commented 4 years ago

Skipping a call to gps.getPVT() and only calling gps.getHPPOSLLH() didn't make a difference. I still don't get the data

PaulZC commented 4 years ago

You will need to make sure the autoPVT messages are disabled, otherwise the reverse could happen: a PVT message arrives when you are expecting HPPOSLLH. Please call myGPS.setAutoPVT(false); Does that work?

dotMorten commented 4 years ago

Ignore my last comment, skipping gps.getPVT() does work, even with AutoPVT still on does work. The problem appears when calling getPVT(), which results in getHPPOSLLH() always returning false. I tried skipping calling getHPPOSLLH and just read the values, but then I just keep getting back 0.0 for the accuracy values, so I don't think the HP message is ever being parsed.

PaulZC commented 4 years ago

Hi Morten, I'm still thinking about possible solutions for this issue... Watch this space! Paul

dotMorten commented 4 years ago

Sounds good. I could imagine I'd want to be able to auto-process more values that aren't covered by PVT or HPPOSLLH, so a generic solution might be good. I'm also wondering if a callback-approach for specific message would be better? Ie in the loop call, ping the queue, and have callbacks for each method type, so I can be notified of a PVT, HPPOSLLH or something else. That'll allow me to do efficient update of UI only when needed, and also not experience any lag between getting the message and checking for the message. This worked pretty good for me for the NMEA parser I used before switching to this library.

PaulZC commented 4 years ago

Hi Morten (@dotMorten), I think I have a solution for you! I've merged the code changes into the release_candidate branch: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/commit/722afc43e7859749301b993b8f838e0c7829bca5 The solution is not elegant. PVT and HPPOSLLH can still arrive out of sequence and can overwrite each other, but that's OK. The data is extracted correctly. There are new debug messages to show when this happens. I've added a new example in the examples folder: examples\ZED-F9P\Example11_autoHPPOSLLH Please give it a try if you have time. This will get merged into the master branch when Nathan (@nseidle) has completed his other changes. A callback-based library would be a big improvement - but that's a BIG re-write for another day... Very best wishes - and thanks for contributing! Paul

dotMorten commented 4 years ago

@PaulZC This is amazing! Thank you! I'll try that out

dotMorten commented 4 years ago

@PaulZC Looks like it's working for me! I did have one comment on the example though: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/commit/722afc43e7859749301b993b8f838e0c7829bca5#r43629235

PaulZC commented 4 years ago

Many thanks for the suggestion Morten (@dotMorten)! I've updated the example: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/commit/8b27b3ea0af2baa5377ecfc17b7f68e9e7f9e0c5 I OR'd the results of getPVT and getHPPOSLLH. If I check them separately then the first one checked usually wins... Let me know if there's a better way? Very best wishes, Paul

PaulZC commented 4 years ago

Hi Morten (@dotMorten ), Can we close this issue? :-D Very best wishes, Paul

dotMorten commented 4 years ago

Yup. Thank you!