Skip to content
Snippets Groups Projects
Commit f5f67c3b authored by Lukas Friedrichsen's avatar Lukas Friedrichsen
Browse files

revision second iteration

parent c6016a57
Branches
No related tags found
No related merge requests found
No preview for this file type
......@@ -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,6 +1192,7 @@ 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}
......@@ -1190,7 +1202,7 @@ For those UARTs which are not capable of that speed, they will also work at the
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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment