Author SHA1 Message Date
kleiax 479a3d171e added description and video to readme 2024-10-04 22:59:18 +00:00
kleiax a5bfbc3df9 added readme 2024-10-04 22:56:44 +00:00
kleiax 4251eda946 added pictures 2024-10-05 00:27:51 +02:00
kleiax 27a0a2ca7b fix ntrip client and integration 2024-08-17 10:44:42 +02:00
30 changed files with 96 additions and 43 deletions
+7
View File
@@ -1,5 +1,6 @@
{ {
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"editor.wordWrap": "on",
"cSpell.ignoreWords": [ "cSpell.ignoreWords": [
"ledc", "ledc",
"write" "write"
@@ -132,6 +133,7 @@
"Doxygen", "Doxygen",
"Dutycycle", "Dutycycle",
"gast", "gast",
"gnss",
"GNSS", "GNSS",
"GPGGA", "GPGGA",
"HSPI", "HSPI",
@@ -140,9 +142,12 @@
"kleiax", "kleiax",
"Lebennig", "Lebennig",
"microcontroller", "microcontroller",
"Mqtt",
"MQTT", "MQTT",
"NMEA", "NMEA",
"NMEAGPGGA", "NMEAGPGGA",
"ntrip",
"Ntrip",
"NTRIP", "NTRIP",
"pcnt", "pcnt",
"pidl", "pidl",
@@ -150,6 +155,8 @@
"Punica", "Punica",
"RHEDE", "RHEDE",
"Rtcm", "Rtcm",
"sapos",
"SAPOS",
"Schalke", "Schalke",
"Soln", "Soln",
"Systeminformation", "Systeminformation",
+5
View File
@@ -0,0 +1,5 @@
# Autonomer Rover
Testfahrt auf Youtube: https://youtu.be/GigIyo-vghE?si=jhProl1DQFUrcz7w
# Beschreibung
Vollständige Softwarelösung und Hardwareerweiterungen für einen Rover mit Skid-Antrieb. Das System wurde in C++ geschrieben und es wurden erweiterte Konzepte der Objektorientierung wie Polymorphie eingesetzt. Die Datenhaltung wurde erfolgreich von der Logik getrennt, hierfür wurde unter anderem eine API mit Express.js implementiert. Hardwareseitig wurde PWM für die Motorsteuerung, IC2 für verschiedene Sensoren und SPI für das GNSS-Modul eingesetzt. Zusätzlich wurden Encoder an den Motoren verbaut, um diese präzise zu steuern. Überdies wurde eine RTK-Referenzstation geplant und umgesetzt, dafür wurde die Antenne, ein weiteres GNSS-Modul und ein Embedded-Server installiert und konfiguriert. Durch das Zusammenspiel dieser Systeme kann der Rover Routen im niedrigen einstelligen Zentimeterbereich aufzeichnen und abfahren.
+1 -1
View File
@@ -44,7 +44,7 @@ PROJECT_NUMBER =
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "A small verhicle which should be drive a route with GPS" PROJECT_BRIEF = "A small verhicle which should be drive a route with GNNS and RTK"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

+19 -2
View File
@@ -14,7 +14,9 @@
#include <stdint.h> #include <stdint.h>
#define HOTSPOT #define ZUHAUSE
#define SAPOS_NI
// #define RTK2GO
#ifdef HOTSPOT #ifdef HOTSPOT
namespace NetworkConfig namespace NetworkConfig
@@ -61,7 +63,7 @@ namespace NetworkConfig
{ {
const char ssid[] = "Tuedelkram"; const char ssid[] = "Tuedelkram";
const char password[] = "3!Kaesehoch"; const char password[] = "3!Kaesehoch";
const char ip[] = "192.168.178.11"; const char ip[] = "192.168.178.13";
const char subnet[] = "255.255.255.0"; const char subnet[] = "255.255.255.0";
const char gateway[] = "192.168.178.1"; const char gateway[] = "192.168.178.1";
const char dns[] = "8.8.8.8"; const char dns[] = "8.8.8.8";
@@ -77,6 +79,7 @@ namespace MqttConfig
const char password[] = "p?{$_~5%hBM7wrcFkr55KWr#"; const char password[] = "p?{$_~5%hBM7wrcFkr55KWr#";
} }
#ifdef RTK2GO
namespace NtripConfig namespace NtripConfig
{ {
const char host[] = "rtk2go.com"; const char host[] = "rtk2go.com";
@@ -86,4 +89,18 @@ namespace NtripConfig
// const char mountPoint[] = "Rtkramerntrip"; // const char mountPoint[] = "Rtkramerntrip";
const char user[] = "alklein1@gmx.de"; const char user[] = "alklein1@gmx.de";
const char password[] = "none"; const char password[] = "none";
const bool sendOwnPosition = false;
} }
#endif // RTK2GO
#ifdef SAPOS_NI
namespace NtripConfig
{
const char host[] = "sapos-ni-ntrip.de";
const uint16_t port = 2101;
const char mountPoint[] = "VRS_3_4G_NI";
const char user[] = "ni_FHDo01";
const char password[] = "ALdx-1-3e49";
const bool sendOwnPosition = true;
}
#endif // RTK2GO
+31 -35
View File
@@ -47,6 +47,7 @@ void NTRIPClient::run()
{ {
std::cout << "Failed!" << std::endl; std::cout << "Failed!" << std::endl;
this->state = NTRIPClientStates::waiting; this->state = NTRIPClientStates::waiting;
this->lastReconnectTime = millis();
this->activated = false; this->activated = false;
} }
break; break;
@@ -97,7 +98,7 @@ void NTRIPClient::gnssConfiguration()
// Set the differential mode - ambiguities are fixed whenever possible // Set the differential mode - ambiguities are fixed whenever possible
this->gnss->setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); this->gnss->setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED);
this->gnss->setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP); this->gnss->setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
this->gnss->enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, 10); this->gnss->enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI);
} }
bool NTRIPClient::setActivated(bool state) bool NTRIPClient::setActivated(bool state)
@@ -153,11 +154,7 @@ bool NTRIPClient::beginClient()
{ {
snprintf(static_cast<char *>(serverRequest), snprintf(static_cast<char *>(serverRequest),
this->bufferSize, this->bufferSize,
static_cast<const char *>("GET /%s HTTP/1.0\r\n\ static_cast<const char *>("GET /%s HTTP/1.0\r\nHost: %s:%u\r\nUser-Agent: NTRIP KleiaxNtripClient/0.1\r\nAccept: */*\r\nConnection: close\r\n"),
Host: %s:%u\r\n\
User-Agent: NTRIP KleiaxNtripClient/0.1\r\n\
Accept: */*\r\n\
Connection: close\r\n"),
this->mountPoint, this->mountPoint,
this->host, this->host,
this->port); this->port);
@@ -166,12 +163,7 @@ bool NTRIPClient::beginClient()
{ {
snprintf(static_cast<char *>(serverRequest), snprintf(static_cast<char *>(serverRequest),
this->bufferSize, this->bufferSize,
static_cast<const char *>("GET /%s HTTP/1.1\r\n\ static_cast<const char *>("GET /%s HTTP/1.1\r\nHost: %s:%u\r\nNtrip-Version: Ntrip/2.0\r\nUser-Agent: NTRIP KleiaxNtripClient/0.1\r\nAccept: */*\r\nConnection: close\r\n"),
Host: %s:%u\r\n\
Ntrip-Version: Ntrip/2.0\r\n\
User-Agent: NTRIP KleiaxNtripClient/0.1\r\n\
Accept: */*\r\n\
Connection: close\r\n"),
this->mountPoint, this->mountPoint,
this->host, this->host,
this->port); this->port);
@@ -180,6 +172,7 @@ bool NTRIPClient::beginClient()
// Add own Position if activated // Add own Position if activated
if (this->transmitLocation && !this->useNtripRev1) if (this->transmitLocation && !this->useNtripRev1)
{ {
std::cout << "NTRIPClient::beginClient - Add own position to server request." << std::endl;
auto *data = new NMEA_GGA_data_t; auto *data = new NMEA_GGA_data_t;
const uint8_t res = this->gnss->getLatestNMEAGPGGA(data); const uint8_t res = this->gnss->getLatestNMEAGPGGA(data);
if (res > 0) // valid data if (res > 0) // valid data
@@ -187,10 +180,14 @@ bool NTRIPClient::beginClient()
char positionUpdate[this->bufferSizePushGPGGA]; char positionUpdate[this->bufferSizePushGPGGA];
snprintf(static_cast<char *>(positionUpdate), snprintf(static_cast<char *>(positionUpdate),
this->bufferSizePushGPGGA, this->bufferSizePushGPGGA,
static_cast<const char *>("Ntrip-GGA: %s\r\n"), static_cast<const char *>("Ntrip-GGA: %s"),
data->nmea); data->nmea);
strncat(static_cast<char *>(serverRequest), static_cast<const char *>(positionUpdate), this->bufferSize); strncat(static_cast<char *>(serverRequest), static_cast<const char *>(positionUpdate), this->bufferSize);
} }
else
{
std::cout << "NTRIPClient::beginClient - No valid data to send position to caster." << std::endl;
}
delete data; delete data;
this->lastGPGGAPushTime = millis(); this->lastGPGGAPushTime = millis();
@@ -198,24 +195,24 @@ bool NTRIPClient::beginClient()
if (this->user && this->password) if (this->user && this->password)
{ {
// Credentials // Credentials
const uint8_t userCredentialsLength = strlen(this->user) + strlen(this->password) + 2; const uint8_t userCredentialsLength = strlen(this->user) + strlen(this->password) + 2;
auto *userCredentials = new char[userCredentialsLength]; auto *userCredentials = new char[userCredentialsLength];
snprintf(static_cast<char *>(userCredentials), userCredentialsLength, static_cast<const char *>("%s:%s"), this->user, this->password); snprintf(static_cast<char *>(userCredentials), userCredentialsLength, static_cast<const char *>("%s:%s"), this->user, this->password);
std::cout << "Sending credentials: " << userCredentials << std::endl; std::cout << "Sending credentials: " << userCredentials << std::endl;
// Encode // Encode
const base64 base; const base64 base;
const String strEncodedCredentials = base64::encode(userCredentials); const String strEncodedCredentials = base64::encode(userCredentials);
delete userCredentials; delete userCredentials;
char encodedCredentials[strEncodedCredentials.length() + 1]; char encodedCredentials[strEncodedCredentials.length() + 1];
strEncodedCredentials.toCharArray(static_cast<char *>(encodedCredentials), sizeof(encodedCredentials)); strEncodedCredentials.toCharArray(static_cast<char *>(encodedCredentials), sizeof(encodedCredentials));
snprintf(credentials, sizeof(credentials), static_cast<const char *>("Authorization: Basic %s\r\n"), static_cast<const char *>(encodedCredentials)); snprintf(credentials, sizeof(credentials), static_cast<const char *>("Authorization: Basic %s\r\n"), static_cast<const char *>(encodedCredentials));
// Add the encoded credentials to the server request // Add the encoded credentials to the server request
strncat(static_cast<char *>(serverRequest), static_cast<const char *>(credentials), this->bufferSize); strncat(static_cast<char *>(serverRequest), static_cast<const char *>(credentials), this->bufferSize);
} }
strncat(static_cast<char *>(serverRequest), static_cast<const char *>("\r\n"), this->bufferSize); strncat(static_cast<char *>(serverRequest), static_cast<const char *>("\r\n"), this->bufferSize);
@@ -367,7 +364,7 @@ void NTRIPClient::checkAutoReconnect()
void NTRIPClient::pushGPGGA() void NTRIPClient::pushGPGGA()
{ {
if (!this->transmitLocation && !this->activated) if ((!this->transmitLocation || !this->activated) || !this->ntripClient->connected())
{ {
return; return;
} }
@@ -378,23 +375,22 @@ void NTRIPClient::pushGPGGA()
} }
this->lastGPGGAPushTime = millis(); this->lastGPGGAPushTime = millis();
if (!this->ntripClient->connected())
{
std::cout << "Failed to pushing GGA to server: " << std::endl;
}
auto *data = new NMEA_GGA_data_t; auto *data = new NMEA_GGA_data_t;
const uint8_t res = this->gnss->getLatestNMEAGPGGA(data); const uint8_t res = this->gnss->getLatestNMEAGPGGA(data);
if (res == 2) // 2 means fresh data if (res > 0) // 2 means fresh data
{ {
char positionUpdate[this->bufferSizePushGPGGA]; char positionUpdate[this->bufferSizePushGPGGA];
snprintf(static_cast<char *>(positionUpdate), snprintf(static_cast<char *>(positionUpdate),
this->bufferSizePushGPGGA, this->bufferSizePushGPGGA,
static_cast<const char *>("%s\r\n"), static_cast<const char *>("%s"),
data->nmea); data->nmea);
this->ntripClient->write(positionUpdate, strlen(positionUpdate)); this->ntripClient->write(positionUpdate, strlen(positionUpdate));
std::cout << "Position update: " << positionUpdate << std::endl; std::cout << "Position update: " << positionUpdate << std::endl;
} }
else
{
std::cout << "NTRIPClient::pushGPGGA - No valid data to send position to caster." << std::endl;
}
delete data; delete data;
} }
+1 -1
View File
@@ -130,7 +130,7 @@ private:
const uint16_t timeOut = 10000; const uint16_t timeOut = 10000;
const uint16_t bufferSize = 512; const uint16_t bufferSize = 512;
const uint16_t bufferSizePushGPGGA = 128; const uint16_t bufferSizePushGPGGA = 128;
const uint16_t pushGPGGATime = 10000; const uint16_t pushGPGGATime = 5000;
static constexpr uint8_t loopDelay = 20; static constexpr uint8_t loopDelay = 20;
}; };
+3 -2
View File
@@ -25,11 +25,12 @@ SensorData::~SensorData()
delete this->ntripClient; delete this->ntripClient;
} }
void SensorData::enableNtrip(String host, uint16_t port, String mountPoint, String user, String password) void SensorData::enableNtrip(String host, uint16_t port, String mountPoint, String user, String password, bool sendOwnPosition)
{ {
this->ntripClient = new NTRIPClient(this->gnss, host.c_str(), port, mountPoint.c_str(), user.c_str(), password.c_str()); this->ntripClient = new NTRIPClient(this->gnss, host.c_str(), port, mountPoint.c_str(), user.c_str(), password.c_str());
this->ntripClient->gnssConfiguration(); this->ntripClient->gnssConfiguration();
this->ntripClient->loop(); this->ntripClient->loop();
this->ntripClient->setTransmitLocation(sendOwnPosition);
this->ntripClient->setActivated(false); this->ntripClient->setActivated(false);
this->isNtripInit = true; this->isNtripInit = true;
this->addChildComponent(this->ntripClient); this->addChildComponent(this->ntripClient);
@@ -264,7 +265,7 @@ void SensorData::initGnss()
std::cout << "u-blox protocol version: " << static_cast<int>(versionHigh) << "." << static_cast<int>(versionLow) << std::endl; std::cout << "u-blox protocol version: " << static_cast<int>(versionHigh) << "." << static_cast<int>(versionLow) << std::endl;
this->gnss->setSPIOutput(COM_TYPE_UBX); this->gnss->setSPIOutput(COM_TYPE_UBX);
this->gnss->enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, 10); this->gnss->enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI);
this->gnss->setUSBOutput(COM_TYPE_UBX | COM_TYPE_NMEA); this->gnss->setUSBOutput(COM_TYPE_UBX | COM_TYPE_NMEA);
this->gnss->setAutoPVTcallbackPtr(&(SensorData::savePVTdata)); this->gnss->setAutoPVTcallbackPtr(&(SensorData::savePVTdata));
// SensorData::setOutputStatusPrintPVTdata(true); // SensorData::setOutputStatusPrintPVTdata(true);
+1 -1
View File
@@ -38,7 +38,7 @@ public:
SensorData(); SensorData();
~SensorData(); ~SensorData();
void enableNtrip(String host, uint16_t port, String mountPoint, String user, String password); void enableNtrip(String host, uint16_t port, String mountPoint, String user, String password, bool sendOwnPosition = false);
/** /**
* @brief Enable the gnss module over spi * @brief Enable the gnss module over spi
@@ -150,3 +150,28 @@ void MenuSensorData::printPage() const
this->print(lineOne, lineTwo); this->print(lineOne, lineTwo);
} }
void MenuSensorData::runCommand()
{
switch (this->getCurrentPage())
{
case 5:
{
NTRIPClient* client = this->sensorData->getNtripClient();
NTRIPClientStates state = client->getClientState();
if (state == NTRIPClientStates::pushingData)
{
client->deactivate();
}
else if (state == NTRIPClientStates::waiting)
{
client->activate();
}
}
break;
default:
break;
}
}
@@ -30,6 +30,7 @@ public:
private: private:
void printPage() const override; void printPage() const override;
void runCommand() override;
SensorData *sensorData; SensorData *sensorData;
}; };
+2 -1
View File
@@ -129,7 +129,8 @@ void setup()
NtripConfig::port, NtripConfig::port,
static_cast<const char *>(NtripConfig::mountPoint), static_cast<const char *>(NtripConfig::mountPoint),
static_cast<const char *>(NtripConfig::user), static_cast<const char *>(NtripConfig::user),
static_cast<const char *>(NtripConfig::password)); static_cast<const char *>(NtripConfig::password),
NtripConfig::sendOwnPosition);
sensorData->enableGyroscope(); sensorData->enableGyroscope();
driveManager = new DriveManager(&moveController, sensorData, controlPad->getControlPadDataPtr()); driveManager = new DriveManager(&moveController, sensorData, controlPad->getControlPadDataPtr());