Bad GPS decoder on RAK WisBlock KIT 2 GPS TRACKER

Hello,
A few weeks ago I ordered a RAK WIS BLOC kit 2 GPS Tracker.
This kit is fitted with a u-blox ZOE-M8Q GNSS GPS module (RAK12500)
I loaded the arduino software from the link below,

The accelerometers work well, but when the USB socket position is vertical the GPS location does not work No location found! and bad GNSS decoding.

I tried to test only the GPS with dedicated arduino software ((RAK12500_GPS_ZOE-M8Q_IIC.ino), the GPS working very well, with accurate location.

I need help to solve this arduino problem (main soft with bad GPS decoder ??)

Thanks a lot for your help
Philip

In which slot did you place the RAK12500? The example firmware is using the serial communication to the u-Blox (originally written for the RAK1910) and works only when the RAK12500 is in Slot A or Slot D.

The RAK12500 u-Blox has both UART and I2C and works in any Sensor Slot.

You can try as well the RAK4631-Kit-2-RAK12500-RAK1906 example I made. I didn’t touch it for a year, but it should still work.

Hello Beegee,
Many thanks for your reply and I wish you the best for 2024 !.
I confirm the slot A for the RAK12500, and the slot D give the same results.
The RAK4631 with RAK 12500 gives good positioning using both slots.
I try to use your example (GitHub - beegee-tokyo/RAK4631-Kit-2-RAK12500-RAK1906: Example code for WisBlock GNSS tracker with RAK12500 GNSS module and RAK1906 environment sensor) but some difficulties with the compilation, many errors and I am not expert for arduino DEV.
It’s clear that the problem comes from arduino software used (see my first mail)
Could you give more details using your alternate proposal example, may be i forget ta add some libraries ?
Thanks in advance for your help.
Regards
Philippe

Let me double check the code, it is quite some time since I wrote and used it.

I guess you are on ArduinoIDE? I am never using ArduinoIDE (unless someone puts a gun to my head :rofl:)

You will need these libraries:

beegee-tokyo/SX126x-Arduino
sparkfun/SparkFun u-blox GNSS Arduino [email protected]
adafruit/Adafruit BME680 Library
beegee-tokyo/WisBlock-API

Thanks II will try,
Rgds

@Philippe

Found the problem on ArduinoIDE.

In the file environment.cpp replace line 12 with

#include "app.h"

In PIO it doesn’t matter if I use <app.h> or "app.h". Arduino IDE doesn’t like the first one.

I would like to confirm that the RAK GPS ZOE M8Q module is working Very good. However, there are a few challenges to programming this GPS module - it is very modern and needs to be extensively initialized to work well. In particular, this concerns the initialization of device modes. The SparkFun_u-blox_GNSS_Arduino_Library GPS ZOE M8Q library has several new functions that are often not used when writing Arduino programs. These are mode selection functions (pedestrian, wrist, airplane, etc.), as well as interference calculation and signal gain and selection of satellite systems The latter is very important, since “by default” support for all satellite systems is enabled, but the GPS ZOE M8Q only works with two (three) systems.
I tried to experiment with ZOE M8Q in Linux, where there is a very good program for working with this module. And wrote a few small functions to initialize ZOE M8Q. These all functions are mainly taken from the library SparkFun_u-blox_GNSS_Arduino_Library
Below I initialize the GPS module, which allows me to view the level of interference, as well as enable certain modes. This is an experimental program that I plan to embed into a program written in FreeRTOS soon using the Wisblock API library from Bernd Giesecke. In the program, you can select two (or three) satellite systems, operating mode (pedestrian, etc.), etc. (I’m currently writing AT commands for my module) I hope my message will be useful to someone.



/** FreeRTOS enabled (0 disable) */
#define FREERTOS_ENABLE 0
/** turn beeps on or off (0 disable) */
#define SOUND_ALERTS 0
/** Minimum satellite reception signal */
#define MINIMUM_LEVEL 0
/** Enable or disable NMEA message output (0 - disable) */
#define NMEA_SET 0
/** Enable debug GNSS (0 - disable) */
#define DEBUG_GNSS 1

/** Produce one solutions per second */
#define NAVIGATIONFREQUENCY 1
/** Produce a measurement every 1000ms */
#define MEASUREMENTRATE 1000
/** Set i2cPollingWait to 250ms */
#define I2CPOLLINGWAIT 250
/** Produce a navigation solution every measurement */
#define NAVIGATIONRATE 1
#include <Wire.h>		// Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>	// http:// librarymanager/All#SparkFun_u-blox_GNSS

SFE_UBLOX_GNSS myGNSS;

#if FREERTOS_ENABLE == 0
#define RAK_RTC_ID 0
/*** RTC date/time structure */
struct date_time_s {
    uint16_t year;
    uint8_t month;
    uint8_t weekday;
    uint8_t date;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
};

#define MYLOG(tag, ...) \
do \
{ \
if (tag) \
PRINTF("[%s] ", tag); \
PRINTF(__VA_ARGS__); \
PRINTF("\n"); \
} while (0)

#define AT_PRINTF(...) \
Serial.printf(__VA_ARGS__); \
if (g_ble_uart_is_connected) \
{ \
g_ble_uart.printf(__VA_ARGS__); \
}

#include "RAK12002_rtc.cpp"
#endif

#include <math.h>
//#include "NMEA.h"
#include "utilitiesGNSS.h"

/** Eurasia 0, Europe 1, Asia 2, Japan 3, Other 4 */
uint8_t observed_continent = 1;

bool setup_gnss()
{

/** Configuring GNSS Module Interrupts, These settings are only for Wisblock modules! */
#if FREERTOS_ENABLE == 0
    pinMode(WB_IO2, OUTPUT);
    digitalWrite(WB_IO2, LOW);
    delay(100);
#endif
    digitalWrite(WB_IO2, HIGH);
    delay(500);

    Wire.begin();

/** GNSS ZOE-M8Q I2C, connect to the u-blox module using Wire port */
    if (myGNSS.begin() == false)
      {
	  // u-blox GNSS not detected at default I2C address!
	  //Serial.print(F("u-blox GNSS not detected\n"));
	  MYLOG("GNSS", "u-blox GNSS not detected\n");
	  return false;
      }

    /*
     * Uncomment the next line if you need to completely reset your module
     * Reset everything and wait while the module restarts:
     * 0, factoryReset(); 1, hardReset(); 2, softwareResetGNSSOnly(); 3, factoryDefault()
     */
    // resetUnit(3, 500);

/** Uncomment this line to enable helpful debug messages on Serial */
// myGNSS.enableDebugging();

/**
* Disable or enable various NMEA sentences over the I2C interface
* Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
*/
//    if (NMEA_SET == 1)
//	myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX);
//    else
// Set the I2C port to output UBX only (turn off NMEA noise) 
	myGNSS.setI2COutput(COM_TYPE_UBX);


    myGNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS);
    setupGNSS(observed_continent);

/**
* Demonstrate get/setMeasurementRate and get/setNavigationRate
* We also disable NMEA output on the I2C bus and use only UBX.
* This dramatically decreases the amount of data that needs to be transmitted.
*/

    myGNSS.setNavigationFrequency(NAVIGATIONFREQUENCY);
// myGNSS.setNavigationFrequency(5); // Set output to 5 times a second 

/**
* The measurement rate is the elapsed time between GNSS measurements,
* which defines the rate e.g. 100 ms => 10 Hz, 1000 ms => 1 Hz,
* 10000 ms => 0.1 Hz. Let's set the measurement rate (interval) to
* 5 seconds = 5000 milliseconds
*/

/** Produce a measurement every 1000ms */
    if (myGNSS.setMeasurementRate(MEASUREMENTRATE) == false)
      {
	  MYLOG("GNSS", "Could not set the measurement rate\n");
	  return false;
      }

    /*
     * setMeasurementRate will set i2cPollingWait to a quarter of the interval
     * Let's override that so we can poll the module more frequently and avoid timeouts
     */

    /* Set i2cPollingWait to 250ms */
    myGNSS.setI2CpollingWait(I2CPOLLINGWAIT);

/**
* The navigation rate is the ratio between the number of measurements and
* the number of navigation solutions e.g. 5 means five measurements for
* every navigation solution. Maximum value is 127.
* Let's set the navigation rate (ratio) to 12 to produce a solution every minute
*/

/** Produce a navigation solution every measurement */
    if (myGNSS.setNavigationRate(NAVIGATIONRATE) == false)
      {
	  MYLOG("GNSS", "Could not set the navigation rate\n");
	  return false;
      }

						  /****** Wisblock PIN ******/
    /* PPS - 12 pin C WB_IO3 work PPS */
    pinMode(WB_IO3, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(WB_IO3),
		    interruptCallbackGPS, CHANGE);

    setup_timepulse();
    setup_dynmodel();

/** Setting up message output NMEA */
    if (NMEA_SET == 1)
      {
	  settingNMEA();
	  return true;
      }

    setup_jamming();

/** Save current configuration to flash and BBR (battery backed RAM) */
// myGNSS.saveConfiguration(uint16_t maxWait = defaultMaxWait);

/** Save the selected configuration sub-sections to flash and BBR (battery backed RAM) */
// myGNSS.saveConfigSelective(uint32_t configMask, uint16_t maxWait = defaultMaxWait);

/** Save (only) the communications port settings to flash and BBR */
// myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);


/************ Module setup GNSS ***********/

/** Tell the GNSS to "send" each solution */
// myGNSS.setAutoPVT(true);

/** Enable automatic NAV SAT messages with callback to newNAVSAT */
    myGNSS.setAutoNAVSATcallbackPtr(&newNAVSAT);

/** Enable automatic NAV PVT messages with callback to printPVTdata */
// myGNSS.setAutoPVTcallbackPtr(&printPVTdata);

/** Uncomment this line to reset the odometer */
// myGNSS.resetOdometer();
/** Enable automatic NAV ODO messages with callback to printODOdata */
// myGNSS.setAutoNAVODOcallbackPtr(&printODOdata);
    return true;
}


#if DEBUG_GNSS > 0
void setup()
{
/** Initialize Serial for debug output */
    time_t timeout = millis();
    Serial.begin(115200);
    while (!Serial)
      {
	  if ((millis() - timeout) < 5000)
	    {
		delay(100);
	  } else
	    {
		break;
	    }
      }
#if RAK_RTC_ID == 1 && FREERTOS_ENABLE == 0
    init_rak12002();
#endif
    setup_gnss();
    info_gnss();
    MYLOG("GNSS", "Module initialization completed\n");
}

void loop()
{
#if NMEA_SET == 1
    vievNMEA();
#else
// FreeRTOS timeshare emulation
    delay(1000);
    printUBX();
#endif
}
#endif



/**
* Disable or enable various NMEA sentences over the I2C interface
* Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
*/

void settingNMEA()
{
    myGNSS.enableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
    myGNSS.enableNMEAMessage(UBX_NMEA_ZDA, COM_PORT_I2C);
/**
* Set the mainTalkerId used by NMEA messages - allows all NMEA messages
* except GSV to be prefixed with GP instead of GN
* Prefix: · GP – GPS, GPGGA · GL – ГЛОНАСС, GLGGA · BD – BeiDou, BDGGA
* · GA – GALILEO, GAGGA · GN – GNGGA (multi)
*/

/**
* Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA
* instead of GNGGA
*/
// myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);

/** Uncomment this line to restore the default main talker ID */
    myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT);

/**
* Enable High Precision Mode - include extra decimal places in the GGA
* messages
*/
    myGNSS.setHighPrecisionMode(true);

/**
* Here's the advanced configure method
* Some of the other examples in this library enable the PVT message
* so let's disable it Message Class, ID, and port we want to configure,
* sendRate of 0 (disable).
*/
// myGNSS.configureMessage(UBX_CLASS_NAV, UBX_NAV_PVT, COM_PORT_UART1, 0);

/** Turn off UBX and RTCM sentences on the UART1 interface */
// myGNSS.setUART1Output(COM_TYPE_NMEA);

/** Set UART1 to 57600bps */
// myGNSS.setSerialRate(57600);

/**
* Messages configured. NMEA now being output over the UART1 port on the
* u-blox module at 57600bps.
*/

/** Optional: Save only the ioPort and message settings to NVM */
// myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF);

/** Uncomment this line to echo all NMEA data to Serial for debugging */
// myGNSS.setNMEAOutputPort(Serial);
}

void vievNMEA()
{
/** getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here */

/** Storage for the GPGGA data */
    NMEA_GGA_data_t dataGGA;
/** Get the latest GPGGA data (if any) */
    uint8_t result = myGNSS.getLatestNMEAGPGGA(&dataGGA);
    if (result == 2)
      {
	  // .nmea is printable (NULL-terminated)
	  Serial.print((const char *) dataGGA.nmea);
      }
/** GNGGA data */
    result = myGNSS.getLatestNMEAGNGGA(&dataGGA);
    if (result == 2)
      {
	  Serial.print((const char *) dataGGA.nmea);
      }
/** GPVTG data */
    NMEA_VTG_data_t dataVTG;
    result = myGNSS.getLatestNMEAGPVTG(&dataVTG);
    if (result == 2)
      {
	  Serial.print((const char *) dataVTG.nmea);
      }
/** GNVTG data */
    result = myGNSS.getLatestNMEAGNVTG(&dataVTG);
    if (result == 2)
      {
	  Serial.print((const char *) dataVTG.nmea);
      }
/** GPRMC data */
    NMEA_RMC_data_t dataRMC;
    result = myGNSS.getLatestNMEAGPRMC(&dataRMC);
    if (result == 2)
      {
	  Serial.print((const char *) dataRMC.nmea);
      }
/** GNRMC data */
    result = myGNSS.getLatestNMEAGNRMC(&dataRMC);
    if (result == 2)
      {
	  Serial.print((const char *) dataRMC.nmea);
      }
/** GPZDA data */
    NMEA_ZDA_data_t dataZDA;
    result = myGNSS.getLatestNMEAGPZDA(&dataZDA);
    if (result == 2)
      {
	  Serial.print((const char *) dataZDA.nmea);
      }
}


/**
* If we are going to change the dynamic platform model, let's do it here.
* Possible values are: PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, SEA,
* AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
*/
bool setup_dynmodel()
{
/** Set the dynamic model to PEDESTRIAN */
    if (myGNSS.setDynamicModel(DYN_MODEL_PEDESTRIAN) == false)
      {
	  MYLOG("GNSS", "Warning: setDynamicModel failed!");
	  return false;
      }
    return true;
}

void enableGNSS(bool QZSS, bool GLONASS, bool GALILEO, bool SBAS,
		bool BEIDOU, bool IMES)
{
    myGNSS.enableGNSS(QZSS, SFE_UBLOX_GNSS_ID_QZSS);
    myGNSS.enableGNSS(GLONASS, SFE_UBLOX_GNSS_ID_GLONASS);
    myGNSS.enableGNSS(GALILEO, SFE_UBLOX_GNSS_ID_GALILEO);
    myGNSS.enableGNSS(SBAS, SFE_UBLOX_GNSS_ID_SBAS);
    myGNSS.enableGNSS(BEIDOU, SFE_UBLOX_GNSS_ID_BEIDOU);
    myGNSS.enableGNSS(IMES, SFE_UBLOX_GNSS_ID_IMES);
}

void setupGNSS(uint8_t observed_continent)
{
/** QZSS GLONASS GALILEO SBAS BEIDOU IMES */

// Fast Eurasia, GPS + GLONASS
    if (observed_continent == 0)
      {
	  enableGNSS(false, true, false, false, false, false);
      }
// Europe, GPS + GLONASS + GALILEO
    if (observed_continent == 1)
      {
	  enableGNSS(false, true, true, false, false, false);
      }
// China, GPS + GLONASS + BEIDOU
    if (observed_continent == 2)
      {
	  enableGNSS(false, true, false, false, true, false);
      }
// Japan, GPS + QZSS + GLONASS
    if (observed_continent == 3)
      {
	  enableGNSS(true, true, false, false, false, false);
      }
// Other 
    if (observed_continent == 4)
      {
	  enableGNSS(true, true, true, true, true, true);
      }
}

