\subsection[Navigation]{\mintinline{c++}|class Navigation|} \label{ssec:navigation_implementation} Diese Klasse vereinigt die Verwaltung der Route mit den Sensorwerten wie die Positionsdaten und Ausrichtung um die eigentliche Navigation bereitzustellen. Außerdem werden die Anforderungen an die Genauigkeit überwacht. Die Navigation wird von den Modi zur Aufzeichnung und Abfahrt der Route benötigt. \par Es wurde ein \mintinline{c++}|enum Status| implementiert, welcher von einigen Funktionen der Klasse genutzt wird um Informationen über den Ausgang des Funktionsaufrufes zu informieren. Es kann mitgeteilt werden ob die Genauigkeit unzureichend ist, keine Änderungen erfolgt sind, etwas geändert wurde und ob die etwas abgeschlossen wurde. Des weiteren wird in der selben Header-Datei das \mintinline{c++}|struct CourseCorrection| definiert um die Distanz und die anzuwendende Kurskorrektur zum Zielpunkt in einem Datentypen zu vereinen. \subsection{Modus - Route aufzeichnen} Um eine Route aufzeichnen zu können wurde zum einen die \mintinline{c++}|class CaptureRoute| implementiert, welche von der bereits vorhanden Klasse zum manuellen Verfahren des Rovers erbt und damit auch in der Hierarchie des \texttt{DiveModi} Interfaces zu finden ist. Dadurch kann der Modus dem bestehenden System ohne weitere Änderungen hinzugefügt werden. \par Die Instanz der \mintinline{c++}|class Navigation| wird von dem aktuellen Modus erzeugt dafür wird Komponente \texttt{SensorData} benötigt und eine Route. Die \texttt{SensorData} Komponente wird jedem \texttt{DriveModi} über den Konstruktor zur Verfügung gestellt. Wenn keine Route übergeben wird, erzeugt die \texttt{Navigation} eine eigene. Da eine neue Route aufgezeichnet werden soll ist dieses Verhalten gewollt. \par Um die aktuellen Koordinaten der Route hinzuzufügen, muss der Aktions-Button auf der Fernbedienung gedrückt werden. Dadurch versucht \texttt{Navigation} die Route zu erweitern. Dies kann fehlschlagen, wenn die Genauigkeit der aktuellen Position nicht den eingestellten Anforderungen entspricht oder die aktuelle Position zu nah an der, sofern vorhanden, vorherigen ist. Der minimale Abstand zwischen zwei Punkten kann ebenfalls eingestellt werden. Auch der maximale Abstand zwischen zwei Punkten ist definiert und kann eingestellt werden. Wenn die gesamte Route aufgezeichnet wurde, kann der Modus verlassen werden. Dabei wird die Instanz von Navigationsklasse zerstört und damit auch die dort gehaltene Route. Deshalb wird diese zwischengespeichert und überschreibt gegebenen falls die zuletzt gespeicherte Route. Ein Überschreiben erfolgt nur wenn die Route mindesten über zwei Einträge verfügt. Die Datenhaltung der Route wird über statische Funktionen und Member in der Klasse \texttt{Route} realisiert, die zwischengespeicherte Route ist dementsprechend nicht persistent. \par Der Modus wird über einen Menüeintrag gestartet. Während der Modus aktiv ist, werden im Menü neben Informationen über Sensorwerte und die bisher aufgezeichnete Route auch Einstellungen zu der geforderten Genauigkeit geboten. \subsection{Modus - Route abfahren} \label{ssec:route_drive} Die Funktionalität, erfasste Routen abzufahren erfordert die Zusammenarbeit mehrerer Komponenten. Zunächst wird beschrieben wie die Navigationsklasse den Kurs zum Zielpunkt berechnet und die Navigationsanweisungen gibt und bestimmt ab wann ein Punkt als erreicht gilt. Die Anweisungen müssen von dem Autopiloten umgesetzt werden, dafür muss sich dieser auf den Zielpunkt Ausrichten und die Strecke mit angepasster Geschwindigkeit zurücklegen. \par Der letztendlich ausführende Modus nennt sich \texttt{Autopilot} und wird wie \texttt{CaptureRoute} in das System eingebunden, da dieser Modus, um den Rover an die Startposition der Route fahren zu können, ebenfalls von dem Modus zum manuellen Verfahren erbt. Während der Autopilot die Steuerung übernimmt, werden keine Eingaben von dem Joystick zum verfahren des Rovers akzeptiert. Wenn der Autopilot verfügbar ist kann er durchs betätigen der Aktions-Taste aktiviert werden und auch wieder deaktiviert werden. \par Auch der \texttt{Autopilot} verfügt über ein Menü über den dieser aufgerufen wird. Das Menü stellt Status-, Sensor-, Routen-, und Navigationsinformationen zur Verfügung und ermöglicht das Einstellen der wie präzise ein Punkt angefahren werden muss, ob nach Abschluss der Route diese von vorne gestartet werden soll und ob der aktuelle Zielpunkt eingefroren werden soll was dazu führt, dass die Route an diesem Punkt pausiert wird. \subsubsection{Kursberechnung} Das Ziel der Kursberechnung ist es ein vorzeichenbehaftete Kurskorrektur in Grad zu erzeugen. Dafür muss die aktuelle Ausrichtung bekannt sein. Für diese Information stehen drei Quellen zur Verfügung. \begin{itemize} \item Das Magnetometer liefert absolute Werte, welche die Ausrichtung laut Datenblatt !!!cite!!! im optimalen Fall auf \(2^\circ\) genau beschreiben. \item Die nächste Quelle ergibt sich aus den gefahrenen Strecken des Rovers. Dafür wird der erste Punkt nach einer Rotation und der letzte Punkt vor einer Rotation festgehalten und daraus die Ausrichtung mit der \mintinline{c++}|int16_t Point::courseTo(Point&);| Methode berechnet. Diese Variante ist bei kurzen Strecken ungenau und wird mit steigendem Abstand zwischen den Punkten genauer, wenn die Positionsbestimmung im niedrigen Zentimeter Bereich erfolgt. Sollte der Rover durch den Untergrund oder anderen Fehlern keineGerade fahren sondern ein leichte Kurve, wird dieses Verfahren ungenauer. \item Es bleibt noch das hinzugefügte Gyroskop, dieses kann keine absoluten Werte bestimmen. Dafür kann es präzise relative Drehwerte angeben. Es eignet sich also um bei einem vorgegebenen Winkel die Drehung zu überwachen. !!!Sensorfusion ausgeführt?!!! \end{itemize} Nachdem die Datenquelle ausgewählt wurde muss der Kurs von der aktuellen Position zum Zielpunkt berechnet werden. Von diesem Ergebnis wird die aktuelle Ausrichtung subtrahiert. Anschließend muss das Resultat auf den gewünschten Wertbereich normiert werden. \subsubsection{Navigationsanweisungen} Aus der berechneten Kurskorrektur und dem verbleibenden Abstand zum Zielpunkt wird Navigationsanweisung erstellt. Die Informationen in das folgende \mintinline{c++}|struct| verpackt: \begin{minted}[linenos, gobble=5, breaklines]{c++} struct CourseCorrection { int16_t correction; double distance; }; \end{minted} Wenn die Navigationsanweisungen bei der Navigationsklasse abgefragt werden muss das genannte \mintinline{c++}|struct| der Funktion als Referenz übergeben werden. Der Rückgabewert wird für das bereits beschriebene \mintinline{c++}|enum Navigation::Status| verwendet. Darüber wird mitgeteilt ob die Navigationsanweisungen aktualisiert wurden oder weshalb dies nicht geschah. Zum Beispiel wenn der Rover seine Position nicht wesentlich verändert hat, die aktuelle Positionsbestimmung zu ungenau ist oder das Ziel erreicht wurde. \subsubsection{Autopilot aufbau} Der Autopilot ist einen Zustandsautomaten nachempfunden. In den verschiedenen Zuständen können unterschiedliche und gleiche Funktionen aufgerufen werden. Die beiden häufigsten Funktionsaufrufe in den verschiedenen Status sollen erläutert werden: \begin{itemize} \item \mintinline{c++}|void Autopilot::askNavigationForOrder();| holt sich die aktuellen Navigationsanweisungen von \texttt{Navigation} und wertet dabei den zurückgegebenen Status aus. Durch diese Auswertung können Zustandsübergänge auftreten. Beispielsweise bei vollständiger abgefahrener Route oder mangelnder Genauigkeit bei der Positionsbestimmung. Sollte der zweite Fall eintreten wird der vorherige Zustand gespeichert, in welchen zurückgekehrt wird, wenn die Genauigkeit wieder den Anforderungen entspricht und \item \mintinline{c++}|void Autopilot::checkButtonInput();| überprüft ob der Aktions-Button gedrückt ist. Wenn die Eingabe vorliegt werden Zustandswechsel durchgeführt, wie selbstständiges Fahren aktivieren und deaktivieren. \end{itemize} Die folgende Tabelle \ref{tab:autopilot} listet die Zustände auf und beschreibt die Funktionalitäten der einzelnen Zustände. Dabei wird in der Spalte \texttt{Update} angegeben ob die Navigationsanweisungen mit der beschriebenen Funktion in diesem Zustand aktualisiert werden und mit der Spalte \texttt{Check} wird das gleich für die Überprüfung der Benutzereingaben dargestellt. \begin{table}[] \centering \begin{tabular}{|l|c|c|l|} \hline Zustand & \multicolumn{1}{l|}{Update} & \multicolumn{1}{l|}{Check} & Beschreibung \\ \hline InsufficientAccuracy & x & - & -Warten auf bessere Genauigkeit \\ \hline NoRoute & - & - & -Autopilot nicht verfügbar \\ \hline None & - & - & -Default Zustand zum Programmbeginn \\ \hline NavigationStarted & x & x & \begin{tabular}[c]{@{}l@{}}-Autopilot initialisiert\\ -Auf Benutzereingabe warten\end{tabular} \\ \hline GetToStartPoint & x & - & \begin{tabular}[c]{@{}l@{}}-Warten bis Benutzer den Rover in die \\ Nähe des Startpunktes gebracht hat\\ -Fahren mit dem Joystick möglich\end{tabular} \\ \hline SelfDrivingAvailable & x & x & \begin{tabular}[c]{@{}l@{}}-Autopilot bereit\\ -Auf Benutzereingabe warten\end{tabular} \\ \hline SelfDriving & x & x & \begin{tabular}[c]{@{}l@{}}-Rover fährt geradeaus bis die\\ Abweichung zu groß ist.\end{tabular} \\ \hline SelfDrivingRotate & x & - & -Abweichung korrigieren \\ \hline TargetReached & - & - & -Navigation abgeschlossen \\ \hline \end{tabular} \caption{Auflistung und Beschreibung der Zustände des Autopiloten} \label{tab:autopilot} \end{table} \subsubsection{Ausrichten} Wenn der Rover zu weit von dem Kurs abweicht und damit nicht mehr ausreichend genau auf den Zielpunkt ausgerichtet ist, wird von dem Zustand \texttt{SelfDriving} in den Zustand \texttt{SelfDrivingRotate} gewechselt. Dieser wechsel kann nur aus \texttt{SelfDriving} erfolgen und beginnt damit die Rotation einzuleiten. Dabei wird Drehrichtung der Rotation durch das Vorzeichen der gegebenen Kurskorrektur bestimmt. Ab diesem Zeitpunkt wird ständig überprüft, wann sich der Rover weit genug gedreht hat um die Rotation rechtzeitig zu beenden. Anschließend wird wieder in den vorherigen Zustand gewechselt. \subsubsection{Geschwindigkeit} Die Geschwindigkeit wird je nach Abstand zu dem Zielpunkt eingestellt. Dabei gibt es drei verschiedene Abstandszonen. Die Werte für Geschwindigkeit und Abstand werden in Tabelle \ref{tab:roverSpeed} beschrieben. Die Geschwindigkeit wird im Nahbereich deutlich reduziert um einfacher auf Abweichungen reagieren zu können. \begin{table}[] \centering \begin{tabular}{|l|c|c|} \hline Bereich & \multicolumn{1}{l|}{Abstand {[}m{]}} & \multicolumn{1}{l|}{Geschwindigkeit {[}m/s{]}} \\ \hline ferm & 2!!! & 2 \\ \hline mittel & 1!!! & 1 \\ \hline nah & 0,75!!! & 0,5 \\ \hline \end{tabular} \caption{Geschwindigkeit der Rovers je nach Abstand zum Zielpunkt} \label{tab:roverSpeed} \end{table}