Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Add example showing NTRIP Server on ESP32 #162

Merged
merged 1 commit into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 274 additions & 0 deletions examples/ZED-F9P/Example14_NTRIPServer/Example14_NTRIPServer.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
/*
Use ESP32 WiFi to push RTCM data to RTK2Go (caster) as a Server
By: SparkFun Electronics / Nathan Seidle
Date: December 14th, 2020
License: MIT. See license file for more information but you can
basically do whatever you want with this code.

This example shows how to gather RTCM data over I2C and push it to a casting service over WiFi.
It's confusing, but the Arduino is acting as a 'server' to a 'caster'. In this case we will
use RTK2Go.com as our caster because it is free. A rover (car, surveyor stick, etc) can
then connect to RTK2Go as a 'client' and get the RTCM data it needs.

You will need to register your mountpoint here: http://www.rtk2go.com/new-reservation/
(They'll probably block the credentials we include in this example)

To see if your mountpoint is active go here: http://rtk2go.com:2101/

This is a proof of concept. Serving RTCM to a caster over WiFi is useful when you need to
set up a high-precision base station.

Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
RTK Surveyor: https://www.sparkfun.com/products/17369

Hardware Connections:
Plug a Qwiic cable into the GPS and a ESP32 Thing Plus
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Open the serial monitor at 115200 baud to see the output
*/

#include <WiFi.h>
#include "secrets.h"
WiFiClient client;

#include <Wire.h> //Needed for I2C to GPS
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
SFE_UBLOX_GPS myGPS;

//Basic Connection settings to RTK2Go NTRIP Caster - See secrets for mount specific credentials
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const uint16_t casterPort = 2101;
const char * casterHost = "rtk2go.com";
const char * ntrip_server_name = "SparkFun_RTK_Surveyor";

long lastSentRTCM_ms = 0; //Time of last data pushed to socket
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster

uint32_t serverBytesSent = 0; //Just a running total
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

long lastReport_ms = 0; //Time of last report of bytes sent

void setup()
{
Serial.begin(115200); // You may need to increase this for high navigation rates!
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));

Wire.begin();

//myGPS.enableDebugging(); // Uncomment this line to enable debug messages

if (myGPS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}

Serial.print("Connecting to local WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.print("\nWiFi connected with IP: ");
Serial.println(WiFi.localIP());

myGPS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //UBX+RTCM3 is not a valid option so we enable all three.

myGPS.setNavigationFrequency(1); //Set output in Hz. RTCM rarely benefits from >1Hz.

//Disable all NMEA sentences
bool response = true;
response &= myGPS.disableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GST, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);

if (response == false)
{
Serial.println(F("Failed to disable NMEA. Freezing..."));
while (1);
}
else
Serial.println(F("NMEA disabled"));

//Enable necessary RTCM sentences
response &= myGPS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through UART2, message every second
response &= myGPS.enableRTCMmessage(UBX_RTCM_1074, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1084, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1094, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1124, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds

if (response == false)
{
Serial.println(F("Failed to enable RTCM. Freezing..."));
while (1);
}
else
Serial.println(F("RTCM sentences enabled"));

//-1280208.308,-4716803.847,4086665.811 is SparkFun HQ so...
//Units are cm with a high precision extension so -1234.5678 should be called: (-123456, -78)
//For more infomation see Example12_setStaticPosition
//Note: If you leave these coordinates in place and setup your antenna *not* at SparkFun, your receiver
//will be very confused and fail to generate correction data because, well, you aren't at SparkFun...
//See this tutorial on getting PPP coordinates: https://learn.sparkfun.com/tutorials/how-to-build-a-diy-gnss-reference-station/all
response &= myGPS.setStaticPosition(-128020830, -80, -471680384, -70, 408666581, 10); //With high precision 0.1mm parts
if (response == false)
{
Serial.println(F("Failed to enter static position. Freezing..."));
while (1);
}
else
Serial.println(F("Static position set"));

//You could instead do a survey-in but it takes much longer to start generating RTCM data. See Example4_BaseWithLCD
//myGPS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m

if (myGPS.saveConfiguration() == false) //Save the current settings to flash and BBR
Serial.println(F("Module failed to save."));

Serial.println(F("Module configuration complete"));
}

void loop()
{
if (Serial.available()) beginServing();

Serial.println(F("Press any key to start serving."));

delay(1000);
}

void beginServing()
{
Serial.println("Xmit to RTK2Go. Press any key to stop");
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush

while (Serial.available() == 0)
{
//Connect if we are not already
if (client.connected() == false)
{
Serial.printf("Opening socket to %s\n", casterHost);

if (client.connect(casterHost, casterPort) == true) //Attempt connection
{
Serial.printf("Connected to %s:%d\n", casterHost, casterPort);

const int SERVER_BUFFER_SIZE = 512;
char serverBuffer[SERVER_BUFFER_SIZE];

snprintf(serverBuffer, SERVER_BUFFER_SIZE, "SOURCE %s /%s\r\nSource-Agent: NTRIP %s/%s\r\n\r\n",
mntpnt_pw, mntpnt, ntrip_server_name, "App Version 1.0");

Serial.printf("Sending credentials:\n%s\n", serverBuffer);
client.write(serverBuffer, strlen(serverBuffer));

//Wait for response
unsigned long timeout = millis();
while (client.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
delay(10);
}

//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (client.available())
{
response[responseSpot++] = client.read();
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
connectionSuccess = true;
if (responseSpot == 512 - 1) break;
}
response[responseSpot] = '\0';

if (connectionSuccess == false)
{
Serial.printf("Failed to connect to RTK2Go: %s", response);
}
} //End attempt to connect
else
{
Serial.println("Connection to host failed");
}
} //End connected == false

if (client.connected() == true)
{
delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns

lastReport_ms = millis();
lastSentRTCM_ms = millis();

//This is the main sending loop. We scan for new ublox data but processRTCM() is where the data actually gets sent out.
while (1)
{
if (Serial.available()) break;

myGPS.checkUblox(); //See if new data is available. Process bytes as they come in.

//Close socket if we don't have new data for 10s
//RTK2Go will ban your IP address if you abuse it. See http://www.rtk2go.com/how-to-get-your-ip-banned/
//So let's not leave the socket open/hanging without data
if (millis() - lastSentRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println("RTCM timeout. Disconnecting...");
client.stop();
return;
}

delay(10);

//Report some statistics every 250
if (millis() - lastReport_ms > 250)
{
lastReport_ms += 250;
Serial.printf("Total sent: %d\n", serverBytesSent);
}
}
}

delay(10);
}

Serial.println("User pressed a key");
Serial.println("Disconnecting...");
client.stop();

delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
}

//This function gets called from the SparkFun u-blox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GPS::processRTCM(uint8_t incoming)
{
if (client.connected() == true)
{
client.write(incoming); //Send this byte to socket
serverBytesSent++;
lastSentRTCM_ms = millis();
}
}
7 changes: 7 additions & 0 deletions examples/ZED-F9P/Example14_NTRIPServer/secrets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//Your WiFi credentials
const char* ssid = "TRex";
const char* password = "hasBigTeeth";

//Your RTK2GO mount point credentials
const char* mntpnt_pw = "WR5wRo4H";
const char* mntpnt = "bldr_dwntwn2";