bool setup_timepulse()
{
/** Create storage for the time pulse parameters */
    UBX_CFG_TP5_data_t timePulseParameters;

/** Version: */
// byte versionHigh = myGNSS.getProtocolVersionHigh();
// byte versionLow = myGNSS.getProtocolVersionLow();

/** Get the time pulse parameters */
    if (myGNSS.getTimePulseParameters(&timePulseParameters) == false)
      {
	  MYLOG("GNSS", "getTimePulseParameters failed! ");
	  return false;
      }

/** Select the TIMEPULSE pin */
    timePulseParameters.tpIdx = 0;

/**
* Let's say that we want our pulse-per-second to be as accurate as possible. So, let's tell the module
* to generate no signal while it is _locking_ to GNSS time. We want the signal to start only when the module is
* _locked_ to GNSS time.
*/
    timePulseParameters.freqPeriod = 0;	// Set the frequency/period to zero
    timePulseParameters.pulseLenRatio = 0;	// Set the pulse ratio to zero

/** When the module is _locked_ to GNSS time, make it generate a 0.1 second pulse once per second */
    timePulseParameters.freqPeriodLock = 1000000;	// Set the period to 1,000,000 us
    timePulseParameters.pulseLenRatioLock = 100000;	// Set the pulse length to 0.1s (100,000 us)
// timePulseParameters.pulseLenRatioLock = 1000000; // Set the pulse length to 1,000,000 us
    timePulseParameters.flags.bits.polarity = 1;	// Set the polarity to "1" (high for 0.1s, low for 0.9s, rising edge at top of second)


/** Make sure the active flag is set to enable the time pulse. (Set to 0 to disable.) */
    timePulseParameters.flags.bits.active = 1;
/** Tell the module to use freqPeriod while locking and freqPeriodLock when locked to GNSS time */
    timePulseParameters.flags.bits.lockedOtherSet = 1;
/** Tell the module that we want to set the period (not the frequency) */
    timePulseParameters.flags.bits.isFreq = 0;
/** Tell the module that pulseLenRatio is a length (in us) - not a duty cycle */
    timePulseParameters.flags.bits.isLength = 1;
/**
* Tell the module that we want the rising edge at the top of second.
* (Set to 0 for falling edge.)
*/
// timePulseParameters.flags.bits.polarity = 1;
/** Now set the time pulse parameters */
    if (myGNSS.setTimePulseParameters(&timePulseParameters) == false)
      {
	  MYLOG("GNSS", "setTimePulseParameters failed!");
	  return false;
      }
    return true;
}

/** Enable the jamming / interference monitor */
bool setup_jamming()
{
/** Create storage for the jamming configuration */
    UBX_CFG_ITFM_data_t jammingConfig;
/** Read the jamming configuration */
    if (myGNSS.getJammingConfiguration(&jammingConfig))
      {
	  /* Check if the monitor is already enabled */
	  if (jammingConfig.config.bits.enable == 0)
	    {
		/* Enable the monitor */
		jammingConfig.config.bits.enable = 1;
		/* Set the jamming configuration */
		if (myGNSS.setJammingConfiguration(&jammingConfig))
		    MYLOG("GNSS", "Enable the jamming");
		else
		    MYLOG("GNSS", "Error the jamming");
	    }
      }
    return true;
}