Skip to content
Snippets Groups Projects
Commit 59fc9e69 authored by 's avatar
Browse files

Almost-final commit of the LeonardoMixer documentation.

todo: Reference to Jan Webers work is still missing.
parent df2d23b2
No related branches found
No related tags found
No related merge requests found
No preview for this file type
...@@ -1384,7 +1384,7 @@ Die Parametrisierung des Schedulers erfolgt innerhalb der \lstinline{setup()} Me ...@@ -1384,7 +1384,7 @@ Die Parametrisierung des Schedulers erfolgt innerhalb der \lstinline{setup()} Me
scheduler = new Scheduler(rtTasks, nRtTasks); scheduler = new Scheduler(rtTasks, nRtTasks);
//scheduler->setDebugger(&Serial); //scheduler->setDebugger(&Serial);
\end{lstlisting} \end{lstlisting}
\noindent
Die hierbei hervorzuhebenden Parameter sind die \lstinline{cycleTime} der Die hierbei hervorzuhebenden Parameter sind die \lstinline{cycleTime} der
echtzeitkritischen Tasks sowie die \lstinline{priority} der nicht-echtzeitkritischen echtzeitkritischen Tasks sowie die \lstinline{priority} der nicht-echtzeitkritischen
Tasks. Tasks.
...@@ -1398,25 +1398,37 @@ Diese wurden für den Flugbetrieb wie folgt gewählt: ...@@ -1398,25 +1398,37 @@ Diese wurden für den Flugbetrieb wie folgt gewählt:
send.cycleTime = 20000; send.cycleTime = 20000;
\end{lstlisting} \end{lstlisting}
\noindent
Mit den Funktionen, welche Daten empfangen und das lokale Daten-Abbild aktualisieren Die Priorisierung der nicht-echtzeitkritischen Tasks gestaltet sich wie folgt:
als den höchstprioren nicht-echtzeitkritischen Tasks, dem eigentlichen Mischer als Tasks welche Daten empfangen und das lokale Daten-Abbild aktualisieren besitzen die
nächst-priorem und der LCD-Ausgabe (nur im stationären Laborbetrieb im Rahmen des Debugging) höchste Priorität. Es folgt der eigentlichen Mischer, welcher die durch diese Tasks
mit niedrigster Priorität. empfangenen Daten verarbeitet. Niedrigste Priorität besitzt die LCD-Ausgabe,
Das Senden der Daten an die Flugsteuerung ist echtzeit-kritisch und erfolgt mit welche nur im stationären Laborbetrieb im Rahmen des Debugging genutzt wird.
einer vorgegebenen Zykluszeit von 20ms. Das Senden der Daten an die Flugsteuerung ist echtzeit-kritisch und erfolgt zyklisch
alle 20ms.
\section{Testbedingungen} \section{Testbedingungen}
Getestet wurde der Mischer zum einen auf seine Ausführungszeit (den sog.\ \glqq{}Runtime-Over"=head\grqq{}) und zum anderen auf seine Stabilität. Bzgl.\ der Ausführungszeit wurde wiederum zwischen Echtzeit- und Nicht-Echtzeit-Taskverwaltung unterschieden. Getestet wurden sowohl die Applikation im Ganzen, also der LeonardoMixer,
wie auch der Scheduler für sich alleine. Bei diesem wurde zum einen die Ausführungszeit
Im ersten Fall wurde dazu die Funktion \lstinline{schedule()} derart modifiziert, dass am Ende der Ausführung die Differenz zwischen der aktuellen Laufzeit und der Laufzeit zu Beginn der Funktion ausgegeben wird. Als Test-Tasks wurden lediglich zwei leere Echtzeit-Tasks mit unterschiedlichen Zykluszeiten angelegt. So wird zum einen gewährleistet, dass die Funktion \lstinline{sortRtTasks(...)} zum Tragen kommt. Zum anderen wird \lstinline{perform()} nicht aufgerufen, da die Betrachtung der Nicht-Echtzeit-Tasks einzeln erfolgen soll. (der sog.\ \glqq{}Runtime-Over"=head\grqq{}) und zum anderen die Stabilität untersucht.
Bzgl.\ der Ausführungszeit wurde wiederum zwischen Echtzeit- und Nicht-Echtzeit-Taskverwaltung unterschieden.
Im ersten Test wurde dazu die Funktion \lstinline{schedule()} derart modifiziert,
dass am Ende der Ausführung die Differenz zwischen der aktuellen Laufzeit und der
Laufzeit zu Beginn der Funktion ausgegeben wird.
Als Test-Tasks wurden lediglich zwei leere Echtzeit-Tasks mit unterschiedlichen
Zykluszeiten angelegt. So wird zum einen gewährleistet, dass die Funktion
\lstinline{sortRtTasks(...)} zum Tragen kommt. Zum anderen wird \lstinline{perform()}
nicht aufgerufen, da die Betrachtung der Nicht-Echtzeit-Tasks einzeln erfolgen soll.
Die Messung des \glqq{}Runtime-Overheads\grqq{} der Nicht-Echtzeit-Taskverwaltung gestaltete sich insofern einfacher, dass \lstinline{perform()} nicht extra modifiziert werden musste. Es war ausreichend, lediglich einen Nicht-Echtzeit-Task anzulegen, der bei jeder Ausführung die Differenz zwischen dem Zeitpunkt seiner letzten Ausführung (d.\,h.\ \lstinline{timestamp}) und Die Messung des \glqq{}Runtime-Overheads\grqq{} der Nicht-Echtzeit-Taskverwaltung gestaltete sich insofern einfacher, dass \lstinline{perform()} nicht extra modifiziert werden musste. Es war ausreichend, lediglich einen Nicht-Echtzeit-Task anzulegen, der bei jeder Ausführung die Differenz zwischen dem Zeitpunkt seiner letzten Ausführung (d.\,h.\ \lstinline{timestamp}) und
der aktuellen Laufzeit ausgibt. der aktuellen Laufzeit ausgibt.
\\ \\
\\ \\
Die Stabilität des Mischers wurde in Form eines Dauertest 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 Die Stabilität des Gesamtsystem LeonardoMixer wurde in Form eines Dauertest auf
Flugplattform, einem Quadrokopter in X-Anordung, getestet. 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 Quadrokopter in X-Anordung, getestet.
\begin{figure}[hb] \begin{figure}[hb]
\centering \centering
...@@ -1450,7 +1462,8 @@ Testaufbaus: ...@@ -1450,7 +1462,8 @@ Testaufbaus:
\newpage \newpage
\section{Ergebnisse} \section{Ergebnisse}
Nach mehreren Messungen des \glqq{}Runtime-Overheads\grqq{} auf Basis des im Rahmen des Projekts verwendeten Olimexino 32u4 konnten folgende Ausführungszeiten ermittelt werden: Nach mehreren Messungen des \glqq{}Runtime-Overheads\grqq{} des Schedulers konnten
folgende Ausführungszeiten auf dem verwendeten Atmega 32u4 ermittelt werden:
\\ \\
\\ \\
\begin{tabular}{ l l } \begin{tabular}{ l l }
...@@ -1459,19 +1472,27 @@ Nach mehreren Messungen des \glqq{}Runtime-Overheads\grqq{} auf Basis des im Rah ...@@ -1459,19 +1472,27 @@ Nach mehreren Messungen des \glqq{}Runtime-Overheads\grqq{} auf Basis des im Rah
\end{tabular} \end{tabular}
\\ \\
\\ \\
Das heißt, dass von Seiten des Schedulers (bei entsprechender Programmierung der Tasks) eine Echtzeitfähigkeit von bis zu ca.\ 0.1ms erreicht werden kann. Für die gegebene Anwendung mit einer Anforderung von 50Hz, d.\,h.\ 20ms, ist dies mehr als ausreichend. Dies bedeutet, dass bei Verwendung dieses Schedulers mit zwei Echtzeit-Tasks eine Abweichung von der vorgegeben
Zykluszeit von unter 85µs erreicht werden kann. Für die gegebene Anwendung mit einer
Ziel-Zykluszeit von 20ms entspricht dies einer Abweichung von 0,425\%.
\\ \\
\\ \\
Anmerkung: Es ist zu beachten, dass lediglich der statische Anteil des \glqq{}Runtime-Overheads\grqq{} gemessen wurde. Der dynamische Anteil, d.\,h.\ die für die Sortierung benötigte Zeit, steigt mit zunehmender Anzahl der jeweiligen Tasks um den Faktor $n$ (für Echtzeit-Tasks) bzw.\ $n\cdot\log n$ (für Nicht-Echtzeit-Tasks). Weiterhin verlängert sich die Ausführungszeit im Fall von Starvation durch das Ausführen von \lstinline{setPriorities()} ebenfalls. Anmerkung: Es ist zu beachten, dass lediglich der statische Anteil des
\glqq{}Runtime-Overheads\grqq{} für zwei Echtzeit-Tasks gemessen wurde.
Der dynamische Anteil, d.\,h.\ die für die Sortierung benötigte Zeit, steigt mit
zunehmender Anzahl der jeweiligen Tasks um den Faktor $n$ (für Echtzeit-Tasks)
bzw.\ $n\cdot\log n$ (für Nicht-Echtzeit-Tasks). Die Ausführungszeit im Fall von
Starvation erhöht sich durch das Ausführen von \lstinline{setPriorities()} ebenfalls.
\\ \\
\\ \\
Bzgl.\ der Stabilität des Systems konnte nach einem Dauertest über den Zeitraum von 45 Minuten kein Verklemmen oder Bzgl.\ der Stabilität des Gesamt-Systems konnte nach einem Dauertest über den Zeitraum
unerwünschtes Verhalten festgestellt werden. von 45 Minuten kein Verklemmen oder anderweitig unerwünschtes Verhalten festgestellt werden.
Im Verlaufe der abschließenden Flugversuche ist kein einziger Ausfall zu vermerken, Im Verlaufe der abschließenden Flugversuche ist kein einziger Ausfall zu vermerken,
welcher auf das in diesem Projekt geschaffene System zurückzuführen wäre. welcher auf das in diesem Projekt geschaffene System zurückzuführen wäre.
Dies bedeutet, dass der Mischer die gesetzten Anforderungen bezüglich der Echtzeitfähigkeit Unterschiede im Ansprechverhalten des Systems im Betrieb mit und ohne Mischer konnten
und bezüglich der Stabilität der Anwendung gänzlich erfüllt. nicht festgestellt werden. Dies bedeutet, dass der Mischer die gesetzten Anforderungen
bezüglich der Echtzeitfähigkeit und der Stabilität der Anwendung gänzlich erfüllt.
Dieser Erfolg ist insbesondere dem Scheduler sowie der konsequenten Auslegung der Dieser Erfolg ist insbesondere dem Scheduler sowie der konsequenten Auslegung der
einzelnen Methoden auf kooperatives Multitasking zuzuschreiben. einzelnen Methoden auf kooperatives Multitasking zuzuschreiben.
......
// LeonardoMixer.cpp
// Copyright 2016, 2017 Lukas Friedrichsen, Philipp Stenkamp
// License: Modified BSD-License
//
// Realtime RC mixer for Arduino-devices
//
// 2017-01-06
#include <Arduino.h>
#include "RC.h"
#include "RawSerial.h"
#include "Spektrum.h"
#include "MultiWiiSerial.h"
#include "Mixer.h"
#include "Scheduler.h"
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
rcSource rcSerial;
rcSource rcSpektrum;
rcSource rcMSP;
RawSerial serial(&rcSerial);
Spektrum spektrum(&rcSpektrum);
MultiWiiSerial msp(&rcMSP);
Mixer mixer(&rcMSP,&rcSpektrum,&rcSerial);
Scheduler *scheduler;
rtTask send;
rtTask *rtTasks[] = { &send, NULL };
nRtTask nop1, nop2;
nRtTask *nRtTasks[] = { &nop1, &nop2, NULL };
long oldTime = micros();
void nop1 (void)
{
//do nothing
}
void nop2 (void)
{
//do nothing
}
void send_Function (void)
{
long newTime = micros();
Serial.println("Cycle time: " + (oldTime-newTime));
}
void setup()
{
nop1.priority = 1;
nop1.activity = readRawSerial_Function;
nop1.timestamp = 0;
nop2.priority = 1;
nop2.activity = readSpektrum_Function;
nop2.timestamp = 0;
send.activity = send_Function;
send.timestamp = 0;
send.cycleTime = 50000;
scheduler = new Scheduler(rtTasks, nRtTasks);
//scheduler->setDebugger(&Serial);
while(Serial1.available()){
Serial1.read();
}
}
void loop() { scheduler->schedule(); }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment