Skip to content

Instantly share code, notes, and snippets.

@ksasao
Last active June 8, 2024 05:01
Show Gist options
  • Select an option

  • Save ksasao/5fa6174f2d1efd9f75277bdab009ab01 to your computer and use it in GitHub Desktop.

Select an option

Save ksasao/5fa6174f2d1efd9f75277bdab009ab01 to your computer and use it in GitHub Desktop.
M5StickC と u-blox ZED-F9P でRTK測位をするサンプル。M5StickCとZED-F9Pモジュールとの接続はI2C、RTCM3はAndroid スマホからの Bluetooth Serial 経由で受信する実装です。https://twitter.com/ksasao/status/1655098208903888901
#include <M5GFX.h>
#include <M5StickCPlus.h>
#include "BluetoothSerial.h"
#include <TinyGPS++.h>
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
SFE_UBLOX_GNSS myGNSS;
// Location of Destination
double destLat = 35.5000000;
double destLon = 139.6000000;
TinyGPSPlus gps; // for calculate distance
M5GFX display;
char txt[64];
// Bluetooth Serial
uint64_t chipid;
char chipname[256];
BluetoothSerial SerialBT;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Used for GGA sentence parsing from incoming NMEA
bool ggaSentenceStarted = false;
bool ggaSentenceComplete = false;
bool ggaTransmitComplete = true; //Goes true once we transmit GGA to the caster
char ggaSentence[128] = {0};
byte ggaSentenceSpot = 0;
int ggaSentenceEndSpot = 0;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void drawText(double meter, int fix){
bool isKilo = true;
display.setTextColor(TFT_WHITE, TFT_BLACK);
display.setTextWrap(false);
display.setTextDatum(textdatum_t::top_right);
display.setTextSize(0.75,1);
display.setFont(&fonts::Font8);
if(meter<0 || meter > 9999.9 * 1000.0){
sprintf(txt," -----");
}else if (meter > 999.99*1000.0){ // 1000km以上
sprintf(txt," %.1f", meter/1000.0);
}else if (meter > 99.999*1000.0){ // 100km以上
sprintf(txt," %.2f", meter/1000.0);
}else if (meter > 9.9999*1000.0){ // 10km以上
sprintf(txt," %.3f", meter/1000.0);
}else if (meter > 999.99){ // 1km以上
isKilo = false;
sprintf(txt," %.1f", meter);
}else{
isKilo = false;
sprintf(txt," %.2f", meter);
}
display.drawString(txt, 235,10);
display.setFont(&fonts::lgfxJapanGothic_40);
if(isKilo){
display.drawString("km", 230,85);
}else{
display.drawString(" m", 230,85);
}
display.setTextDatum(textdatum_t::top_left);
if(fix == 1){
sprintf(txt,"Floating ");
}else if(fix == 2){
sprintf(txt,"Fix ");
}else{
sprintf(txt,"None ");
}
display.drawString(txt, 5,85);
}
void updateStatus(double lat, double lon, int fix){
double distance = -1;
distance =
TinyGPSPlus::distanceBetween(
lat,
lon,
destLat,
destLon);
if (!display.displayBusy())
{
display.startWrite();
drawText(distance,fix);
display.endWrite();
}
}
void setup()
{
M5.begin();
Serial.begin(115200);
Serial.println(F("Receive RTCM3 via Bluetooth Serial for RTK positioning"));
Wire.begin(); //Start I2C
Wire.setClock(80000);
delay(2000); // wait a second
Serial.print("Location of Destination: ");
Serial.print(destLat,7);
Serial.print(",");
Serial.print(destLon,7);
Serial.println();
display.init();
display.setRotation(1);
updateStatus(0,0,0);
Serial.println("Started.");
while (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring or wait a mitune."));
delay(2000);
}
Serial.println(F("u-blox module connected"));
// Set F9P
myGNSS.setI2COutput(COM_TYPE_UBX| COM_TYPE_NMEA); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3);
myGNSS.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // // Set the differential mode - ambiguities are fixed whenever possible
myGNSS.setNavigationFrequency(1);
// 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);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); //Verify the GGA sentence is enabled
myGNSS.setAutoPVT(true);
myGNSS.setI2CTransactionSize(128);
//myGNSS.enableDebugging();
// Bluetooth Serial
chipid = ESP.getEfuseMac();
sprintf( chipname, "M5RTK_%04X", (uint16_t)(chipid >> 32));
Serial.printf("Bluetooth: %s\n", chipname);
SerialBT.begin(chipname);
while (Serial.available()) // Empty the serial buffer
Serial.read();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long last = 0;
size_t rtcmCount = 0;
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
void loop()
{
M5.update();
//Collect any available RTCM data
while (SerialBT.available())
{
rtcmData[rtcmCount++] = SerialBT.read();
if (rtcmCount == sizeof(rtcmData)){
rtcmCount = 0;
break;
}
}
// BluetoothSerialのバッファサイズは512バイト固定だが、
// F9P への I2C 経由でのRTCM3データ送信は 1Kバイト程度を連続的に
// 行わないとFix解が得られないためバッファリングしてまとめて転送する
if (rtcmCount > 1024)
{
//Push RTCM to GNSS module over I2C
myGNSS.pushRawData(rtcmData, rtcmCount);
Serial.print(F("Pushed "));
Serial.print(rtcmCount);
Serial.println(F(" RTCM bytes to ZED"));
rtcmCount = 0;
}
long now = millis();
if (now-last>1000)// || myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false))
{
myGNSS.checkUblox(); // Check for the arrival of new GNSS data and process it.
last = now;
if(ggaSentenceComplete){
Serial.println(ggaSentence);
SerialBT.println(ggaSentence);
ggaTransmitComplete = true;
ggaSentenceComplete = false;
}
printNmeaData();
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void printNmeaData()
{
char buff[256];
int year = myGNSS.getYear();
int month = myGNSS.getMonth();
int day = myGNSS.getDay();
int hour = myGNSS.getHour();
int minute = myGNSS.getMinute();
int sec = myGNSS.getSecond();
int msec = myGNSS.getMillisecond();
double lat = myGNSS.getLatitude() / 10000000.0;
double lon = myGNSS.getLongitude() / 10000000.0;
double alt = myGNSS.getAltitude() / 1000.0;
double altMSL = myGNSS.getAltitudeMSL() / 1000.0;
double geoid = alt - altMSL;
int fixType = myGNSS.getFixType(); //0=no fix, 1=dead reckoning, 2=2D, 3=3D, 4=GNSS, 5=Time fix
int rtk = myGNSS.getCarrierSolutionType(); //0=No solution, 1=Float solution, 2=Fixed solution
long accuracy = myGNSS.getPositionAccuracy();
updateStatus(lat,lon,rtk);
Serial.print("Lat: ");
Serial.print(lat,7);
Serial.print(" Lon: ");
Serial.print(lon,7);
Serial.print(" Fix: ");
Serial.print(fixType);
Serial.print(" RTK: ");
Serial.print(rtk);
Serial.print(" Accuracy: ");
Serial.print(accuracy);
Serial.print(" mm");
Serial.println();
}
//This function gets called from the SparkFun u-blox Arduino Library
//As each NMEA character comes in you can specify what to do with it
//We will look for and copy the GGA sentence
void SFE_UBLOX_GNSS::processNMEA(char incoming)
{
//Serial.print(incoming);
//Take the incoming char from the u-blox I2C port and check to see if we should record it or not
if (incoming == '$' && ggaTransmitComplete == true)
{
ggaSentenceStarted = true;
ggaSentenceSpot = 0;
ggaSentenceEndSpot = sizeof(ggaSentence);
ggaSentenceComplete = false;
}
if (ggaSentenceStarted == true)
{
ggaSentence[ggaSentenceSpot++] = incoming;
//Make sure we don't go out of bounds
if (ggaSentenceSpot == sizeof(ggaSentence))
{
//Start over
ggaSentenceStarted = false;
}
else if (incoming == '*')
{
//We're near the end. Keep listening for two more bytes to complete the CRC
ggaSentenceEndSpot = ggaSentenceSpot + 2;
}
else if (ggaSentenceSpot == ggaSentenceEndSpot){
if(strncmp(ggaSentence+3,"GGA",3) == 0){
ggaSentence[ggaSentenceSpot] = '\0'; //Terminate this string
ggaSentenceComplete = true;
ggaTransmitComplete = false; //We are ready for transmission
ggaSentenceStarted = false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment