Skip to content

Commit 2f6767b

Browse files
authored
Merge pull request #103 from mazgch/mazgch-add-pointperfect
PointPerfect example using WIFI/IP/MQTT
2 parents 081c9cb + 25ab860 commit 2f6767b

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
Use ESP32 WiFi to get SPARTN data from PointPerfect (broker) as a Client
3+
By: u-blox AG / Michael Ammann
4+
Date: January 27th, 2022
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 obtain SPARTN data from a PointPerfect Broker over WiFi
9+
and push it over I2C to a ZED-F9x.
10+
It's confusing, but the Arduino is acting as a 'client' to the PointPerfect SSR correction service.
11+
12+
You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan.
13+
Thingstream offers SSR corrections to SPARTN cabalble RTK receivers such as the u-blox ZED-F9 series
14+
in continental Europ and US. There Network is planned to be expanded to ther regions over next years.
15+
To see sign up go to https://portal.thingstream.io/app/location-services/things
16+
17+
This is a proof of concept to show how to connect via MQTT to get SPARTN SSR correction.
18+
Using WiFi for a rover is generally a bad idea because of limited WiFi range in the field.
19+
You may use this exmaple in combination with a cell phone with hotspot mode enabled.
20+
21+
For more information about MQTT, SPARTN and PointPerfect Correction Services
22+
please see: https://www.u-blox.com/en/product/pointperfect
23+
24+
Feel like supporting open source hardware?
25+
Buy a board from SparkFun!
26+
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
27+
RTK Surveyor: https://www.sparkfun.com/products/18443
28+
RTK Express: https://www.sparkfun.com/products/18442
29+
30+
Recommended Hardware:
31+
MicroMod GNSS Carrier Board: https://www.sparkfun.com/products/17722
32+
ESP32 Micromod https://www.sparkfun.com/products/16781
33+
34+
Hardware Connections:
35+
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
36+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
37+
Open the serial monitor at 115200 baud to see the output
38+
*/
39+
#include <WiFi.h>
40+
#include <WiFiClientSecure.h>
41+
#include <ArduinoMqttClient.h>
42+
#include "secrets.h"
43+
44+
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
45+
SFE_UBLOX_GNSS myGNSS;
46+
47+
//Global variables
48+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
49+
long lastReceived_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
50+
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
51+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
52+
53+
void setup()
54+
{
55+
Serial.begin(115200);
56+
while (!Serial);
57+
Serial.println(F("PointPerfect testing"));
58+
59+
Wire.begin(); //Start I2C
60+
61+
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
62+
{
63+
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
64+
while (1);
65+
}
66+
67+
Serial.println(F("u-blox module connected"));
68+
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
69+
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN); // Be sure SPARTN input is enabled.
70+
71+
myGNSS.setNavigationFrequency(1); //Set output in Hz.
72+
Serial.print(F("Connecting to local WiFi"));
73+
WiFi.begin(ssid, password);
74+
while (WiFi.status() != WL_CONNECTED) {
75+
delay(500);
76+
Serial.print(F("."));
77+
}
78+
Serial.println();
79+
80+
Serial.print(F("WiFi connected with IP: "));
81+
Serial.println(WiFi.localIP());
82+
83+
while (Serial.available()) Serial.read();
84+
}
85+
86+
void loop()
87+
{
88+
if (Serial.available())
89+
{
90+
beginClient();
91+
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
92+
}
93+
94+
Serial.println(F("Press any key to start MQTT/SPARTN Client."));
95+
96+
delay(1000);
97+
}
98+
99+
WiFiClientSecure wifiClient = WiFiClientSecure();
100+
MqttClient mqttClient(wifiClient);
101+
102+
void mqttMessageHandler(int messageSize) {
103+
uint8_t spartnData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
104+
int spartnCount = 0;
105+
Serial.print(F("Pushed data from "));
106+
Serial.print(mqttClient.messageTopic());
107+
Serial.println(F(" topic to ZED"));
108+
while (mqttClient.available())
109+
{
110+
char ch = mqttClient.read();
111+
//Serial.write(ch); //Pipe to serial port is fine but beware, it's a lot of binary data
112+
spartnData[spartnCount++] = ch;
113+
if (spartnCount == sizeof(spartnData))
114+
break;
115+
}
116+
117+
if (spartnCount > 0)
118+
{
119+
//Push KEYS or SPARTN data to GNSS module over I2C
120+
myGNSS.pushRawData(spartnData, spartnCount, false);
121+
lastReceived_ms = millis();
122+
}
123+
}
124+
125+
//Connect to STARTN MQTT broker, receive RTCM, and push to ZED module over I2C
126+
void beginClient()
127+
{
128+
Serial.println(F("Subscribing to Broker. Press key to stop"));
129+
delay(10); //Wait for any serial to arrive
130+
while (Serial.available()) Serial.read(); //Flush
131+
132+
while (Serial.available() == 0)
133+
{
134+
//Connect if we are not already
135+
if (wifiClient.connected() == false)
136+
{
137+
// Connect to AWS IoT
138+
wifiClient.setCACert(AWS_CERT_CA);
139+
wifiClient.setCertificate(AWS_CERT_CRT);
140+
wifiClient.setPrivateKey(AWS_CERT_PRIVATE);
141+
if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) {
142+
Serial.print(F("MQTT connection failed! Error code = "));
143+
Serial.println(mqttClient.connectError());
144+
return;
145+
} else {
146+
Serial.println(F("You're connected to the PointPerfect MQTT broker: "));
147+
Serial.println(AWS_IOT_ENDPOINT);
148+
// Subscribe to MQTT and register a callback
149+
Serial.println(F("Subscribe to Topics"));
150+
mqttClient.onMessage(mqttMessageHandler);
151+
mqttClient.subscribe(MQTT_TOPIC_KEY);
152+
mqttClient.subscribe(MQTT_TOPIC_SPARTN);
153+
lastReceived_ms = millis();
154+
} //End attempt to connect
155+
} //End connected == false
156+
else {
157+
mqttClient.poll();
158+
}
159+
//Close socket if we don't have new data for 10s
160+
if (millis() - lastReceived_ms > maxTimeBeforeHangup_ms)
161+
{
162+
Serial.println(F("SPARTN timeout. Disconnecting..."));
163+
if (mqttClient.connected() == true)
164+
mqttClient.stop();
165+
return;
166+
}
167+
168+
delay(10);
169+
}
170+
171+
Serial.println(F("User pressed a key"));
172+
Serial.println(F("Disconnecting..."));
173+
wifiClient.stop();
174+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//Your WiFi credentials
2+
const char ssid[] = "<YOUR SSID>";
3+
const char password[] = "<YOUR PASSWORD>";
4+
5+
// Below infomation you can set after signing up with u-blox Thingstream portal
6+
// and after add a new New PointPerfect Thing
7+
// https://portal.thingstream.io/app/location-services/things
8+
// in the new PointPerfect Thing you go to the credentials page and copy past the values and certificate into this.
9+
10+
// <Your PointPerfect Thing> -> Credentials -> Hostname
11+
const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com";
12+
const unsigned short AWS_IOT_PORT = 8883;
13+
// <Your PointPerfect Thing> -> Credentials -> IP key distribution topic
14+
const char MQTT_TOPIC_KEY[] = "/pp/key/ip";
15+
// <Your PointPerfect Thing> -> Credentials -> IP correction topic for EU/US region
16+
const char MQTT_TOPIC_SPARTN[] = "/pp/ip/us"; // choice of {eu, us}
17+
18+
// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
19+
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
20+
-----BEGIN CERTIFICATE-----
21+
<ADD YOUR CERTICICATE HERE>
22+
-----END CERTIFICATE-----
23+
)EOF";
24+
25+
// <Your PointPerfect Thing> -> Credentials -> Client Certificate
26+
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
27+
-----BEGIN CERTIFICATE-----
28+
<ADD YOUR CERTICICATE HERE>
29+
-----END CERTIFICATE-----
30+
)KEY";
31+
32+
// Get this from Thingstream Portal
33+
// <Your PointPerfect Thing> -> Credentials -> Client Key
34+
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
35+
-----BEGIN RSA PRIVATE KEY-----
36+
<ADD YOUR KEY HERE>
37+
-----END RSA PRIVATE KEY-----
38+
)KEY";

0 commit comments

Comments
 (0)