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.
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}.
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).}
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
@@ -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}).