Skip to content
Snippets Groups Projects
Commit 55aa5c85 authored by Christoph Schröter's avatar Christoph Schröter
Browse files

No commit message

No commit message
parent 830be4f7
No related branches found
No related tags found
No related merge requests found
images/actionlib_garage.png

205 KiB

...@@ -379,4 +379,14 @@ ...@@ -379,4 +379,14 @@
school = {Aalborg University}, school = {Aalborg University},
} }
@Misc{Actionlib,
author = {{Open Source Robotics Foundation Inc.}, {Huiwu Luo}},
title = {Actionlib Detailed Description},
year = {2021},
publisher = {Open Source Robotics Foundation Inc.},
ranking = {rank3},
readstatus = {read},
url = {http://wiki.ros.org/actionlib/DetailedDescription},
}
@Comment{jabref-meta: databaseType:bibtex;} @Comment{jabref-meta: databaseType:bibtex;}
\chapter{Ausführung}
\section{Integration mit actionlib}
Das hier verwendete Szenario entspricht einem Garagen-Tor, welches präemptiert werden kann. Der implementierte Action-Server nimmt einen Boolean entgegen, der festlegt, ob das Tor geöffnet oder geschlossen werden soll, und gibt dann zufällig Feedback in Form eines Integers zurück, welcher die aktuelle Position des Tores repräsentiert. Dabei steht der Wert 0 für ein geschlossenes sowie 1000 für ein offenes Tor. Nach Abschluss des aktuellen Vorgangs wird der Status zurück zum Client übertragen. Dieser kann jedoch auch während der Ausführung das Wechseln des Ziels anfragen, woraufhin der Server das alte Ziel verwirft.\\
Das entsprechend erstellte Uppaal-Modell ist in \cref{integration:uppaal} zu sehen. Auffällig dabei sind Kanten denen die Channel \textit{fertig} und \textit{position} zugewiesen sind. Bei diesen wird vom System die aktuelle Position übermittelt. Dazu wird eine zufällige Zahl zwischen 0 und 1000 ausgewählt und zur Position addiert beziehungsweise subtrahiert. Außerdem wird garantiert, dass die Grenzen des Wertebereiches nicht überschritten werden.
\begin{figure}[h]
\centering
\includegraphics[scale=.2]{./actionlib_garage.png}
\caption{Testmodell des Action-Servers}
\label{integration:uppaal}
\end{figure}
Der Einsatz des Adapters erfolgt unter Verwendung von eigens für die Nachrichtentypen implementierten Callbacks statt der Zuweisung von Bytes. Dadurch können andere Bestandteile des Action-Protokolls wie die Header vernachlässigt werden. Weiterhin ist zu beachten, dass im Adapter die Nachrichten verwendet werden, die \textbf{Action} im Namen tragen (z.B. TriggerActionGoal, nicht TriggerGoal). Diese Nachrichten beinhalten neben den Daten auch Header- und Statusinformationen und müssen verwendet werden, wenn der Adapter selbst weder Client noch Server des Systems ist, sondern ersteren nur emuliert oder die Kommunikation beider Parteien abhört. Eine Implementierung des Adapters, welcher selbst einen Client darstellt wäre allerdings auch möglich. Die Namen der Topics sind aus dem Namen des Servers (wird bei Konstruktion übergeben) und dem Inhalt der Nachricht zusammengesetzt und können daher ohne Probleme verwendet werden. Die (nicht vollständige) Konfigurationsphase für den Adapter des in \cref{integration:uppaal} gezeigten Modells sieht wie folgt aus:
\begin{lstlisting}[tabsize=1]
// oeffnen und schliessen stellt jeweils ein Ziel dar
Mapping map = Mapping("/garage_server/goal", "oeffnen", true);
map.input_callback = send_goal_open;
mappings.push_back(map);
map = Mapping("/garage_server/goal", "schliessen", true);
map.input_callback = send_goal_close;
mappings.push_back(map);
// wichtig ist, dass die Queue ausreichend gross ist, falls TRON
// viele Inputs sendet (hier relativ unwichtig)
input_publishers.push_back(nh.advertise<actionlib_example::TriggerActionGoal>("/garage_server/goal", 100));
// aktuelle Position wird per feedback zureckgegeben
// (wie bei result-Topic an Channel 'fertig')
map = Mapping("/garage_server/feedback", "position", false);
map.add_var_to_mapping("akt_position", 0);
mappings.push_back(map);
output_subscribers.push_back(nh.subscribe("/garage_server/feedback", 100,
feedback_callback));
\end{lstlisting}
Die hier verwendeten Callbacks \textit{send\_goal\_open(/close)} rufen die Funktion \textit{send\_goal} auf:
\begin{lstlisting}[tabsize=1]
void send_goal (Mapping& map, int32_t* val, bool open){
auto shared_ptr = boost::make_shared<actionlib_example::TriggerActionGoal>();
shared_ptr->goal.open = open;
publish_to_topic<actionlib_example::TriggerActionGoal>(map.topic, shared_ptr);
}
\end{lstlisting}
Es lässt sich hinzufügen, dass beim Versenden eines Ziels (oder einer sonstigen Nachricht) vom (hier emulierten) Client keine Felder im Header wie zum Beispiel die Identifikationsnummer dieses Zieles gesetzt werden müssen, da der Server diese beim Empfangen der Nachricht entsprechend ausfüllt, sollten sie leer sein. Die Identifikationsnummer ist für den Client wichtig, um einen bestimmten Auftrag abzubrechen und sollte folglich in diesem Fall von ihm gesetzt werden. Die Funktion \textit{feedback\_callback} gibt lediglich die aktuelle Position an TRON weiter. Da im Uppaal-Modell keine Angaben zur Zeit vorhanden sind, kann die Zeiteinheit in diesem Fall frei gewählt werden. Der Test-Timeout sollte so gewählt sein, dass mehrere Zyklen durchlaufen werden können und ist daher abhängig von der Zeit, die der Server zum Bewältigen der Aufgabe benötigt.
Die vollständige Implementierung des actionlib-Servers und -Clients sowie des verwendeten TRON-Adapters sind in einem Git-Repository vorhanden (siehe Anhang).
\ No newline at end of file
...@@ -49,7 +49,7 @@ Templates ermöglichen generische Callbacks mit denen den TRON-Variablen Positio ...@@ -49,7 +49,7 @@ Templates ermöglichen generische Callbacks mit denen den TRON-Variablen Positio
Zur Verwendung des Adapters müssen primär Veränderungen in der Funktion \textit{configuration\_phase vorgenommen werden}. Die Struktur \textit{Mapping} beschreibt das Verhältnis von einem Channel zu einem Topic und muss daher für jedes gewünschte Paar initialisiert werden. Dabei ist (nach dem Namen des Topics und dem Namen des Channels) anzugeben, ob dieses Mapping als Eingabe oder Ausgabe dient. Soll ein Channel sowohl Eingabe als auch Ausgabe sein, oder sollen mehrere Topics einem Channel zugewiesen werden (oder umgekehrt), so müssen dafür zusätzliche Mappings erstellt werden. Zur Verwendung des Adapters müssen primär Veränderungen in der Funktion \textit{configuration\_phase vorgenommen werden}. Die Struktur \textit{Mapping} beschreibt das Verhältnis von einem Channel zu einem Topic und muss daher für jedes gewünschte Paar initialisiert werden. Dabei ist (nach dem Namen des Topics und dem Namen des Channels) anzugeben, ob dieses Mapping als Eingabe oder Ausgabe dient. Soll ein Channel sowohl Eingabe als auch Ausgabe sein, oder sollen mehrere Topics einem Channel zugewiesen werden (oder umgekehrt), so müssen dafür zusätzliche Mappings erstellt werden.
\\ Nach der Initialisierung können Variablen hinzugefügt werden. Parameter dafür sind in dieser Reihenfolge: der Name in Uppaal, der Offset (in Byte) von der letzten im Mapping vorhandenen Variable und schließlich optional Zeiger zu Konvertierungsfunktionen (von TRON zum Topic und umgekehrt). Letztere lassen sich verwenden, wenn Variablen des Topics nicht in dem von TRON verwendeten 32-Bit-Integer Format vorliegen oder Felder variabler Länge genutzt werden. Anzumerken ist hier, dass durch den Offset der Variable ausgehend von seinem Vorgänger die Variablen in der Reihenfolge angegeben werden müssen, in der sie innerhalb der ROS-Nachricht vorkommen. \\ Nach der Initialisierung können Variablen hinzugefügt werden. Parameter dafür sind in dieser Reihenfolge: der Name in Uppaal, der Offset (in Byte) von der letzten im Mapping vorhandenen Variable und schließlich optional Zeiger zu Konvertierungsfunktionen (von TRON zum Topic und umgekehrt). Letztere lassen sich verwenden, wenn Variablen des Topics nicht in dem von TRON verwendeten 32-Bit-Integer Format vorliegen oder Felder variabler Länge genutzt werden. Anzumerken ist hier, dass durch den Offset der Variable ausgehend von seinem Vorgänger die Variablen in der Reihenfolge angegeben werden müssen, in der sie innerhalb der ROS-Nachricht vorkommen.
\\ Für Input-Channel muss zusätzlich ein Callback angegeben werden welcher als Parameter eine Referenz zu einem Mapping und ein Array von 32-Bit-Integern bekommt. Dieser sollte im Normalfall \textit{mapping\_callback\_to\_topic} sein, kann aber so wie die Konvertierungsfunktionen auch selbst implementiert werden. \\ Für Input-Channel muss zusätzlich ein Callback angegeben werden welcher als Parameter eine Referenz zu einem Mapping und ein Array von 32-Bit-Integern bekommt. Dieser sollte im Normalfall \textit{mapping\_callback\_to\_topic} sein, kann aber so wie die Konvertierungsfunktionen auch selbst implementiert werden.
\\ Schließlich muss das Mapping der Liste \textit{mappings} hinzugefügt werden. Zu beachten ist, dass für jedes Topic, welches im Rahmen von Input-Mappings verwendet wird ein entsprechender \textit{ros::Publisher} in der Liste \textit{input\_publishers} vorhanden sein muss. Analog dazu müssen \textit{ros::Subscriber} zu \textit{output\_subscriber} hinzugefügt werden, wobei beim Erstellen der Subscriber durch die ROS API die Callbacks für Nachrichten innerhalb der Topics hinzugefügt werden müssen. Wie bei den Input-Channels ist dafür eine generische Funktion vorhanden, \textit{mappings\_callback\_to\_TRON}, welche im Normalfall verwendet werden kann. \\ Schließlich muss das Mapping der Liste \textit{mappings} hinzugefügt werden. Zu beachten ist, dass für jedes Topic, welches im Rahmen von Input-Mappings verwendet wird ein entsprechender \textit{ros::Publisher} in der Liste \textit{input\_publishers} vorhanden sein muss. Analog dazu müssen \textit{ros::Subscriber} zu \textit{output\_subscriber} hinzugefügt werden, wobei beim Erstellen der Subscriber durch die ROS API die Callbacks für Nachrichten innerhalb der Topics hinzugefügt werden müssen. Wie bei den Input-Channels ist dafür eine generische Funktion vorhanden, \textit{mappings\_callback\_to\_TRON}, welche bei einfachen Nachrichten verwendet werden kann. Anzumerken ist hierbei, dass diese Methode alle Channel informiert, die als Output mit dem Topic angegeben sind, während bei den Inputs jeweils eine Funktion im Mapping hinterlegt ist.
\\ Neben den Mappings muss auch die Zeiteinheit sowie der Zeitraum für den getestet werden soll festgelegt werden, dies geschieht über einen Funktionsaufruf an \textit{set\_time\_unit\_and\_timeout}. \\ Neben den Mappings muss auch die Zeiteinheit sowie der Zeitraum für den getestet werden soll festgelegt werden, dies geschieht über einen Funktionsaufruf an \textit{set\_time\_unit\_and\_timeout}.
\\ Für das in \cref{konzept:uppaal_tor} dargestellte Modell könnte die Konfigurierung etwa so aussehen: \\ Für das in \cref{konzept:uppaal_tor} dargestellte Modell könnte die Konfigurierung etwa so aussehen:
\begin{lstlisting}[tabsize=1] \begin{lstlisting}[tabsize=1]
...@@ -71,4 +71,10 @@ Zur Verwendung des Adapters müssen primär Veränderungen in der Funktion \text ...@@ -71,4 +71,10 @@ Zur Verwendung des Adapters müssen primär Veränderungen in der Funktion \text
// 100000 Zeiteinheiten lang testen // 100000 Zeiteinheiten lang testen
set_time_unit_and_timeout(1000, 100000); set_time_unit_and_timeout(1000, 100000);
\end{lstlisting} \end{lstlisting}
Der Channel \textit{position} sowie die Variable \textit{pos} sind in \cref{konzept:uppaal_tor} nicht dargestellt, werden hier aber verwendet um einen Output-Channel sowie das Übertragen einer Variable zu demonstrieren. Der Channel \textit{position} sowie die Variable \textit{pos} sind in \cref{konzept:uppaal_tor} nicht dargestellt, werden hier aber verwendet um einen Output-Channel sowie das Übertragen einer Variable zu demonstrieren.\\
\ No newline at end of file Wenn das Bestimmen der Positionen von Variablen innerhalb einer Nachricht schwierig ist, da diese beispielsweise aus vielen Feldern variabler Größen bestehen, so ist es sinnvoller eigene Callbacks zu implementieren, welche die von ROS erstellten Header-Dateien der Nachrichten zu nutzen, was gleichzeitig zu einer besseren Lesbarkeit des Codes beiträgt und damit die Wartung erleichtert. Dabei können diese Callbacks die Methode \textit{report\_now} verwenden, um TRON das Auslösen eines Channels zu signalisieren und Variablen zu übergeben. Auch hier ist zu erwähnen, dass die Übersetzung von einem Topic zu mehreren Channels in lediglich einer Methode stattfinden muss, die dem ROS-Subscriber als Parameter übergeben wird.
Diese Variante wird auch bei einer später im Text folgenden beispielhaften Anwendung des Adapters für die sogenannte \textit{actionlib} (siehe \cref{konzept:actionlib}) verwendet.
\section{actionlib}\label{konzept:actionlib}
Die actionlib \cite{Actionlib} baut ein Protokoll auf den Nachrichten von ROS auf und ermöglicht Kommunikation von Nodes für das Ausführen einer bestimmten Aufgabe mithilfe einer Client-Server-Architektur. Diese unterscheidet sich von den \textit{ROS Services}\footnote{\url{http://wiki.ros.org/Services}} insbesondere durch die ermöglichte Asynchronität, welche für konstante Rückmeldung des Servers sowie weitere Anfragen des Clients (wie etwa nach der Präemptierung einer Aktion) genutzt wird.
Dazu wurde die Implementierung eines endlichen Automaten realisiert, was sich neben den verwendeten ROS-Nachrichten für das Testen mittels TRON anbietet. Daher wird im Folgenden die Integration des Testadapters in ein System, welches die actionlib verwendet, beispielhaft vollzogen.
\ No newline at end of file
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
\input{sections/einleitung.tex} \input{sections/einleitung.tex}
\input{sections/grundlagen.tex} \input{sections/grundlagen.tex}
\input{sections/konzept.tex} \input{sections/konzept.tex}
\input{sections/ausfuehrung.tex}
\printbibliography[heading=bibintoc]\label{sec:bibliography}% \printbibliography[heading=bibintoc]\label{sec:bibliography}%
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment