Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getPVT() returns false for long periods of time in ZED-F9P moving base application #66

Closed
jordancth opened this issue Sep 16, 2024 · 5 comments

Comments

@jordancth
Copy link

Subject of the issue

I have two ZED-F9P units, each with their own antenna, connected to an ESP32. I am trying use the two units in a moving base setup, as described here - specifically sections 2.2.1 and 2.3.2. I am trying to get the latitude and longitude from the base unit, and the relative position data from the rover unit. Most of the time, the values I get are fine. However, there can be long periods of time (up to 20 seconds) where the getPVT() method returns false. I've also noticed an instance where the callback didn't fire for almost 20 seconds. I'm wondering if that's to be expected, or if there is some way to figure out what the issue is.

Your workbench

  • What development board or microcontroller are you using? ESP32-WROOM-32UE
  • What version of hardware or breakout board are you using? Sparkfun u-blox GPS-RTK2 ZED-F9P.
  • How is the breakout board wired to your microcontroller? Via I2C. The RX pin on the base unit is also connected to the TX pin on the rover unit.
  • How is everything being powered? Via USB (both the ESP32 and the ZED-F9P).
  • Are there any additional details that may help us help you?
    Firmware for ZED-F9P is HPG1.50, although I have also tested using HPG1.13 and had the same problems. When testing, the antennae have a clear view of the sky.

Steps to reproduce

Example code below.

#include <Wire.h>             // I2C needed for GPS-RTK2.
#include <SparkFun_u-blox_GNSS_v3.h> //http://librarymanager/All#SparkFun_u-blox_GNSS

SFE_UBLOX_GNSS fwdGPS;
SFE_UBLOX_GNSS revGPS;
const byte FWD_I2C_ADDRESS = 0x42;       
const byte REV_I2C_ADDRESS = 0x43;   

void setup() {
	delay(2000);
	Serial.begin(115200);
	Wire.begin();

	if (fwdGPS.begin(Wire, FWD_I2C_ADDRESS) == false) //Connect to the Ublox module using Wire port
	{
        	Serial.println(F("Forward GPS not detected at 0x42 I2C address. Please check wiring or reprogram its address. Freezing."));
        	while (1);
	}
  	fwdGPS.setI2COutput(COM_TYPE_UBX);                    //Set the I2C port to output UBX only (turn off NMEA noise)
  	fwdGPS.setSerialRate(460800, COM_PORT_UART1);
  	fwdGPS.setSerialRate(460800, COM_PORT_UART2);
  	fwdGPS.setVal8(UBLOX_CFG_MSGOUT_UBX_NAV_RELPOSNED_UART1, 1);
  	fwdGPS.setNavigationFrequency(5);
  	fwdGPS.setAutoPVT(true, false);    
  	fwdGPS.setAutoRELPOSNEDcallbackPtr(&RELPOSNEDcallback);                
  	fwdGPS.saveConfiguration();                           //Save the current settings to flash and BBR

	if (revGPS.begin(Wire, REV_I2C_ADDRESS) == false) //Connect to the Ublox module using Wire port
    	{
        	Serial.println(F("Reverse GPS not detected at 0x43 I2C address. Please check wiring or reprogram its address. Freezing."));
        	while (1);
    	}
        revGPS.setI2COutput(COM_TYPE_UBX);                 //Set the I2C port to output UBX only (turn off NMEA noise)
    	revGPS.setSerialRate(460800, COM_PORT_UART1);
    	revGPS.setSerialRate(460800, COM_PORT_UART2);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE4072_0_UART2, 1);
    	revGPS.setNavigationFrequency(5);
    	revGPS.setAutoPVT(true); 
    	revGPS.saveConfiguration(); //Save the current settings to flash and BBR
    	revGPS.disableSurveyMode();
}

void RELPOSNEDcallback(UBX_NAV_RELPOSNED_data_t *ubxDataStruct){
	if(revGPS.getPVT())
	{
    		Serial.print("Rear Latitude: ");
    		Serial.println(revGPS.getLatitude());
    		Serial.print("Rear Longitude: ");
    		Serial.println(revGPS.getLongitude());
	}
	else
	{
    		Serial.println("revGPS.getPVT() returned false");
  	}
  	//I don't think I have to check fwdGPS.getPVT() since we call fwdGPS.checkUblox() in the loop method, implicit update set to false
  	Serial.print("Forward Latitude: ");
  	Serial.println(fwdGPS.getLatitude());
  	Serial.print("Forward Longitude: ");
  	Serial.println(fwdGPS.getLongitude());
  	if(ubxDataStruct->flags.bits.relPosValid && ubxDataStruct->flags.bits.relPosHeadingValid)
  	{
  		Serial.print("relPosN: ");
        	Serial.println((float)ubxDataStruct->relPosN / 100); 
        	Serial.print("relPosE: ");
        	Serial.println((float)ubxDataStruct->relPosE / 100);
		Serial.print("relPosHeading: ");
		Serial.println(ubxDataStruct->relPosHeading);
  	}
  	else
  	{
    		Serial.println("Either relPosValid or relPosHeadingValid were false");
  	}
}

void loop(){
	fwdGPS.checkUblox();
	fwdGPS.checkCallbacks();
}

Expected behavior

The getPVT() method shouldn't return false for more than 5 seconds at a time ideally. The callback method should also run at least every 5 seconds.

Actual behavior

There are long periods of time where either getPVT() returns false or the callback method doesn't fire.

@PaulZC
Copy link
Collaborator

PaulZC commented Sep 17, 2024

Hi @jordancth ,

Please try adding the following. By default, both GNSS will be outputting the standard NMEA messages on UART1. Disabling them will help.

fwdGPS.setUART1Output(COM_TYPE_UBX); // Disable NMEA on UART1
revGPS.setUART1Output(COM_TYPE_UBX); // Disable NMEA on UART1

I don't recommend calling getPVT in the RELPOSNED callback. Ideally, PVT should have its own callback. But PVT is "auto" (periodic) so this shouldn't be generating any extra bus traffic.

Let's quickly estimate how much traffic is on the I2C bus:

  • fwd (Rover) is outputting PVT (100 bytes) and RELPOSNED (64 bytes) at 5Hz
  • rev (Base) is outputting PVT (100 bytes) at 5Hz and MSM4 (1074, 1084, 1094, 1124; 169+Nsat*(18+49*Nsig); 450 bytes (3593/8) for Nsat=16, Nsig=4) 1230 (4 + 2 * 4 bytes max) 4072 (variable length; maximum is 1023+6 bytes)

At 100kHz, the bus can support perhaps 5-8kBytes per second (with overheads). I suspect you are exceeding what the I2C bus can support... Increasing to 400kHz will help: Wire.setClock(400000);

Do you need to output RTCM at the full rate? Try reducing the rate:

revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_UART2, 5); // Reduce output rate to 1/5

Let me know if this helps,
Paul

@jordancth
Copy link
Author

Thanks for your help, @PaulZC.

I think disabling NMEA on UART1 and increasing the clock speed to 400 kHz fixed the problem I was having, or at least reduced the severity. It will still happen sometimes, but only lasts for up to 5-6 seconds at most.

I did try reducing the rate of the RTCM to 1/5, but that led to most of the RELPOSNED data being zero, with the exception of some flags. Even reducing output rate to 1/2 didn't work for me; I did get data, but it was way off and never changed.

I also tried moving getPVT to its own callback, but I noticed that there would be stretches of time (maybe around 10 seconds) where only the revGPS's PVT callback would fire, and the other two callbacks (fwdGPS PVT and RELPOSNED) wouldn't. Not too sure why the revGPS unit would get data more often than the fwdGPS unit.

Let me know if you have any other suggestions. Otherwise, I'm happy to close this issue.

@PaulZC
Copy link
Collaborator

PaulZC commented Sep 18, 2024

Hi @jordancth ,

Ah! You might have an issue with the way you are calling the Base revGPS.getPVT from inside the Rover fwdGPS RELPOSNED callback. That could be stalling the I2C bus, or causing fwd data to be lost... Maybe? I'd need to think this through a lot more...

Try adding revGPS.checkUblox(); in the loop. Does that help?

You're not using implicitUpdate on fwdGPS PVT. That means getPVT will always return false, and you need to call checkUblox manually. That's OK - you're aware of that. I see your comment in the code.

More suggestions:

Restructure your code so that you are using separate callbacks for fwd and rev PVT, and fwd RELPOSNED. The loop then needs to call checkUblox and checkCallbacks on both fwdGPS and revGPS.

Try using two I2C (Wire) ports, one for fwd and a second for rev. Does that help? (ESP32 supports two I2C ports.) You could then have separate threads running the fwd and rev instances, but that's really fancy and probably overkill for your application... (ESP32 supports threading. You can use threads on a single port, but you need to add a mutex so the two threads don't try to access the single port at the same time.)

I hope this helps,
Paul

@jordancth
Copy link
Author

jordancth commented Sep 19, 2024

Hi @PaulZC ,

Actually, going back to what you said previously, about calculating the traffic on the I2C bus, wouldn't the MSM4 and the RELPOSNED messages go through UART rather than I2C?

I did update my code to what is below:

#include <Wire.h>             // I2C needed for GPS-RTK2.
#include <SparkFun_u-blox_GNSS_v3.h> //http://librarymanager/All#SparkFun_u-blox_GNSS

SFE_UBLOX_GNSS fwdGPS;
SFE_UBLOX_GNSS revGPS;
const byte FWD_I2C_ADDRESS = 0x42;       
const byte REV_I2C_ADDRESS = 0x43;   

