diff --git a/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.pdf b/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.pdf index b564a5ac009b45afc09354f7384edf13bd23fc88..bc0a1abb8e829d4ef06bace46a4cea5935e4c91b 100644 Binary files a/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.pdf and b/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.pdf differ diff --git a/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.tex b/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.tex index feb6697cfcb71961880c0031f67d05232d49518c..c2b6957cb70c71cc508cabcce212494722084293 100644 --- a/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.tex +++ b/LeonardoMixerIO/doc/Dokumentation_Systemtechnik.tex @@ -70,7 +70,7 @@ Systems, welches eingehende Signale aus mehreren, ggf. unterschiedlichen Quellen erfassen und anschließend zu einem kombinierten Ausgangssignal verarbeiten kann. Konkret sollen hierbei die im Modellbau etablierte Protokolle Spektrum-Remote-Receiver und das Multiwii -Serial Protocol erfasst bzw. ausgegeben werden können. Die +Serial Protocol erfasst bzw.\ ausgegeben werden können. Die Applikation soll auf Mikroprozessoren der Reihe Atmega implementiert werden. @@ -107,6 +107,7 @@ Echtzeitfähigkeit beschreibt in der Informationstechnik also die Fähigkeit, je Daten innerhalb eines fest definierten Zeitraumes verarbeiten zu können. \subsection{Kooperatives Multitasking} +\label{multitasking} Multitasking im Allgemeinen bezeichnet die Verarbeitung einer Vielzahl konkurrierender, quasiparalleler Tasks. Ein Scheduler dient der Ressourcen- und Taskverwaltung. Beim kooperativen Multitasking können Tasks garnicht oder nur dann unterbochen werden, @@ -199,7 +200,7 @@ Jedes dieser Protokolle ist dazu geeignet, mindestens sechs Steuerkanäle zu üb \begin{itemize} \item{Spektrum-Remote-Receiver\\ Das Spektrum-Remote-Receiver Protokoll wird von sog.\ Satelliten-Empfängern des Herstellers -Spektrum bzw. Horizon Hobby dazu kompatiblen Systemen verwendet, um mit einem Hauptempfänger +Spektrum bzw.\ Horizon Hobby und dazu kompatiblen Systemen verwendet, um mit einem Hauptempfänger oder einem Flugcontroller zu kommunizieren. Ursprünglich diente es lediglich der Erhöhung der Ausfall- und Übertragungssicherheit der Funkverbingung zwischen Fernsteuerung und Empfänger durch das Vernetzen mehrerer, @@ -209,12 +210,12 @@ Mehrere erfolgreiche Reverse-Engineering Ansätze ermöglichten jedoch bald die Verwendung dieser kostengünstigen Satellitenempfänger mit Flugsteuerungen. Horizon Hobby reagierte schließlich mit dem begrüßenswerten Entschluss, eine offizielle Spezifikation dieses Protokolls mitsamt einer rudimentären Implementierungsanleitung -zu veröffentlichen.\cite[][2]{spek2016} +zu veröffentlichen \cite[][2]{spek2016}. } \item{SRXL\\ Das Serial Receiver Link Protocol stellt ein offenes Protokoll dar, mit dem Ziel die Kommunikation zwischen Modellbau-Komponenten unterschiedlicher Hersteller zu ermöglichen. Es können in -SRXL Version 2 bis zu 16 Kanäle übertragen werden.\cite[][1]{multiplex2013} +SRXL Version 2 bis zu 16 Kanäle übertragen werden \cite[][1]{multiplex2013}. } \item{MSP\\ Das MultiWii-Serial Protokoll ist eine offenes Protokoll zur Kommunikation unterschiedlichster @@ -426,15 +427,14 @@ struct linkedListElement { void *next; }; \end{lstlisting} + Der Scheduler kann Realtime-Tasks (abgekürzt mittels \glqq{}rtTask\grqq{}) und Non-Realtime-Tasks (abgekürzt mittels \glqq{}nRtTask\grqq{}) verwalten. -Dabei besteht jeder Task grundlegend aus einer Funktion, die ihm bei der -Initialisierung zugewiesen werden kann und einem Zeitstempel, in dem seine letzte +Dabei besteht jeder Task aus einer Funktion, die ihm bei der Initialisierung zugewiesen werden kann und einem Zeitstempel, in dem seine letzte Ausführungszeit gespeichert wird. Es ist dabei zu beachten, dass lediglich Funktionen ohne Übergabeparameter und Rückgabe-Werte zulässig sind, da der Scheduler eine reine Taskverwaltung und keine datenverarbeitende Instanz darstellt. -Der Datenaustausch zwischen den Tasks ist mittels globaler Variablen wie bspw.\ -dem \lstinline{rcSource}-Struct realisiert. +Der Datenaustausch zwischen den Tasks ist über einen gemeinsamen Speicherbereich in Form globaler Variablen wie bspw.\ dem \lstinline{rcSource}-Struct möglich. Die Datenstrukturen \lstinline{rtTask} und \lstinline{nRtTask} erben beide direkt von \lstinline{task} mit dem einzigen Unterschied, dass Realtime-Tasks eine Zykluszeit @@ -444,13 +444,13 @@ lediglich einmal für beide Typen zu definieren (vgl.\ beispielsweise \lstinline Weiterhin ergibt sich durch die grundsätzlich gleiche Datenstruktur von \lstinline{rtTask} und \lstinline{nRtTask} die Möglichkeit, äquivalent auf die Attribute \lstinline{cycleTime} und \lstinline{priority} zuzugreifen (d.\,h.\ über die Funktion \lstinline{getTaskCycleTime} -kann auf einen Non-Realtime-Task dessen Priorität erhalten werden). +kann bei einem Non-Realtime-Task dessen Priorität erhalten werden). Die Datenstruktur \lstinline{linkedListElement} stellt einzelne Elemente einer -verknüpften Liste bereit. Diese enthalten jeweils einen Pointer auf einen Task +verketteten Liste bereit. Diese enthalten jeweils einen Pointer auf einen Task (und sind damit zunächst unabhängig davon, ob es sich um einen Realtime- oder einen Non-Realtime-Task handelt) und einen Pointer auf das nächste Listenelement. -Die durch die Verknüpfung der Elemtente entstehende Liste ist unidirektional, +Die durch die Verkettung der Elemtente entstehende Liste ist unidirektional, d.\,h.\ sie kann nur von vorne nach hinten, nicht jedoch andersherum durchlaufen werden. \begin{lstlisting}[caption=Festlegen der Threshold-Werte] @@ -459,22 +459,22 @@ d.\,h.\ sie kann nur von vorne nach hinten, nicht jedoch andersherum durchlaufen #define OVERLOAD_THRESHOLD_TIMES 100 #define STARVATION_THRESHOLD 100000 \end{lstlisting} + Über die Threshold-Werte können verschiedene Eigenschaften der Taskverwaltung beeinflusst werden. Mittels \lstinline{MAX_TASK_THRESHOLD} lässt sich die maximal -zulässige Anzahl an Realtime- und Non-Realtime-Taks (jeweils) festlegen, um einer +zulässige Anzahl an Realtime- und Non-Realtime-Taks (jeweils) festlegen. Dies dient dazu, einer Überlast vorzubeugen und sicherzustellen zu können, dass das übergebene Task-Array korrekterweise mit einer \lstinline{NULL} beendet wird. \lstinline{OVERLOAD_THRESHOLD_PERCENT} und \lstinline{OVERLOAD_THRESHOLD_TIMES} legen fest, wie häufig ein Realtime-Task bei seiner tatsächlichen Ausführung um wieviel Prozent von seiner vorgesehenen Ausführungszeit abweichen darf, bevor der -Scheduler sich abschaltet, da er aus Überlastgründen keine Echtzeitfähigkeit mehr -gewährleisten kann. +Scheduler sich aus Überlast abschaltet. Somit wird die Echtzeitfähigkeit während des Betriebs gewährleistet. Mittels \lstinline{STARVATION_THRESHOLD} lässt sich weiterhin eine Grenze für die Differenz zwischen letzter Ausführungszeit und aktueller Systemzeit festlegen, ab deren Überschreitung ein Non-Realtime-Task temporär in seiner Priorität erhöht -und somit für einen Zyklus priorisiert ausgeführt wird, um Starvation vorzubeugen. +und somit für einen Zyklus priorisiert ausgeführt wird. Durch diese Maßnahme wird Starvation (s. Kapitel \ref{multitasking}) vorzubeugen. \subsection{Scheduler.cpp} \label{Scheduler.cpp} @@ -500,6 +500,7 @@ Scheduler::Scheduler (rtTask **newRtTasks, nRtTask **newNRtTask) { setNRtTasks(newNRtTask); } \end{lstlisting} + Der Scheduler wird mittels des Konstruktors initialisiert. Beim Aufruf können zwei seperate Arrays mit Pointern auf Realtime- und Non-Realtime-Tasks übergeben werden (das erste Array enthält alle Realtime-Tasks, das zweite Array alle @@ -508,12 +509,8 @@ enthalten, um das Ende zu kennzeichnen. Sollen nur Echtzeit- oder nur Nicht-Echtzeit-Tasks verwaltet werden, oder sollen die Arrays eigenständig mittels der Funktionen \lstinline{setRtTasks(...)} und \lstinline{setNRtTasks(...)} gesetzt werden, so kann dies durch die Übergabe eines Nullpointers an der entsprechend anderen -Stelle beim Konstruktoraufruf signalisiert werden. Standardmäßig werden alle in -der Bibliothek deklarierten, pointerartigen Elemente mit \lstinline{NULL} initialisert; -alle (Zahlen-)Counter werden auf den Wert null gesetzt. Anschließend werden die -Funktionen \lstinline{setRtTasks(...)} und \lstinline{setNRtTasks(...)} aufgerufen. +Stelle beim Konstruktoraufruf signalisiert werden. -\pagebreak \begin{lstlisting}[caption=setNRtTasks] // Sorts and sets the input-array as the new non-realtime-task- // array; the last @@ -542,19 +539,18 @@ void Scheduler::setNRtTasks (nRtTask **newNRtTasks) { } } \end{lstlisting} + Die Funktion \lstinline{setNRtTasks(...)} verarbeitet das übergebene Array mit Zeigern auf Non-Real"=time-Task vor und weist es der Programmintern verwendeten Variable \lstinline{nRtTasks} zu. Zunächst werden die Tasks in dem Array gezählt. Wie bereits erwähnt, muss das übergebene Array am Ende einen Nullpointer enthalten, um das Ende zu kennzeichnen. Überschreitet die Anzahl der Tasks den für \lstinline{MAX_TASK_THRESHOLD} festgelegten Wert (siehe Kapitel \ref{Scheduler.cpp}), -so gibt die Funktion, falls ein serieller Debugging-Port mittels \lstinline{setDebugger(...)} -übergeben wurde, eine Fehlermeldung aus und der Scheduler schaltet sich mittels -\lstinline{exterminate()} ab (bzw. konkret wechselt er in eine Dauerschleife). +so schaltet sich der Scheduler mittels +\lstinline{exterminate()} ab (bzw.\ konkret wechselt er in eine Dauerschleife). Nachdem die Tasks gezählt wurden, werden sie mittels \lstinline{sortTasks(...)} ihrer Priorität nach sortiert. Dies hat zur Folge, das das Array anschließend für -die Ausführungsreihenfolge der Tasks von vorne nach hinten durchlaufen werden kann, -ohne einen zweiten Prioritätscounter mitlaufen zu lassen (Effizienzsteigerung). +die Ausführungsreihenfolge der Tasks einfach von vorne nach hinten durchlaufen werden kann (Effizienzsteigerung). Wurde ein Nullpointer als Parameter übergeben oder ist der erste Eintrag im Array eine \lstinline{NULL}, so wird die Variable \lstinline{nRtTasks} ebenfalls auf \lstinline{NULL} gesetzt, wodurch signalisiert wird, dass es keine Nicht-Echtzeit-Tasks @@ -588,6 +584,7 @@ void Scheduler::setRtTasks (rtTask **newRtTasks) { } } \end{lstlisting} + Die Funktion \lstinline{setRtTasks(...)} dient, ebenso wie \lstinline{setNRtTasks(...)} der Vorverarbeitung und Zuweisung des übergebenen Arrays, dieses Mal jedoch die Echtzeit-kritischen-Tasks betreffend. Der Aufbau Funktion ist analog zu @@ -647,25 +644,25 @@ void Scheduler::sortTasks(task **tasks, int left, int right) { } } \end{lstlisting} -Bei \lstinline{sortTasks(...)} handelt es sich um einen Heapsort-Algorithmus mit einer -Ordnung von $\mathcal{O}(n\cdot\log n)$. Dieser sortiert das übergebene Array -entweder nach Zykluszeiten oder nach Prioritäten (abhängig davon, ob ein Array mit + +Bei \lstinline{sortTasks(...)} handelt es sich um einen Heapsort-Algorithmus mit einer Ordnung von $\mathcal{O}(n\cdot\log n)$. Dieser sortiert das übergebene Array entweder nach Zykluszeiten oder nach Prioritäten (abhängig davon, ob ein Array mit Pointern auf Realtime- oder auf Non-Realtime-Task übergeben wurde). -Dadurch, dass als Typ des Übergabeparameters die Grund-Datenstruktur \lstinline{task} +Dadurch, dass als Typ des Übergabeparameters die Grund-Daten"=struktur \lstinline{task} gewählt wurde, können sowohl Echtzeit- als auch Nicht-Echtzeit-Task-Arrays verarbeitet werden. -Auf die Parameter \lstinline{cycle-time} bzw. \lstinline{priority} kann, da, +Auf die Parameter \lstinline{cycle-time} bzw.\ \lstinline{priority} kann, da, wie bereits in Kapitel \ref{Scheduler.h} angeführt, sowohl \lstinline{rtTask} als auch \lstinline{nRtTask} die gleiche Speicherstruktur haben, analog über die Funktion \lstinline{getTaskCycleTime(...)} zugegriffen werden. -Der Vorteil des Heapsort-Algorithmus gegenüber dem aus Quicksort-Verfahren besteht darin, -dass ersterer iterativ abläuft, während letzterer rekursiv aufgerufen wird. +Der Vorteil des Heapsort-Algorithmus gegenüber Sortierverfahren wie bspw.\ dem Quicksort besteht darin, dass ersterer iterativ abläuft, während letzterer rekursiv aufgerufen wird. Somit wird einem Überlaufen des Stacks des Mikrokontrollers vorgebeugt. Die bereits erwähnte Ordnung des Heapsorts ist darüber hinaus unabhängig vom Inhalt -des zu sortierenden Arrays, sie ist konstant. Sein Verhalten ist folglich deterministisch, -weswegen er sich für die gegebene echtzeitkritische Anwendung anbietet. +des zu sortierenden Arrays, sie ist konstant. Sein Verhalten ist folglich deterministisch, was ihn für die Verwendung in echtzeitkritischen Anwendung prädestiniert. Dies ist durchaus insofern von Relevanz, da die Neusorortierung von Nicht-Echtzeit-Tasks z.\,B.\ bei Starvation eines Tasks auch während des laufenden Betriebs erfolgt. +\\ +\\ +Anmerkung 1: Für eine geringe Anzahl an Tasks bzw.\ für den Fall, dass Starvation kein Problem in der gegebenen Anwendung darstellen sollte, kann für eine Performanceverbesserung ein Algorithmus wie bspw.\ Bubblesort verwendet werden. Ist hingegen nicht zwangsläufig gegeben, dass die zu sortierenden Arrays weitestgehend vorsortiert sind, ist der Heapsort aufgrund seines deterministischen Verhaltens zu präferieren. \\ \\ -Anmerkung: Für die Herleitung und Grundlagen des Heapsort-Algorithmus vergleiche +Anmerkung 2: Für die Herleitung und Grundlagen des Heapsort-Algorithmus vergleiche \cite[][ S.186-192]{sedgewick1992} und \cite[][ S.191-197]{baumann1981}. Die hiesige Implementation orientiert sich an \cite[][ S.336-338]{numRecC1992}. @@ -693,14 +690,15 @@ linkedListElement * Scheduler::convertToLinkedList (task **tasks) return firstElement; } \end{lstlisting} + Mittels \lstinline{convertToLinkedList(...)} wird das übergebene Array mit Pointern auf Tasks in eine einfach verkettete Liste umgewandelt und der Zeiger auf das erste Element der Liste zurückgegeben. Grundsätzlich ist die Implementierung der Funktion unabhängig davon, -ob Realtime- oder Non-Realtime-Tasks übergeben werden; konkret werden jedoch lediglich +ob Realtime- oder Non-Realtime-Tasks übergeben werden. Konkret werden jedoch lediglich die Echtzeit-Tasks in Listenform verwaltet, da sich durch den Zugriffsalgorithmus an dieser Stelle Zeiteinsparungen erzielen lassen, während sich die Effizienz bei Nicht-Echtzeit-Tasks gegenüber der Array-Speicherform verschlechtern würde -(Quicksort ist besser für Arrays als für einfach verkettete Listen geeignet). +(Heapsort ist besser für Arrays als für einfach verkettete Listen geeignet). Zunächst wird mit \lstinline{new_pointer} ein Zeiger auf ein mittels der Funktion \lstinline{newLinkedList-} @@ -709,7 +707,7 @@ Diesem werden der Task an der aktuellen Stelle des übergebenen Task-Arrays und ein Nullpointer als Adresse des nächsten Elements zugewiesen. Anschließend wird überprüft, ob bereits ein vorangegangenes Listenelement existiert. Ist dies der Fall, wird \lstinline{listElementPointer->next} auf die Adresse des neu -erzeugten Elements gesetzt; falls nicht, wird die Adresse als Einstiegspunkt der +erzeugten Elements gesetzt. Falls nicht, wird die Adresse als Einstiegspunkt der Liste in \lstinline{firstElement} gespeichert und später zurückgegeben. Danach wird mit \lstinline{listElementPointer} die Variable in der die Adresse des letzten erzeugten \lstinline{linkedListElement} gespeichert ist, auf @@ -733,6 +731,7 @@ linkedListElement * Scheduler::newLinkedListElement (void){ } } \end{lstlisting} + Die Funktion \lstinline{newLinkedListElement()} gibt als Rückgabewert einen mit jedem Aufruf fortlaufenden Zeiger auf ein \lstinline{linkedListElement} aus einem in \lstinline{setRtTasks(...)} initialisierten Array der Größe \lstinline{MAX_TASK_THRESHOLD} @@ -772,6 +771,7 @@ linkedListElement * Scheduler::sortRtTasks (linkedListElement } } \end{lstlisting} + Die Funktion \lstinline{sortRtTasks(...)} wird direkt nach Ausführen eines Realtime-Tasks aufgerufen und ordnet das übergebene (standardmäßig das gerade ausgeführte) Element der verknüpften Liste abhängig von seinem nächsten Ausführzeitpunkt in die Liste ein. @@ -782,11 +782,11 @@ Listen-Element existiert und ob der Zeitpunkt der nächsten Ausführung vor dem des übergebene Elements liegt. Ist dies nicht der Fall, wird die Liste nicht modifiziert und der Zeiger auf das aktuelle Element zurückgegeben. Ansonsten werden die Elemente solange durchlaufen, wie die Ausführungszeit des betrachteten Tasks vor derjenigen -des übergebenen Tasks liegt oder die Liste zu Ende ist. Anschließend wird das +des übergebenen Tasks liegt oder bis die Liste zu Ende ist. Anschließend wird das übergebene Element an der entsprechenden Stelle einsortiert und der Zeiger auf den ehemals zweiten Task (der jetzt der als Nächstes auszuführende ist) zurückgegeben. -Somit wird im schlechtesten Fall eine Ordnung von O(n) erreicht, während der -äquivalente Vorgang in einem herkömmlichen Array eine Ordnung von O(n\^2) hätte. +Somit wird im schlechtesten Fall eine Ordnung von $O(n)$ erreicht, während der +äquivalente Vorgang in einem herkömmlichen Array eine Ordnung von $O(n^2)$ hätte. \begin{lstlisting}[caption=schedule] // Scheduler, called cyclical in the loop-function @@ -832,6 +832,7 @@ void Scheduler::schedule (void) { } } \end{lstlisting} + Die Funktion \lstinline{schedule()} wird zyklisch vom Mikrocontroller aufgerufen und bildet das Herzstück der Taskverwaltung. Grundsätzlich werden drei möglich Fälle unterschieden: \begin{itemize} @@ -844,16 +845,16 @@ bildet das Herzstück der Taskverwaltung. Grundsätzlich werden drei möglich F die für die Verwaltung der Nicht-Echtzeit-Tasks zuständig ist.} \item{Es sind Realtime-Tasks vorhanden. In diesem Fall überprüft der Scheduler zunächst, ob innerhalb des aktuellen Zyklus noch Zeit für die Ausführung von Non-Realtime-Tasks ist. - Hierzu wird die vorraussichtliche Ausführungszeit des nächsten Realitme-Tasks - mit der verbleibenden Zykluszeit verglichen. Ist noch Zeit übrig und sind Non-Realtime-Tasks + Hierzu wird der vorraussichtliche Ausführungszeitpunkt des nächsten Realitme-Tasks + mit der aktuellen Zykluszeit verglichen. Ist noch Zeit übrig und sind Non-Realtime-Tasks vorhanden, so wird \lstinline{perform()} aufgerufen. Ansonsten wird der Realtime-Task abgearbeitet, sein Timestamp wird aktualisiert und er wird abhängig von seinem nächsten vorgesehenen Ausführungszeitpunkt mittels - \lstinline{sortRtTasks(...)} in die einfach verkettete Liste der Echtzeit-Tasks einsortiert. - Existieren weiterhin zu verwaltende Non-Realtime-Tasks, so wird abschließend die + \lstinline{sortRtTasks(...)} in die einfach verkettete Liste der Echtzeit-Tasks einsortiert. Existieren weiterhin zu verwaltende Non-Realtime-Tasks, so wird abschließend die Funktion \lstinline{setPriorities()} aufgerufen, um gegebenenfalls mittels dynamischer Prioritätenvergabe Starvation zu verhindern. Abschließend wird der Zeiger auf den - aktuellen Nicht-Echtzeit-Task zurückgesetzt.} + aktuellen Nicht-Echtzeit-Task zurückgesetzt. \\ + Es handelt sich bei dieser Art der Taskverwaltung um einen reaktive Ansatz (auf den Ausführungszeitpunkt eines Echtzeit-Tasks wird nach dessen Eintreten reagiert).} \end{itemize} \begin{lstlisting}[caption=perform] @@ -869,6 +870,7 @@ void Scheduler::perform (void) { } } \end{lstlisting} + Die Funktion \lstinline{perform()} verwaltet die Ausführung der Non-Realtime-Tasks. \lstinline{taskCounter} zeigt dabei immer auf die Speicheradresse des aktuellen Tasks. Bei jedem Aufruf der Funktion wird dieser abgearbeitet, sein @@ -896,6 +898,7 @@ void Scheduler::setPriorities (void) { } } \end{lstlisting} + Mittels der Funktion \lstinline{setPriorities()} lassen sich während der Laufzeit der Taskverwaltung durch Verschiebung der Non-Realtime-Tasks innerhalb des Arrays temporär neue Prioritäten vergeben um so Starvation vorzubeugen. @@ -919,12 +922,15 @@ void Scheduler::exterminate (void){ while (true); } \end{lstlisting} + Mit Hilfe der Funktion \lstinline{exterminate()} kann der Scheduler beim Auftreten eines Fehlers in einen definierten Zustand überführt werden. Erreicht wird dies mittels des Eintretens in eine Dauerschleife. Somit wird verhindert, dass unvorhersehbares Verhalten auftritt. -\section{Erstellung eines allgemeinen Mischer-Frameworks} +\chapter{Erstellung eines allgemeinen Mischer-Frameworks} + +\section{Implementierung der Mischerfunktionalität} In Anbetracht der großen Anzahl an bereits existierenden Protokollen zur Kommunikation mit Modellbau-Empfängern und in Hinblick auf die Erweiterbarkeit und Portierbarkeit dieses Projektes erschien es als angemessen und sinnvoll, den RC-Mischer modular @@ -957,7 +963,6 @@ struct rcSource #endif \end{lstlisting} - \subsection{Realisierung des Mischerverhaltens} Gehen wir nun davon aus, dass wir Daten aus unterschiedlichen Quellen in Form des soeben vorgestellten Structs vorliegen haben. Diese sollen nun in einer Anwendungs-spezifischen @@ -979,6 +984,7 @@ class Mixer rcSource *_out, *_in0, *_in1; }; \end{lstlisting} + Wie in Mixer.h zu erkennen, liegt die einfachste Form eines Mischers vor. Daten aus lediglich zwei Quellen werden eingelesen und zu einem einzigen ausgehenden Datenstrom verarbeitet. Der Datenaustausch findet gemäß dem vorangegangenen Abschnitt @@ -1008,11 +1014,11 @@ void Mixer::mix() _out->timestamp = micros(); } \end{lstlisting} -Die Verarbeitung bzw. Vermischung der eingehenden Daten findet in der Funktion \lstinline{mix()} statt. + +Die Verarbeitung bzw.\ Vermischung der eingehenden Daten findet in der Funktion \lstinline{mix()} statt. Sicherheit im Sinne von Wahrung der manuellen Kontrolle über das System zu jedem Zeitpunkt ist hier das Hauptaugenmerk. So befindet sich der Mischer zunächst in -einem inaktiven Zustand, in welchem er lediglich die an \lstinline{in0} vorliegenden Daten in -out kopiert. \lstinline{in0} stellt hierbei die von der Fernsteuerung empfangengen Daten dar. +einem inaktiven Zustand, in welchem er lediglich die an \lstinline{in0} vorliegenden Daten in \lstinline{out} kopiert. \lstinline{in0} stellt hierbei die von der Fernsteuerung empfangengen Daten dar. Erst wenn ein frei definierbarer Kanal der \lstinline{in0} Quelle, also der Fernsteuerung mit welcher das Fluggerät manuell geflogen wird, einen ebenso frei definierbaren Wert überschreitet, werden die Daten aus der Sekundär-Quelle \lstinline{in1} mit den Daten aus der @@ -1026,12 +1032,15 @@ Andere Konfigurationen sind selbstverständlich möglich, sollte dies die konkre Anwendung erfordern. \section{Vernetzung der Systemkomponenten} + \begin{figure}[hb] \centering \includegraphics[width=\textwidth, trim = 0cm 1cm 0cm 1cm, clip]{graphics/diag-LeonardoMixerIO.pdf} \caption{Blockdiagramm des Systems} \label{fig:diag-LeonardoMixerIO} -\end{figure}Wie in Abbildung \ref{fig:diag-LeonardoMixerIO} zu erkennen, ist im Rahmen dieses Projektes die Kommunikation +\end{figure} + +Wie in Abbildung \ref{fig:diag-LeonardoMixerIO} zu erkennen, ist im Rahmen dieses Projektes die Kommunikation zwischen drei wesentlichen Komponenten herzustellen und aufrecht zu erhalten. Im konventionellen Betrieb eines Flugmodells oder Quadrocopters besteht zwischen Flugsteuerung und Fernsteuerungs-Empfänger eine direkte Verbindung. @@ -1044,9 +1053,9 @@ die Anbindung an die beiden verwendeten Quellen, und im Anschluss die Anbindung die verwendete Flugsteuerung erläutert werden. \subsection{Anbindung an die Android-Applikation} -Der Datenaustausch mit der Android-Applikation erfolgt uni-direktional, in Form -eines simplen byte-Streams über eine serielle Schnittstelle. Diese serielle Schnittstelle -ist im Falle des Arduino Leonardo bzw. des Atmega 32u4 als virtueller CDC-USB-ComPort +Der Datenaustausch mit der Android-Applikation erfolgt unidirektional, in Form +eines simplen Byte-Streams über eine serielle Schnittstelle. Diese serielle Schnittstelle +ist im Falle des Arduino Leonardo bzw.\ des Atmega 32u4 als virtueller CDC-USB-ComPort realisiert. Auf eine bi-direktionale Kommunikation wurde verzichtet, da ein erneutes Anfordern potentiell ungültiger oder falsch übertragender Daten allenfalls zu einer Neuübertragung @@ -1082,9 +1091,10 @@ class RawSerial uint16_t channelData[SERIAL_MAX_SUPPORTED_CHANNEL_COUNT]; }; \end{lstlisting} + Die Klasse \lstinline{RawSerial} ist bei Instanzierung mit einem Zeiger auf ein rcSource Objekt im Konstruktor zu versehen. Dieses dient dem Datenaustausch mit Funktionen anderer Klassen. -Die Methode \lstinline{init(Serial_ *raw_Serial)} bzw. \lstinline{init(HardwareSerial *raw_Serial)} +Die Methode \lstinline{init(Serial_ *raw_Serial)} bzw.\ \lstinline{init(HardwareSerial *raw_Serial)} dient der Übergabe und Initialisierung der zu verwendenen seriellen Schnittstelle. Hier ist derzeit je nach verwendeter Art der seriellen Schnittstelle eine manuelle Anpassung im Programmcode der Klasse notwendig, da im Falle des Arduino Leonardos @@ -1126,6 +1136,7 @@ void RawSerial::getData() _source->timestamp = micros(); } \end{lstlisting} + Die abgebildete Funktion \lstinline{getData()} skaliert den Wertebereich der empfangenden Daten um den Faktor 4 auf 0-1024 und verschiebt diesen darüber hinaus um 1024, so dass sich ein resultierender Wertebereich von 1024-2048 ergibt, welcher dem angestrebten @@ -1145,7 +1156,7 @@ und dem Mischer zur Verfügung zu stellen. Die Wahl des verwendeten Funkempfängers fiel aus mehreren Gründen auf einen kompakten und leichten Spektrum-kompatiblen Empfänger, einen sog.\ Satelliten-Empfänger. Ausschlaggebend für diese Wahl war die Bereitstellung einer Implementierungs-Anleitung -von Seiten Spektrums bzw. Horizon Hobbys (vgl.\ \cite[][]{spek2016}). Darüber hinaus +von Seiten Spektrums bzw.\ Horizon Hobbys (vgl.\ \cite[][]{spek2016}). Darüber hinaus findet das Spektrum DSMX Protokoll im europäischen und amerikanischen Raum große Verbreitung und es stehen zahlreiche kompatible und preisgünstige Fernsteuerungen zur Verfügung, welche dieses Protokoll unterstützen. Dies unterstützt das Ziel dieser @@ -1181,16 +1192,17 @@ class Spektrum uint16_t channelData[SPEKTRUM_MAX_SUPPORTED_CHANNEL_COUNT]; }; \end{lstlisting} + Der Spektrum-Remote-Receiver überträgt die empfangenen Daten ebenfalls uni-direktional mittels einer einfachen seriellen Schnittstelle gemäß der untenstehenden Spezifikation: \begin{quote} In normal operation, the Spektrum remotes issue a 16-byte data packet every 11ms or 22ms, depending -upon the selected protocol. The packet is transmitted at 125000bps, 8 bits, No parity, 1 stop (8N1). -For those UARTs which are not capable of that speed, they will also work at the more-standard -115200bps. + upon the selected protocol. The packet is transmitted at 125000bps, 8 bits, No parity, 1 stop (8N1). + For those UARTs which are not capable of that speed, they will also work at the more-standard + 115200bps. (vgl.\ \cite[][2]{spek2016}) \end{quote}Die Formatierung dieser empfangenen Daten unterscheidet sich grundlegend von dem -simplen Protokoll, welches im vorrangegangenen Abschnitt vorgestellt wurde. +simplen Protokoll, welches im vorangegangenen Abschnitt vorgestellt wurde. Sie ist ausführlich in dem von Horizon Hobby, LLC herausgegebenen Dokument beschrieben: \begin{quote} [...][T]he first two bytes (fieldname “fades” in Section 8.4 below) indicate the fade @@ -1201,7 +1213,9 @@ Sie ist ausführlich in dem von Horizon Hobby, LLC herausgegebenen Dokument besc is the msb. (vgl.\ \cite[][3,4]{spek2016}) \end{quote} + \newpage + \begin{lstlisting}[caption=Spektrum::dataReceive()] void Spektrum::dataReceive() { @@ -1222,6 +1236,7 @@ void Spektrum::dataReceive() } } \end{lstlisting} + Die obenstehende Methode \lstinline{dataReceive()} liest zunächst die vom Empfänger geschriebenen Daten aus dem Puffer der seriellen Schnittstelle. Anschließend werden diese nach folgendem Schema ausgelesen und klassenintern in \lstinline{channelData[]} gespeichert: @@ -1259,7 +1274,9 @@ Eintrag in dem MultiWii-Wiki (vgl.\ \cite[][]{multiWii2015}) lediglich eine Übe über die verfügbaren Datenfelder bietet, wurde an dieser Stelle auf die Umsetzung des MSP in Cleanflight zurückgegriffen, um sich anhand dieser ein Verständnis der Funktionsweise der Datenübertragung mittels MSP zu erarbeiten. + \newpage + \begin{lstlisting}[caption=MultiWiiSerial.h - Auszug] #define MSP_MAX_SUPPORTED_CHANNEL_COUNT 16 #define MSP_FRAME_SIZE 16*2 // two bytes per channel @@ -1282,6 +1299,7 @@ class MultiWiiSerial uint16_t channelData[MSP_MAX_SUPPORTED_CHANNEL_COUNT]; }; \end{lstlisting} + Die Klasse \lstinline{MultiWiiSerial} wird analog zu den bereits vorgestellten Empfangs-Klassen instanziiert. Der \lstinline{void init(HardwareSerial *msp_Serial)} Methode wird die Referenz auf eine serielle Schnittstelle übergeben. @@ -1305,12 +1323,11 @@ crc & = XOR of <size>, <command> and each data byte into a zero'ed sum \\ \end{tabular} \cite[][]{multiWii2015} \end{quote} -Die Implementierung dieses Protokolls gestaltet sich als verhältnismäßig einfach, +Die Implementierung dieses Protokolls gestaltet sich als verhältnismäßig einfach; die folgende Methode \lstinline{SerialEncode()} ist speziell und ausschließlich für das Bilden und Senden sogenannter \glqq{}MSP\_SET\_RAW\_RC\grqq{}-Pakete (message\_id = 200, vgl.\ \cite[][]{multiWii2015}) geschrieben. -\pagebreak \begin{lstlisting}[caption=MultiWiiSerial::SerialEncode()] void MultiWiiSerial::SerialEncode() { @@ -1353,9 +1370,8 @@ des Mischerverhaltens, genauer der Gewichtung der vom Mobiltelefon empfangenen K kann zur Laufzeit und aus der Ferne über einen freien Proportional-Kanal der verwendeten Fernsteuerung erfolgen. Dies erwies sich während der Testflüge als ausgesprochen hilfreich. -Die Parametrisierung des Schedulers ist nicht zur Laufzeit möglich, dies wäre für -dieses Projekt jedoch auch nicht zielführend. -Sie erfolgt innerhalb der \lstinline{setup()} Methode der LeonardoMixerIO.cpp: +Die Parametrisierung des Schedulers erfolgt innerhalb der \lstinline{setup()} Methode der LeonardoMixerIO.cpp: + \begin{lstlisting}[caption=Parametrisierung des Schedulers] nRtTask42.priority = 3; nRtTask42.activity = doSomething_Function; @@ -1368,10 +1384,12 @@ Sie erfolgt innerhalb der \lstinline{setup()} Methode der LeonardoMixerIO.cpp: scheduler = new Scheduler(rtTasks, nRtTasks); //scheduler->setDebugger(&Serial); \end{lstlisting} + Die hierbei hervorzuhebenden Parameter sind die \lstinline{cycleTime} der echtzeitkritischen Tasks sowie die \lstinline{priority} der nicht-echtzeitkritischen Tasks. Diese wurden für den Flugbetrieb wie folgt gewählt: + \begin{lstlisting} readRawSerial.priority = 1; readSpektrum.priority = 1; @@ -1380,6 +1398,7 @@ Diese wurden für den Flugbetrieb wie folgt gewählt: send.cycleTime = 20000; \end{lstlisting} + Mit den Funktionen, welche Daten empfangen und das lokale Daten-Abbild aktualisieren als den höchstprioren nicht-echtzeitkritischen Tasks, dem eigentlichen Mischer als nächst-priorem und der LCD-Ausgabe (nur im stationären Laborbetrieb im Rahmen des Debugging) @@ -1388,7 +1407,7 @@ Das Senden der Daten an die Flugsteuerung ist echtzeit-kritisch und erfolgt mit einer vorgegebenen Zykluszeit von 20ms. \section{Testbedingungen} -Getestet wurde der Mischer auf der im Rahmen des Schwesterprojektes VBLS genutzten +Getestet wurde der Mischer auf der im Rahmen des Parallelprojekts \glqq{}VBLS\grqq{} \footnote{VBLS - \url{https://gitlab.cvh-server.de/lf.ps/vbls/tree/master/Visual-Based-Landing-System}} genutzten Flugplattform, einem Quadrocopter in X-Anordung. In Abbildung \ref{fig:pic-quad-detail-sexy} gut zu erkennen ist der schichtweise Aufbau des @@ -1444,25 +1463,14 @@ Nicht nur konnte eine Vernetzung der Einzelkomponenten RC-Empfänger, Mobiltelef und Flugsteuerung hergestellt und im Testbetrieb aufrecht erhalten werden, diese konnte sich auch in mehreren Testflügen über einen Zeitraum von insgesamt mehr als 60 Minuten bewähren. - -\section{Persönliches Fazit} -Ergänzend zu dem vorangegangenen inhaltlichen Fazit möchten wir zum Ende dieser -Dokumentation noch kurz unser persönliches Fazit ziehen. - -Die Entwicklung dieses Systems hat uns als Autoren der hierfür nötigen Software -und dieser Dokumentation einiges an Zeit gekostet. Zusammenfassend lässt sich jedoch -sagen, dass diese Zeit ausgesprochen sinnvoll investiert ist und die gewonnenen -Erkenntnisse und Erfahrungen den nötigen Aufwand mehr als rechtfertigen. Auch konnten -wir als Team von einem regen Wissens- und Erfahrungsaustausch untereinander profitieren. -So konnte jeder von uns sein eigenes Wissen und seine persönlichen Fähigkeiten voll -in dieses Projekt einbringen. Dies freut uns sehr. - +\todo{Bezug auf gemessene Zykluszeiten nehmen} \chapter{Ausblick} Wie in der Zusammenfassung bereits verdeutlich, konnten alle Projektziele erreicht -werden. Der modulare Aufbau dieses Projektes bzw. des diesem zugrunde liegenden Programms +werden. Der modulare Aufbau dieses Projektes bzw.\ des diesem zugrunde liegenden Programms lädt jedoch zu Erweiterungen und Modifikationen ein: \begin{itemize} +\item{Implementierung eines präventiven (im Gegensatz zum vorhandenen reaktiven) Ansatz der Taskverwaltung, d.\,h.\ lediglich Ausführen eines Nicht-Echtzeit-Tasks, wenn dessen durchschnittlich benötigte Ausführungszeit geringer ist, als die Differenz zwischen aktuellem Zeitpunkt und dem Ausführungszeitpunkt des nächsten Echtzeit-Tasks. Somit könnte künstlich nahezu harte Echtzeit geschaffen werden} \item{Erweiterung um weitere Protokolle} \item{Erweiterung des eigentlichen Mischer-Codes, beispielsweise um eine Möglichkeit der Parametrisierung zur Laufzeit, etwa mittels eines Kommandozeileninterfaces. @@ -1478,6 +1486,21 @@ bereitgestellt werden können.} \printbibliography[heading = bib] \chapter{Anhang} + +\section{Persönliches Fazit} +Ergänzend zu dem vorangegangenen inhaltlichen Fazit möchten wir zum Ende dieser +Dokumentation noch kurz unser persönliches Fazit ziehen. +\\ +\\ +Die Entwicklung dieses Systems hat uns als Autoren der hierfür nötigen Software +und dieser Dokumentation einiges an Zeit gekostet. Zusammenfassend lässt sich jedoch +sagen, dass diese Zeit ausgesprochen sinnvoll investiert ist und die gewonnenen +Erkenntnisse und Erfahrungen den nötigen Aufwand mehr als rechtfertigen. Auch konnten +wir als Team von einem regen Wissens- und Erfahrungsaustausch untereinander profitieren. +So konnte jeder von uns sein eigenes Wissen und seine persönlichen Fähigkeiten voll +in dieses Projekt einbringen. Dies freut uns sehr. + +\newpage \section{Lizenzen} Der im Rahmen dieses Projektes geschaffene Programmcode steht ebenso wie diese Dokumentation unter der Modifizierten BSD Lizenz (\url{https://gitlab.cvh-server.de/lf.ps/vbls/blob/master/common/BSD-MODIFIED.txt}). @@ -1524,7 +1547,9 @@ Freeware \\ Proprietär \& Kommerziell \\ \url{http://labs.adobe.com/technologies/eula/lightroom.html}} \end{itemize} + \newpage + \section{gitlab-Repository} Der im Rahmen dieses Projektes entstandene Quellcode sowie die hier vorliegende Dokumentation können über den gitlab-Server des Campus Velbert-Heiligenhaus