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

Commit 98a957f

Browse files
authored
Merge pull request #162 from sparkfun/NTRIPServerExample
Add example showing NTRIP Server on ESP32
2 parents 0b48d58 + 6b01e8f commit 98a957f

File tree

2 files changed

+281
-0
lines changed

2 files changed

+281
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/*
2+
Use ESP32 WiFi to push RTCM data to RTK2Go (caster) as a Server
3+
By: SparkFun Electronics / Nathan Seidle
4+
Date: December 14th, 2020
5+
License: MIT. See license file for more information but you can
6+
basically do whatever you want with this code.
7+
8+
This example shows how to gather RTCM data over I2C and push it to a casting service over WiFi.
9+
It's confusing, but the Arduino is acting as a 'server' to a 'caster'. In this case we will
10+
use RTK2Go.com as our caster because it is free. A rover (car, surveyor stick, etc) can
11+
then connect to RTK2Go as a 'client' and get the RTCM data it needs.
12+
13+
You will need to register your mountpoint here: http://www.rtk2go.com/new-reservation/
14+
(They'll probably block the credentials we include in this example)
15+
16+
To see if your mountpoint is active go here: http://rtk2go.com:2101/
17+
18+
This is a proof of concept. Serving RTCM to a caster over WiFi is useful when you need to
19+
set up a high-precision base station.
20+
21+
Feel like supporting open source hardware?
22+
Buy a board from SparkFun!
23+
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
24+
RTK Surveyor: https://www.sparkfun.com/products/17369
25+
26+
Hardware Connections:
27+
Plug a Qwiic cable into the GPS and a ESP32 Thing Plus
28+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
29+
Open the serial monitor at 115200 baud to see the output
30+
*/
31+
32+
#include <WiFi.h>
33+
#include "secrets.h"
34+
WiFiClient client;
35+
36+
#include <Wire.h> //Needed for I2C to GPS
37+
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
38+
SFE_UBLOX_GPS myGPS;
39+
40+
//Basic Connection settings to RTK2Go NTRIP Caster - See secrets for mount specific credentials
41+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
42+
const uint16_t casterPort = 2101;
43+
const char * casterHost = "rtk2go.com";
44+
const char * ntrip_server_name = "SparkFun_RTK_Surveyor";
45+
46+
long lastSentRTCM_ms = 0; //Time of last data pushed to socket
47+
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
48+
49+
uint32_t serverBytesSent = 0; //Just a running total
50+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
51+
52+
long lastReport_ms = 0; //Time of last report of bytes sent
53+
54+
void setup()
55+
{
56+
Serial.begin(115200); // You may need to increase this for high navigation rates!
57+
while (!Serial)
58+
; //Wait for user to open terminal
59+
Serial.println(F("SparkFun u-blox Example"));
60+
61+
Wire.begin();
62+
63+
//myGPS.enableDebugging(); // Uncomment this line to enable debug messages
64+
65+
if (myGPS.begin() == false) //Connect to the u-blox module using Wire port
66+
{
67+
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
68+
while (1)
69+
;
70+
}
71+
72+
Serial.print("Connecting to local WiFi");
73+
WiFi.begin(ssid, password);
74+
while (WiFi.status() != WL_CONNECTED) {
75+
delay(500);
76+
Serial.print(".");
77+
}
78+
79+
Serial.print("\nWiFi connected with IP: ");
80+
Serial.println(WiFi.localIP());
81+
82+
myGPS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //UBX+RTCM3 is not a valid option so we enable all three.
83+
84+
myGPS.setNavigationFrequency(1); //Set output in Hz. RTCM rarely benefits from >1Hz.
85+
86+
//Disable all NMEA sentences
87+
bool response = true;
88+
response &= myGPS.disableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
89+
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
90+
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
91+
response &= myGPS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
92+
response &= myGPS.disableNMEAMessage(UBX_NMEA_GST, COM_PORT_I2C);
93+
response &= myGPS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
94+
response &= myGPS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
95+
96+
if (response == false)
97+
{
98+
Serial.println(F("Failed to disable NMEA. Freezing..."));
99+
while (1);
100+
}
101+
else
102+
Serial.println(F("NMEA disabled"));
103+
104+
//Enable necessary RTCM sentences
105+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through UART2, message every second
106+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1074, COM_PORT_I2C, 1);
107+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1084, COM_PORT_I2C, 1);
108+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1094, COM_PORT_I2C, 1);
109+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1124, COM_PORT_I2C, 1);
110+
response &= myGPS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
111+
112+
if (response == false)
113+
{
114+
Serial.println(F("Failed to enable RTCM. Freezing..."));
115+
while (1);
116+
}
117+
else
118+
Serial.println(F("RTCM sentences enabled"));
119+
120+
//-1280208.308,-4716803.847,4086665.811 is SparkFun HQ so...
121+
//Units are cm with a high precision extension so -1234.5678 should be called: (-123456, -78)
122+
//For more infomation see Example12_setStaticPosition
123+
//Note: If you leave these coordinates in place and setup your antenna *not* at SparkFun, your receiver
124+
//will be very confused and fail to generate correction data because, well, you aren't at SparkFun...
125+
//See this tutorial on getting PPP coordinates: https://learn.sparkfun.com/tutorials/how-to-build-a-diy-gnss-reference-station/all
126+
response &= myGPS.setStaticPosition(-128020830, -80, -471680384, -70, 408666581, 10); //With high precision 0.1mm parts
127+
if (response == false)
128+
{
129+
Serial.println(F("Failed to enter static position. Freezing..."));
130+
while (1);
131+
}
132+
else
133+
Serial.println(F("Static position set"));
134+
135+
//You could instead do a survey-in but it takes much longer to start generating RTCM data. See Example4_BaseWithLCD
136+
//myGPS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
137+
138+
if (myGPS.saveConfiguration() == false) //Save the current settings to flash and BBR
139+
Serial.println(F("Module failed to save."));
140+
141+
Serial.println(F("Module configuration complete"));
142+
}
143+
144+
void loop()
145+
{
146+
if (Serial.available()) beginServing();
147+
148+
Serial.println(F("Press any key to start serving."));
149+
150+
delay(1000);
151+
}
152+
153+
void beginServing()
154+
{
155+
Serial.println("Xmit to RTK2Go. Press any key to stop");
156+
delay(10); //Wait for any serial to arrive
157+
while (Serial.available()) Serial.read(); //Flush
158+
159+
while (Serial.available() == 0)
160+
{
161+
//Connect if we are not already
162+
if (client.connected() == false)
163+
{
164+
Serial.printf("Opening socket to %s\n", casterHost);
165+
166+
if (client.connect(casterHost, casterPort) == true) //Attempt connection
167+
{
168+
Serial.printf("Connected to %s:%d\n", casterHost, casterPort);
169+
170+
const int SERVER_BUFFER_SIZE = 512;
171+
char serverBuffer[SERVER_BUFFER_SIZE];
172+
173+
snprintf(serverBuffer, SERVER_BUFFER_SIZE, "SOURCE %s /%s\r\nSource-Agent: NTRIP %s/%s\r\n\r\n",
174+
mntpnt_pw, mntpnt, ntrip_server_name, "App Version 1.0");
175+
176+
Serial.printf("Sending credentials:\n%s\n", serverBuffer);
177+
client.write(serverBuffer, strlen(serverBuffer));
178+
179+
//Wait for response
180+
unsigned long timeout = millis();
181+
while (client.available() == 0)
182+
{
183+
if (millis() - timeout > 5000)
184+
{
185+
Serial.println(">>> Client Timeout !");
186+
client.stop();
187+
return;
188+
}
189+
delay(10);
190+
}
191+
192+
//Check reply
193+
bool connectionSuccess = false;
194+
char response[512];
195+
int responseSpot = 0;
196+
while (client.available())
197+
{
198+
response[responseSpot++] = client.read();
199+
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
200+
connectionSuccess = true;
201+
if (responseSpot == 512 - 1) break;
202+
}
203+
response[responseSpot] = '\0';
204+
205+
if (connectionSuccess == false)
206+
{
207+
Serial.printf("Failed to connect to RTK2Go: %s", response);
208+
}
209+
} //End attempt to connect
210+
else
211+
{
212+
Serial.println("Connection to host failed");
213+
}
214+
} //End connected == false
215+
216+
if (client.connected() == true)
217+
{
218+
delay(10);
219+
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
220+
221+
lastReport_ms = millis();
222+
lastSentRTCM_ms = millis();
223+
224+
//This is the main sending loop. We scan for new ublox data but processRTCM() is where the data actually gets sent out.
225+
while (1)
226+
{
227+
if (Serial.available()) break;
228+
229+
myGPS.checkUblox(); //See if new data is available. Process bytes as they come in.
230+
231+
//Close socket if we don't have new data for 10s
232+
//RTK2Go will ban your IP address if you abuse it. See http://www.rtk2go.com/how-to-get-your-ip-banned/
233+
//So let's not leave the socket open/hanging without data
234+
if (millis() - lastSentRTCM_ms > maxTimeBeforeHangup_ms)
235+
{
236+
Serial.println("RTCM timeout. Disconnecting...");
237+
client.stop();
238+
return;
239+
}
240+
241+
delay(10);
242+
243+
//Report some statistics every 250
244+
if (millis() - lastReport_ms > 250)
245+
{
246+
lastReport_ms += 250;
247+
Serial.printf("Total sent: %d\n", serverBytesSent);
248+
}
249+
}
250+
}
251+
252+
delay(10);
253+
}
254+
255+
Serial.println("User pressed a key");
256+
Serial.println("Disconnecting...");
257+
client.stop();
258+
259+
delay(10);
260+
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
261+
}
262+
263+
//This function gets called from the SparkFun u-blox Arduino Library.
264+
//As each RTCM byte comes in you can specify what to do with it
265+
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
266+
void SFE_UBLOX_GPS::processRTCM(uint8_t incoming)
267+
{
268+
if (client.connected() == true)
269+
{
270+
client.write(incoming); //Send this byte to socket
271+
serverBytesSent++;
272+
lastSentRTCM_ms = millis();
273+
}
274+
}

Diff for: examples/ZED-F9P/Example14_NTRIPServer/secrets.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//Your WiFi credentials
2+
const char* ssid = "TRex";
3+
const char* password = "hasBigTeeth";
4+
5+
//Your RTK2GO mount point credentials
6+
const char* mntpnt_pw = "WR5wRo4H";
7+
const char* mntpnt = "bldr_dwntwn2";

0 commit comments

Comments
 (0)