void setup() {
	delay(2000);
	Serial.begin(115200);
	Wire.begin();
	Wire.setClock(400000);

	if (fwdGPS.begin(Wire, FWD_I2C_ADDRESS) == false) //Connect to the Ublox module using Wire port
	{
        	Serial.println(F("Forward GPS not detected at 0x42 I2C address. Please check wiring or reprogram its address. Freezing."));
        	while (1);
	}
	fwdGPS.setUART1Output(COM_TYPE_UBX); // Disable NMEA on UART1
  	fwdGPS.setI2COutput(COM_TYPE_UBX);                    //Set the I2C port to output UBX only (turn off NMEA noise)
  	fwdGPS.setSerialRate(460800, COM_PORT_UART1);
  	fwdGPS.setSerialRate(460800, COM_PORT_UART2);
  	fwdGPS.setVal8(UBLOX_CFG_MSGOUT_UBX_NAV_RELPOSNED_UART1, 1);
  	fwdGPS.setNavigationFrequency(5);
  	fwdGPS.setAutoPVTcallbackPtr(&fwdPVTcallback);    
  	fwdGPS.setAutoRELPOSNEDcallbackPtr(&RELPOSNEDcallback);              
  	fwdGPS.saveConfiguration();                           //Save the current settings to flash and BBR

	if (revGPS.begin(Wire, REV_I2C_ADDRESS) == false) //Connect to the Ublox module using Wire port
    	{
        	Serial.println(F("Reverse GPS not detected at 0x43 I2C address. Please check wiring or reprogram its address. Freezing."));
        	while (1);
    	}
	revGPS.setUART1Output(COM_TYPE_UBX); // Disable NMEA on UART1
	revGPS.setI2COutput(COM_TYPE_UBX);                    //Set the I2C port to output UBX only (turn off NMEA noise)
    	revGPS.setSerialRate(460800, COM_PORT_UART1);
    	revGPS.setSerialRate(460800, COM_PORT_UART2);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_UART2, 1);
    	revGPS.setVal8(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE4072_0_UART2, 1);
    	revGPS.setNavigationFrequency(5);
    	revGPS.setAutoPVTcallbackPtr(&revPVTcallback); 
    	revGPS.saveConfiguration(); //Save the current settings to flash and BBR
    	revGPS.disableSurveyMode();
}

void RELPOSNEDcallback(UBX_NAV_RELPOSNED_data_t *ubxDataStruct){
  	if(ubxDataStruct->flags.bits.relPosValid && ubxDataStruct->flags.bits.relPosHeadingValid)
  	{
  		Serial.print("relPosN: ");
        	Serial.println((float)ubxDataStruct->relPosN / 100); 
        	Serial.print("relPosE: ");
        	Serial.println((float)ubxDataStruct->relPosE / 100);
		Serial.print("relPosHeading: ");
		Serial.println(ubxDataStruct->relPosHeading);
  	}
  	else
  	{
    		Serial.println("Either relPosValid or relPosHeadingValid were false");
  	}
}

void revPVTcallback(UBX_NAV_PVT_data_t *ubxDataStruct){
	Serial.print("Rear Latitude: ");
    	Serial.println(revGPS.getLatitude());
    	Serial.print("Rear Longitude: ");
  	Serial.println(revGPS.getLongitude());
}

void fwdPVTcallback(UBX_NAV_PVT_data_t *ubxDataStruct){
	Serial.print("Forward Latitude: ");
  	Serial.println(fwdGPS.getLatitude());
  	Serial.print("Forward Longitude: ");
  	Serial.println(fwdGPS.getLongitude());
}

void loop(){
	fwdGPS.checkUblox();
	fwdGPS.checkCallbacks();
	revGPS.checkUblox();
	revGPS.checkCallbacks();
}

Still having some minor issues. I've not yet tried using two I2C ports or multiple threads. I'll get back to you on that.

@PaulZC
Copy link
Collaborator

PaulZC commented Sep 20, 2024

Hi @jordancth ,

Yes, sorry, I got a bit carried away including the RTCM in the I2C traffic numbers. At least you have an indication of how much traffic UART2 is carrying...! ;-)

Do make sure you only have the PVT and RELPOSNED messages enabled. If you have something like RXM-RAWX enabled from earlier code, that would add an excess of traffic. I'd recommend doing a factoryDefault() on both modules; but, in your case, that's tricky with them sharing the same bus and defaulting to the same address. If you connect over USB, you can use u-center and UBX-CFG-CFG to restore the defaults, then CFG-PRT to modify the rev I2C address, then CFG-CFG to save the settings.

Your code looks good to me... It should be running fine at 5Hz. To dig further, you may need to put a logic analyzer on the bus and see how much traffic each is generating. We wrote a UBX analyzer for the Saleae Logic Pro, if you have access to one of those. It really helps figure out what's going on... You can have two analyzers running, one watching 0x42 and a second watching 0x43. I've done the same thing to debug traffic between the ZED-F9P and the NEO-D9S.

Please close this if you think we're done. Or leave it open if you need more suggestions. No problem either way.

All the best,
Paul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants