How To Set Up the RAK12500 with GNSS/GPS Module

KHM-082-00.png

Overview

RAK introduced RAK12500, a GNSS module featuring the u-blox ZOE-M8Q module, which truly talks to everybody: not only does it work with GPS, GLONASS, BeiDou, and QZSS, but it also works both with Serial and I2C. The latter may be a bit surprising, considering that I2C is often slower than serial, and you need to parse a whole lot of NMEA sentences. But, the SparkFun library takes care of everything and provided you with a rich API.

KHM-082-01.png

To help you get started, we have provided you with all the necessary documentation for your product and a code example.

One cool thing about GPS and the like is that they also carry the time, UTC. So, even without a real-time clock, you can maintain fairly accurate time, albeit in the UTC timezone. This can be useful when logging data (or sending it via LoRa). You can recalculate the proper local time using a library like Timezone_Generic or semi-manually.

I am in Hong Kong, GMT + 7, with no summer/winter time, so it is pretty easy. (You may see different results.) And once you get a fix, the GNSS module's RTC keeps the time updated, even if you have no satellites in view, as long as it is powered on.

Having your location is useful when you're doing LoRa distance tests and geolocation: when you get a ping, you create a log entry, with the time and coordinates, and you can also display (and log) the distance with the haversine formula. I've been using this to calculate the distance between the sender and the receiver. My senders add the "home" location to their json packets.

Altitude and BM(PE)280

But there's something else I've been making great use of that's not related to distance testing. In Hong Kong, the Observatory, HKO, has a poor-man's API for data from their stations. So, if you're in Hong Kong and using a BMP280 or BME280 like me, you'll get pressure from the device. Most libraries offer a faulty function to calculate altitude. It is based on an artificial Mean Sea Level Pressure, which probably has nothing to do with reality.

KHM-082-02.png

I explained this in my PR for a fix for SeeedStudio's BMP280 library – noting that it was the case for BME280, but they never fixed it in the other library.

So, now that I had an accurate method for calculating altitude, I needed a reference MSL Pressure to work. This is where having the haversine formula comes into play: with the location of all HKO stations known, it is child's play to decide which station is closest to you and get that station's MSL Pressure from the text version. This requires an Internet connection – which isn't available on a RAK4630, but we have a couple of solutions: either add a RAK2305 WisBlock Wi-Fi Interface Module, which gives you WiFi, or a RAK5860 WisBlock NB-IoT Interface Module for NB-IoT. The latter module also gives you GNSS, so that's a bit overkill.

I took a slightly different approach, using a BLE connection to my phone and an Android Cordova app to log the pings and provide services to the device, such as getting MSL Pressure from HKO, time sync, GNSS when the device lacks a module, and so on. This may be discussed in another article – for now, we're talking RAK12500.

Setting Up

Install the GNSS library.

#include <Wire.h> // Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
// http://librarymanager/All#SparkFun_u-blox_GNSS

I'm quoting first the code from the example mentioned above because there's a neat trick in recent versions of the Arduino IDE. If you make a comment with an HTTP link starting with http://librarymanager/All#SparkFun_u-blox_GNSS, followed by the name of the library, or a good search term, it opens the library manager for you and searches. As you can see below, there are actually two libraries with the same name – the first is labeled DEPRECATED. Install the other one.

KHM-082-03.png

When this is installed, you can start coding. You need to instantiate a GNSS object, and in setup(), initialize it:

SFE_UBLOX_GNSS g_myGNSS;
void setup() {
    pinMode(WB_IO2, OUTPUT);
    digitalWrite(WB_IO2, 0);
    delay(1000);
    digitalWrite(WB_IO2, 1);
    delay(1000);
    // This turns on the device on slots A/B
    [...]
    if (g_myGNSS.begin() == false) {
    //Connect to the u-blox module using Wire port
    Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing. oled.println(F("u-blox GNSS not detected.\nCheck wiring.\nFreezing."));
    while (1);
    }

    g_myGNSS.setI2COutput(COM_TYPE_UBX);
    // Sets the I2C port to output UBX only (turns off NMEA noise)
    g_myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
    // Saves (only) the communications port settings to flash and BBR

In loop(), whenever you are ready to get coordinates and other satellite information, grab the data from the module. As mentioned, the library does all the parsing for you. You just need to get the information you want. SIV is very important: if it's zero, there are no available GNSS signals, but the time might still be accurate, which can be verified with getTimeValid().

long latitude = g_myGNSS.getLatitude();
long longitude = g_myGNSS.getLongitude();
long altitude = g_myGNSS.getAltitude();
long speed = g_myGNSS.getGroundSpeed();
long heading = g_myGNSS.getHeading();
byte SIV = g_myGNSS.getSIV();
// Satellites In View: how many satellites the module is getting a fix from
bool isTimeValid = g_myGNSS.getTimeValid();
// Do we have valid datetime info?

We have a WisBlock RTC module, RAK12002, but I haven't received it yet, so I was thinking I should introduce instead a module I do have, the magnifico one-stop-shop WisBlock Sensor Adapter Module, RAK1920.

KHM-082-04.png

You need to connect a Grove module or two. The following can be used:

  • I2C or one-wire or two-wire
  • Adafruit's Stemma, aka Sparkfun Qwiic
  • Mikroe sensor, with their weird but convenient connector reminiscent of Zigbee. This is what we'll use for this case.

Previously, I did a survey of the competition, which means I have sensors from various companies, including a Mikroe RTC 10 Click. Let's use this today.

KHM-082-05.png

The little package in front is a RAK15000, an EEPROM module. This will come in handy when we reach a level where we need to store preferences and other data. I am porting right now the Minimal_LoRa firmware I wrote for BastWAN, and this EEPROM module will be perfect for this.

In between, the code is on GitHub. Below is the image of it in action. The altitude is a bit off, later on it recalibrated itself to 157 meters, which sounds just about right. It had 12 SIV, which is probably the most I ever had.

KHM-082-06.png

Updated