- more pictures

- more fixes
- more literatur
This commit is contained in:
2024-08-11 14:31:02 +02:00
parent 4869e41e5d
commit b616953920
14 changed files with 215 additions and 82 deletions
+19 -19
View File
@@ -1,19 +1,19 @@
\section{Rover}
Die Implementierungen für den Rover beginnen mit der Integration des Gyroskops, dies umschließt den Einbau der Hardware und das einbinden der Sensorwerte in die dafür vorgesehene Komponente. Im nächsten Schritt wird der Ntrip-Client dem System hinzugefügt, damit in den folgenden Prozessen die hochgenaue Positionsbestimmung verfügbar ist. Sobald das GNSS-Modul die Korrekturdaten verarbeitet, kann die Implementierung der Verwaltung für die Routen beginnen. Danach sind alle voraussetzungen gegeben um den Modus zum Routen aufzeichnen programmieren zu können. Daraufhin können die Algorithmen für das automatische befahren der Route entwickelt werden.
Die Implementierungen für den Rover beginnen mit der Integration des Gyroskops, dies umschließt den Einbau der Hardware und das Einbinden der Sensorwerte in die dafür vorgesehene Komponente. Im nächsten Schritt wird der Ntrip-Client dem System hinzugefügt, damit in den folgenden Prozessen die hochgenaue Positionsbestimmung verfügbar ist. Sobald das GNSS-Modul die Korrekturdaten verarbeitet, kann die Implementierung der Verwaltung für die Routen beginnen. Danach sind alle Voraussetzungen gegeben, um den Modus zum Routen aufzeichnen programmieren zu können. Daraufhin können die Algorithmen für das automatische Befahren der Route entwickelt werden.
\subsection{Gyroskop installieren}
Die elektrische Verbindung des Moduls wird über vier Pins hergestellt, dabei handelt es sich um die zwei I2C Leitungen sowie Masse und die Spannungsversorgung. Das Modul kann mit \(+5V\) betrieben werden. Auf der Hauptplatine sind Pin-Leisten vorhanden um weitere I2C-Module, welche mit \(+5V\) betrieben werden können, dem System hinzufügen zu können.
Die elektrische Verbindung des Moduls wird über vier Pins hergestellt, dabei handelt es sich um die zwei I2C Leitungen sowie Masse und die Spannungsversorgung. Das Modul kann mit \(+5V\) betrieben werden. Auf der Hauptplatine sind Pin-Leisten vorhanden, um weitere I2C-Module, welche mit \(+5V\) betrieben werden können, dem System hinzufügen zu können.
\par
Das Modul wird mit einer nicht bestückten Pin-Leise geliefert, daher bestand die Möglichkeit eine gewinkelte Pin-Leiste einzulöten. Es wurde eben diese Pin-Leiste gewählt um das Modul waagerecht mit einer weiteren Platine verbinden zu können. Bei der zusätzlichen Platine handelt es sich lediglich um einen Verteiler, welcher in Abbildung !!!ref!!! gezeigt wird. Dort ist zu sehen wie der Verteiler, durch seine L-Form, an einem Querbalken mit einer Maul-Büroklammer befestigt wird. Das MPU-6050 Module wird seitlich an eine ebenfalls gewinkelte Sockel-Leiste eingesteckt. Auf der Oberseite der Platine befinden sich drei weitere Konnektoren an denen das Display und das Magnetometer angeschlossen werden. Zwei der Konnektoren sind für das Magnetometer um es entweder an den I2C-Bus des ESP32 oder an den Auxiliary-I2C-Bus des MPU-6050 anzuschließen. Auf der Unterseite der Platine ist ein Kabel angelötet welches auf die Hauptplatine gesteckt wird.
Das Modul wird mit einer nicht bestückten Pin-Leise geliefert, daher bestand die Möglichkeit eine gewinkelte Pin-Leiste einzulöten. Es wurde eben diese Pin-Leiste gewählt, um das Modul waagerecht mit einer weiteren Platine verbinden zu können. Bei der zusätzlichen Platine handelt es sich lediglich um einen Verteiler, welcher in Abbildung !!!ref!!! gezeigt wird. Dort ist zu sehen, wie der Verteiler, durch seine L-Form, an einem Querbalken mit einer Maul-Büroklammer befestigt wird. Das MPU-6050 Module wird seitlich an eine ebenfalls gewinkelte Sockel-Leiste eingesteckt. Auf der Oberseite der Platine befinden sich drei weitere Konnektoren, an denen das Display und das Magnetometer angeschlossen werden. Zwei der Konnektoren sind für das Magnetometer, um es entweder an den I2C-Bus des ESP32 oder an den Auxiliary-I2C-Bus des MPU-6050 anzuschließen. Auf der Unterseite der Platine ist ein Kabel angelötet, welches auf die Hauptplatine gesteckt wird.
\par
Durch diese weitere Platine wurde zum einen der benötigte feste Platz für das neue Modul geschaffen und zum anderen die Möglichkeit offen gehalten den bereits verbauten Kompass nun über den MPU-6050 zu nutzen um eine 9-Achsen Sensorfusion zu ermöglichen. Der Versuch diese 9-Achsen Sensorfusion zu implementieren ist gescheitert. Der Hersteller wirbt zwar mit dieser Funktion, jedoch ist die Rechenleitung des Chips nicht ausreichend hoch genug um die Funktion umzusetzen. Daher müssten Berechnung dafür auf den ESP32 ausgelagert werden !!!cite \url{https://www.i2cdevlib.com/devices/mpu6050#help}!!!. Dieser Weg wurde aufgrund der Komplexität nicht weiter verfolgt.
Durch diese weitere Platine wurde zum einen der benötigte feste Platz für das neue Modul geschaffen und zum anderen die Möglichkeit offen gehalten, den bereits verbauten Kompass nun über den MPU-6050 zu nutzen, um eine 9-Achsen Sensorfusion zu ermöglichen. Der Versuch diese 9-Achsen Sensorfusion zu implementieren ist gescheitert. Der Hersteller wirbt zwar mit dieser Funktion, jedoch ist die Rechenleitung des Chips nicht ausreichend hoch genug, damit die Funktion umzusetzen werden kann. Daher müssten Berechnung dafür auf den ESP32 ausgelagert werden !!!cite \url{https://www.i2cdevlib.com/devices/mpu6050#help}!!!. Dieser Weg wurde aufgrund der Komplexität nicht weiter verfolgt.
\par
Die Einbindung des Sensors in den vorhandenen Programmcode erfolgte mit der bereits vorhanden \mintinline{c++}|class SensorData|. Für die Kommunikation mit dem Sensor wird die Bibliothek \texttt{I2Cdevlib-MPU6050} verwendet. Der Klasse wurden neben einer Funktionen zum Datenerhalt, die Funktion \mintinline{c++}|void enableGyroscope();| hinzugefügt. Diese erzeugt ein Objekt für den MPU6050 und initialisiert sowohl den MPU6050 als auch den verbauten Digital Motion Processor. Außerdem werden ermittelte Offsets eingestellt. Die periodische aufgerufene \mintinline{c++}|void run();| Funktion wurde ebenfalls erweitertet und überprüft jetzt im jeden Durchgang ob neue Daten des Sensors verfügbar sind und verarbeitet diese dann.
Die Einbindung des Sensors in den vorhandenen Programmcode erfolgte mit der bereits vorhanden \mintinline{c++}|class SensorData|. Für die Kommunikation mit dem Sensor wird die Bibliothek \texttt{I2Cdevlib-MPU6050} verwendet. Der Klasse wurden neben einer Funktion zum Datenerhalt, die Funktion \mintinline{c++}|void enableGyroscope(); | hinzugefügt. Diese erzeugt ein Objekt für den MPU-6050 und initialisiert sowohl den MPU-6050 als auch den verbauten Digital Motion Processor. Außerdem werden ermittelte Offsets eingestellt. Die periodische aufgerufene \mintinline{c++}|void run(); | Funktion wurde ebenfalls erweitertet und überprüft jetzt in jedem Durchgang, ob neue Daten des Sensors verfügbar sind und verarbeitet diese dann.
\subsection{Ntrip Client}
\label{ssec:ntripclient}
Die Implementierungen des Clients orientiert sich an dem von der RTCM herausgegebenen Paper \glqq Best Practices for NTRIP Client developers\grqq \cite{NTRIPWorkingGroup2023}. Außerdem können beide Revisionen des Protokolls mit dem Client benutzt werden. Die Revision 1 ist offiziell von der RTCM als \texttt{outdated} markiert. Der in dieser Arbeit verwendete Caster \url{rtk2go.com} gibt jedoch in seinen Statistiken an, dass \(95\%\) der eingehenden Verbindungen die Revision 1 verwenden. Zusätzlich kann durch die Implementierung beider Revisionen die angegeben Abwärtskompatibilität getestet werden. Des weiteren wird die Authentisierung mit Benutzernamen und Kennwort sowie die Übermittlung des eigenen Standorts an den Caster implementiert. Der Eigene Standort ist für Caster wichtig, welche mit einem Netz aus Referenzstationen betrieben werden. Die Implementierung erfolgt also damit der Rover auch abseits der errichteten Referenzstation von anderen Anbietern mit Korrekturdaten versorgt werden kann.
Die Implementierungen des Clients orientiert sich an dem von der RTCM herausgegebenen Paper \glqq Best Practices for NTRIP Client developers\grqq \cite{NTRIPWorkingGroup2023}. Zudem können beide Revisionen des Protokolls mit dem Client benutzt werden. Die Revision 1 ist offiziell von der RTCM als \texttt{outdated} markiert. Der in dieser Arbeit verwendete Caster \url{rtk2go.com} gibt jedoch in seinen Statistiken an, dass \(95\%\) der eingehenden Verbindungen die Revision 1 verwenden. Zusätzlich kann durch die Implementierung beider Revisionen, die angegeben Abwärtskompatibilität getestet werden. Des Weiteren wird die Authentisierung mit Benutzernamen und Kennwort sowie die Übermittlung des eigenen Standorts an den Caster implementiert. Der eigene Standort ist für Caster wichtig, welche mit einem Netz aus Referenzstationen betrieben werden. Die Implementierung erfolgt also, damit der Rover auch abseits der errichteten Referenzstation von anderen Anbietern mit Korrekturdaten versorgt werden kann.
\subsubsection{Einstellungen}
Eine Instanz des Clients fordert die Adresse des Casters, den Mountpoint, die Zugangsdaten und das GNSS-Modul als Parameter für den Konstruktor, diese sind nur durch eine neue Instanz änderbar. Der Benutzername und das Passwort können ignoriert werden, wenn eine Anmeldung bei dem Caster ohne Zugangsdaten möglich ist.
@@ -30,13 +30,13 @@
\setlist{}
\subsubsection{Zustandsautomaten}
Der Ntrip Client wurde nach dem Schema eines Zustandsautomaten entworfen, welcher in Abbildung !!!ref!!! skizziert wird. Im folgenden wird auf die Funktionalitäten der einzelnen Zustände eingegangen. Die Zustände werden durch das \mintinline{c++}|enum NTRIPClientStates| definiert.
Der Ntrip Client wurde nach dem Schema eines Zustandsautomaten entworfen, welcher in Abbildung !!!ref!!! skizziert wird. Im Folgenden wird auf die Funktionalitäten der einzelnen Zustände eingegangen. Die Zustände werden durch das \mintinline{c++}|enum NTRIPClientStates| definiert.
\begin{itemize}
\item \textbf{openingConnection} In diesem Zustand wird versucht die Verbindung zu dem Caster aufzubauen. Dafür wird zwischen den Revisionen von Ntrip unterschieden, ob die Position gesendet werden soll und ob Zugangsdaten angegeben worden sind. Sollte der Verbindungsaufbau scheitern wird in den \texttt{waiting} Zustand gewechselt ansonsten in den \texttt{pushingData} Zustand.
\item \textbf{openingConnection} In diesem Zustand wird versucht, die Verbindung zu dem Caster aufzubauen. Dafür wird zwischen den Revisionen von Ntrip unterschieden, ob die Position gesendet werden soll und ob Zugangsdaten angegeben worden sind. Sollte der Verbindungsaufbau scheitern, wird in den \texttt{waiting} Zustand gewechselt, ansonsten in den \texttt{pushingData} Zustand.
\item \textbf{pushingData} Wenn eine Verbindung zu dem Caster besteht, befindet sich der Client in diesem Zustand und leitet die empfangenen Daten an das GNSS-Modul weiter. Es kann nur in den \texttt{closingConnection} Zustand gewechselt werden.
\item \textbf{closingConnection} Sollt der Ntrip Client deaktiviert werden oder ein Timeout festgestellt werden, wird in diesen Zustand gewechselt, damit die Verbindung aus Sicht des Clients ordnungsgemäß beendet wird. Sobald die Verbindung getrennt ist wird der \texttt{waiting} Zustand aktiv.
\item \textbf{waiting} Wenn dieser Zustand betreten wird, wurde die Verbindung getrennt und es wird darauf gewartet in den \texttt{openingConnection} Zustand zu wechseln. Dafür muss entweder der Client wieder aktiviert werden oder die automatische Wiederverbindung muss aktiviert sein.
\item \textbf{closingConnection} Sollte der Ntrip Client deaktiviert oder ein Timeout festgestellt werden, wird in diesen Zustand gewechselt, damit die Verbindung aus Sicht des Clients ordnungsgemäß beendet wird. Sobald die Verbindung getrennt ist, wird der \texttt{waiting} Zustand aktiv.
\item \textbf{waiting} Wenn dieser Zustand betreten wird, wurde die Verbindung getrennt und es wird darauf gewartet, in den \texttt{openingConnection} Zustand zu wechseln. Dafür muss entweder der Client wieder aktiviert werden oder die automatische Wiederverbindung muss aktiviert sein.
\item \textbf{notAvailable} Dieser Zustand wird betreten, wenn keine Verbindung zum Internet bereitsteht.
\end{itemize}
@@ -45,16 +45,16 @@
Die Implementierung der Routen Verwaltung erfolgt über die \mintinline{c++}|class Route|, welche eine Liste zur Speicherung der Punkte nutzt. Die Punkte sind Instanzen der \mintinline{c++}|class Point|. Es herrscht also eine 1 zu n Beziehung zwischen \mintinline{c++}|class Route| und \mintinline{c++}|class Point|.
\subsubsection{Postionen mit \mintinline{c++}|class Point|}
Eine Instanz dieser Klasse besteht unter anderem aus den Koordinaten, welche in dem \mintinline{c++}|struct Coordinates| als zwei \mintinline{c++}|double| Werte gespeichert werden. Zusätzlich kann die Zeit der Erzeugung und die geschätzte Genauigkeit des Punktes angegeben und gespeichert werden. Neben Methoden zur Datenkontrolle und Zugriff wird die Funktionalität der Klasse durch diese beiden Funktionen gegeben:
Eine Instanz dieser Klasse besteht unter anderem aus den Koordinaten, welche in dem \mintinline{c++}|struct Coordinates| als zwei \mintinline{c++}|double| Werte gespeichert werden. Zusätzlich kann die Zeit der Erzeugung und die geschätzte Genauigkeit des Punktes angegeben und gespeichert werden. Neben den Methoden zur Datenkontrolle und Zugriff wird die Funktionalität der Klasse durch diese beiden Funktionen gegeben:
\begin{itemize}
\item \mintinline{c++}|double distanceTo(Point);| errechnet die Entfernung zwischen den Koordinaten der Instanz zu dem gegeben Punkt. Für die Berechnung wird die Erdkrümmung vernachlässigt, deshalb kann der Satz des Pythagoras genutzt werden. Dafür müssen die Grad angegebenen Koordinaten zunächst in Radianten umgewandelt werden und anschließend in ein kartesisches Koordinatensystem überführt werden. Anschließend kann die Entfernung der beiden Punkte berechnet werden. Dafür werden die beiden Koordinaten einer Achse voneinander abgezogen und anschließend quadriert. Die Ergebnisse der beiden Achsen werden schließlich aufsummiert und radiziert.
\item \mintinline{c++}|double distanceTo(Point); | errechnet die Entfernung zwischen den Koordinaten der Instanz zu dem gegebenen Punkt. Für die Berechnung wird die Erdkrümmung vernachlässigt, deshalb kann der Satz des Pythagoras genutzt werden. Dafür müssen die in Grad angegebenen Koordinaten zunächst in Radianten umgewandelt und anschließend in ein kartesisches Koordinatensystem überführt werden. Anschließend kann die Entfernung der beiden Punkte berechnet werden. Dafür werden die beiden Koordinaten einer Achse voneinander abgezogen und anschließend quadriert. Die Ergebnisse der beiden Achsen werden schließlich aufsummiert und radiziert.
\begin{eqnarray}
d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}
\end{eqnarray}
\item \mintinline{c++}|int16_t courseTo(Point);| errechnet den Kurs von dem aktuellen Punkt zu dem gegebenen Punkt und gibt ihn in Grad aus. \(0^\circ\) entspricht Norden. Von da an wird im Uhrzeigersinn weiter gezählt, sodass \(270^\circ\) beispielsweise einen Kurs nach Westen angeben würden. Für die Berechnung müssen die Längen- und Breitengrade zunächst in Radianten umgewandelt werden. Anschließend kann dann mit der Formel
\item \mintinline{c++}|int16_t courseTo(Point);| errechnet den Kurs von dem aktuellen Punkt zu dem gegebenen Punkt und gibt ihn in Grad aus. \(0^\circ\) entspricht Norden. Von da an wird im Uhrzeigersinn weiter gezählt, sodass \(270^\circ\) etwa einen Kurs nach Westen angeben würden. Für die Berechnung müssen die Längen- und Breitengrade zunächst in Radianten umgewandelt werden. Anschließend kann dann mit der Formel
\begin{eqnarray}
\theta = \text{atan2}(\sin(\Delta \lambda)cos(\phi_2), \cos(\phi_1)\sin(\phi_2) - \sin(\phi_1)\cos(\phi_2)\cos(\Delta \lambda))
@@ -68,23 +68,23 @@
\lambda_1, \lambda_2 &\widehat{=}& \text{Längengrad der Punkte}
\end{eqnarray}
Anschließend muss \(\theta\) wieder in Grad umgewandelt werden und mit modulo auf den Wertebereich \(0 \text{ bis } 360\) normalisiert werden.
Anschließend muss \(\theta\) wieder in Grad umgewandelt und mit dem modulo-Operator auf den Wertebereich \(0 \text{ bis } 360\) normalisiert werden.
\end{itemize}
\subsubsection{Postionsspeicherung mit \mintinline{c++}|class Route|}
Die Klasse nutzt die Implementierung der Liste aus der C++ Standardbibliothek. Darüber hinaus wird ein Iterator für diese Liste von der Klasse verwaltet. Mit primitiven Datentypen wird festgehalten ob die Route gestartet ist und der wievielte Punkt gerade aus der Route selektiert ist.
Die Klasse nutzt die Implementierung der Liste aus der C++ Standardbibliothek. Überdies wird ein Iterator für diese Liste von der Klasse verwaltet. Mit primitiven Datentypen wird festgehalten, ob die Route gestartet und der wievielte Punkt gerade aus der Route selektiert ist.
\par
Die Funktionen der Klasse beschränken sich darauf den Iterator und Liste zu verwalten. Der Liste können nur Daten hinzugefügt werden. Die Entfernung einzelner Punkte ist nicht möglich und erfordert das Löschen der gesamten Liste. Es kann jeweils der nächste oder der vorherige Punkt ausgewählt werden. Die Route kann am Ende oder am Anfang gestartet werden. Soll die Route im Umgekehrter Reihenfolge abgefahren werden muss diese am Ende gestartet werden und immer der vorherige Punkt der Route abgerufen werden. Bei einem Fehler, weil beispielsweise keine Route aufgezeichnet wurde, wird von Funktionen eine Instanz von der \mintinline{c++}|class Point| mit den Koordinaten \(0 \text{ und } 0\) zurückgegeben. Dies kann von aufrufenden Funktion überprüft werden, dafür wurde eigens die Funktion \mintinline{c++}|bool Point::isValid();| implementiert.
Die Funktionen der Klasse beschränken sich darauf, den Iterator und Liste zu verwalten. Der Liste können nur Daten hinzugefügt werden. Die Entfernung einzelner Punkte ist nicht möglich und erfordert das Löschen der gesamten Liste. Es kann jeweils der nächste oder der vorherige Punkt ausgewählt werden. Die Route kann am Ende oder am Anfang gestartet werden. Soll die Route im umgekehrter Reihenfolge abgefahren werden, muss diese am Ende gestartet und immer der vorherige Punkt der Route abgerufen werden. Bei einem Fehler, weil beispielsweise keine Route aufgezeichnet wurde, wird von Funktionen eine Instanz von der \mintinline{c++}|class Point| mit den Koordinaten \(0 \text{ und } 0\) zurückgegeben. Dies kann von der aufrufenden Funktion überprüft werden, dafür wurde eigens die Funktion \mintinline{c++}|bool Point::isValid(); | implementiert.
\par
Damit Informationen über die Route abgefragt werden können, wurde ein Datentyp hinzugefügt. Das \mintinline{c++}|struct RouteInfo| enthält die Gesamtzahl der in der Route gespeicherten Punkte und der wievielte davon gerade ausgewählt ist.
Damit Informationen über die Route abgefragt werden können, wurde ein Datentyp hinzugefügt. Das \mintinline{c++}|struct RouteInfo| enthält die Gesamtzahl der in der Route gespeicherten Punkte sowie den Index des selektierten Punktes.
\subsubsection{Verwaltung über das Menü}
In die vorhandene Menüstruktur wurde in der ersten Ebene der Punkt \flqq Route\frqq{} als Untermenü hinzugefügt. Dieses Menü stellt die in der folgenden Liste erläuterten Funktionen bereit. Für einige dieser Funktionen wird auf eine entwickelte HTTP-API zugegriffen, deshalb muss für diese Funktionen eine Internetverbindung bestehen. Die serverseitige Implementierung der API wird im Anhang \ref{cha:httpApi} beschrieben. Werden Teile der API auf dem Rover genutzt, zeigt dieser den HTTP-Code an. Mit diesem lässt sich erkennen ob die ausgeführte Operation korrekt ausgeführt wurde.
In die vorhandene Menüstruktur wurde in der ersten Ebene der Punkt \flqq Route\frqq{} als Untermenü hinzugefügt. Dieses Menü stellt die in der folgenden Liste erläuterten Funktionen bereit. Für einige dieser Funktionen wird auf eine entwickelte HTTP-API zugegriffen, deshalb muss für diese Funktionen eine Internetverbindung bestehen. Die serverseitige Implementierung der API wird im Anhang \ref{cha:httpApi} beschrieben. Werden Teile der API auf dem Rover genutzt, zeigt dieser den HTTP-Code an. Mit diesem kann erkannt werden, ob die ausgeführte Operation korrekt ausgeführt wurde.
\begin{itemize}
\item \textbf{Points} - Unter diesem Punkt können die einzelnen Koordinaten der in der Route gespeicherten Punkte betrachtet werden.
\item \textbf{Clear} - Löscht die aktuell lokal erstellte Route.
\item \textbf{Import} - Bei Auswahl dieses Punktes muss der Benutzter die ID der Route wissen mit der diese Exportiert wurde. Sofern die gewählte ID existiert, wird die Route heruntergeladen und steht dem Rover nun zur Verfügung. Wenn bereits ein Route lokal vorhanden war, wird diese durch importierte überschrieben. In diesem Fall könnte die gefährdete Route vorher exportiert werden.
\item \textbf{Import} - Bei Auswahl dieses Punktes muss der Benutzer die ID der Route wissen, mit der diese exportiert wurde. Sofern die gewählte ID existiert, wird die Route heruntergeladen und steht dem Rover nun zur Verfügung. Wenn bereits eine Route lokal vorhanden war, wird diese durch importierte überschrieben. In diesem Fall könnte die gefährdete Route vorher exportiert werden.
\item \textbf{Export} - Mit dieser Funktionen können Routen für die spätere Verwendung gesichert werden. Dafür muss ihnen eine ID zugewiesen werden, unter dieser ID lässt sich die Route später wieder abrufen.
\item \textbf{Delete} - Mit Delete kann eine exportierte Route mit ihrer ID gelöscht werden, dies betrifft allerdings nicht aktuell lokal vorhandene Route.
\end{itemize}