481 lines
38 KiB
TeX
481 lines
38 KiB
TeX
\chapter{Komponenten-/Softwareauswahl}
|
|
Die Auswahl der verwendeten Softwarekomponenten beeinflusst den späteren Entwicklungsprozess nachhaltig.
|
|
|
|
Alle Komponenten sollen später in der entwickelten Softwareumgebung ihre jeweiligen Teilbereiche abdecken.
|
|
Alle diese Teilbereiche können dann zu einer Simulation verbunden werden, die das gesamte Problemfeld abdeckt.
|
|
|
|
Wie bereits in Abbildung \ref{concept_overview} dargestellt, ist für die Erfüllung der Aufgaben eine Dienst- und eine Simulationsumgebung erforderlich.
|
|
Dieses Kapitel beschreibt die Auswahl der Umgebungen und alle in den Umgebungen laufenden Prozesse.
|
|
\section{Dienstumgebung}
|
|
Die Dienstumgebung bestimmt maßgeblich, wie Software im Entwicklungsprozess geschrieben wird.
|
|
Durch sie werden häufig benötigte Funktionen bereitgestellt, die Programme innerhalb der Umgebung nutzen können.
|
|
|
|
Bei einer Dienstumgebung für Roboter gehört die Nachrichtenübergabe zwischen den einzelnen Programmen zu den grundlegenden Aspekten.
|
|
Diese wird genutzt, um eine gemeinsame Basis für ein erweiterbares System zu schaffen.
|
|
Außerdem sind Werkzeuge zur Parameterübergabe an Teilsysteme sinnvoll, um die Einstellungen an einer Stelle gesammelt anpassen zu können.
|
|
|
|
\subsection{Auswahl}
|
|
Es existieren mehrere Systeme, die als Dienstumgebung für Roboter infrage kommen, wenn man lediglich die Nachrichtenübergabe zwischen Programmen betrachtet.
|
|
Jede Dienstumgebung, die Nachrichten zwischen Prozessen austauschen kann, ist potenziell als ein Roboterframework einsetzbar.
|
|
|
|
Wichtige Aspekte sind dabei die Geschwindigkeit der Anbindung und die Definition der Nachrichten, die über das System ausgetauscht werden.
|
|
|
|
Nutzbare, bereits als Interprozesskommunikation integrierte Systeme sind zum Beispiel Pipes, die Daten zwischen Prozessen über Buffer austauschen.
|
|
Auch die Nutzung von Message Queues oder Shared Memory ist für diesen Einsatzzweck möglich.
|
|
Diese Systeme sind performant, jedoch schwerer zu verwalten.
|
|
Ein Problem dieser Methoden ist die direkte Kommunikation mehrerer Komponenten, da die Art der Kommunikation keine Modifikation von Nachrichten zur Anpassung an andere Szenarien vorsieht.
|
|
|
|
Eine Alternative stellen Sockets dar, die Daten zwischen mehreren Programmen austauschen können.
|
|
Dabei dient ein Programm als Server, der Anfragen von anderen Programmen, auch Clients genannt, entgegen nimmt.
|
|
Die Kommunikation zwischen Client und Server ist bidirektional möglich, was kompliziertere Protokolle ermöglicht.
|
|
|
|
Alle diese Lösungen besitzen einen gemeinsamen Nachteil in deren Nachrichtendefinition.
|
|
Dieser Nachteil besteht in der potenziellen Variabilität dieser Kommunikationsmechanismen.
|
|
Bei einem ausreichend großen Projekt treten so unweigerlich Unterschiede in der Handhabung von Nachrichten auf, die es zu berücksichtigen gilt.
|
|
Durch solche Unterschiede kann es zu Inkompatibilitäten zwischen Programmen kommen, was sich auf die universelle Nutzbarkeit der Programme negativ auswirkt.
|
|
|
|
Im Bereich der Robotik ist ROS \cite{doi:10.1126/scirobotics.abm6074}, bei dem es sich um ein quelloffenes System handelt, als Dienstumgebung etabliert.
|
|
Der oben genannte Nachteil einzelner Systeme wird in ROS durch mehrere standardisierte und erweiterbare Nachrichtendefinitionen gelöst, die von den Programmen in der Umgebung genutzt werden.
|
|
Um diese Nachrichten senden und empfangen zu können, liefert ROS bereits eine eigene Implementation des Protokolls für mehrere Programmiersprachen mit.
|
|
Zum Beispiel existieren für Python \cite{python}, C und C++ \cite{cpp} entsprechende Implementationen in Form der Pakete \code{rospy}, \code{rclc} und \code{rclcpp}.
|
|
|
|
Die neuste Version ROS2 bietet mehrere Verbesserungen im Vergleich zu früheren Version ROS1 \cite{changesRosII}.
|
|
Ein neues Nachrichtenformat mit Quality of Service kann beispielsweise Nachrichten zwischenspeichern und über sowohl TCP, als auch UDP kommunizieren.
|
|
Außerdem werden neben CMake \cite{cmake} auch andere Buildsysteme unterstützt, was die Verwendung von Python erlaubt.
|
|
|
|
Generell existieren im Feld der Roboter-Dienstumgebungen keine freien Alternativen mit ähnlichem Funktionsumfang und gleicher Reichweite.
|
|
Vor allem die Vielzahl von ROS-Bibliotheken, die von Nutzern des Systems über die Jahre erstellt wurden, machen das System so populär \cite{rospackages}.
|
|
|
|
ROS kann sowohl für simulierte Umgebungen als auch für echte Roboter eingesetzt werden.
|
|
Diese beiden Anwendungsfälle werden durch unterschiedliche Controller realisiert.
|
|
Für simulierte Umgebungen leitet der Controller die Steuerdaten an die Simulationsumgebung weiter.
|
|
Bei dem Einsatz echter Hardware werden die Zielpositionen durch den Controller an die Roboterhardware weitergeleitet.
|
|
|
|
%-Alternative Ökosysteme mit gleichem Umfang wie ROS existieren nicht.
|
|
%-ROS2
|
|
%-Andere (nur) Messagingsysteme
|
|
%-LCM
|
|
%-ZeroMQ
|
|
\subsection{Beschreibung}
|
|
ROS2 \cite{doi:10.1126/scirobotics.abm6074}, im weiteren Verlauf nur ROS genannt, beschreibt sich selbst als ``a meta operating system for robots'' \cite{ros-git}.
|
|
Hierbei ist ``operating system'' nicht in seiner herkömmlichen Bedeutung eines vollständigen Betriebssystems zu verstehen.
|
|
Es handelt sich dabei um eine gemeinsame Grundlage für Programme und Daten, die durch ROS bereitgestellt wird.
|
|
|
|
Einzelne Bestandteile in der Umgebung sind dabei in Pakete gegliedert, wobei jedes Paket beliebig viele Daten und Programme beinhalten kann.
|
|
Programme, die mit anderen Programmen in der Umgebung über die ROS internen Schnittstellen kommunizieren, werden in ROS ``Nodes'' genannt.
|
|
|
|
Zu den Aufgaben von ROS zählen folgende Teilbereiche:
|
|
\begin{description}
|
|
\item[Organisation]\hfill \\
|
|
Um die einzelnen Teile einer Roboterumgebung zu separieren, werden diese in ROS auf unterschiedliche Pakete aufgeteilt.
|
|
Jedes Paket enthält dabei eine \code{package.xml}-Datei.
|
|
In dieser befindet sich eine in XML verfasste Definition des Paketinhalts, die verschiedene Aspekte des Pakets beschreibt.
|
|
|
|
Darunter fallen Informationen über das Paket selbst, wie dessen Name, Beschreibung und Version.
|
|
Außerdem sind Name und Mailadresse des Autors, sowie die gewählte Lizenz des Codes vermerkt.
|
|
Um das Paket später korrekt ausführen zu können, werden benötigte Pakete für den Kompiliervorgang und die Ausführung in die package.xml-Datei eingetragen.
|
|
|
|
\item[Buildumgebung]\hfill \\
|
|
ROS nutzt die eigene Buildumgebung \code{colcon} \cite{colcon}, um Pakete in den Workspaces reproduzierbar zu erstellen.
|
|
Zu deren Konfiguration wird eine \code{CMakeLists.txt}-Datei erstellt, die den Buildprozess beschreibt.
|
|
In dieser sind die Buildinstruktionen für den Compiler enthalten, mit welchen die im Paket befindlichen Programme kompiliert werden.
|
|
Der Aufruf des \code{ament_cmake}-Makros in dieser ergänzt den Kompiliervorgang um weitere Parameter aus der \code{package.xml}-Datei.
|
|
|
|
Nach diesen Vorbereitungsschritten kann CMake das Paket kompilieren.
|
|
Hierbei werden alle in der \code{CMakeLists.txt}-Datei angegebenen Programmteile kompiliert.
|
|
|
|
Es ist außerdem möglich, bestimmte Pfade des Pakets nach dem Buildvorgang zu exportieren.
|
|
Diese sind dann später im erstellten Workspace für die Nutzung durch andere Programme verfügbar.
|
|
|
|
\item[Workspaceverwaltung]\hfill \\
|
|
Gruppen von Paketen werden zur einfacheren Handhabung in sogenannten ``Workspaces'' zusammengefasst.
|
|
Diese vereinfachen das Auffinden der enthaltenen Pakete durch Skripte, die diese im System registrieren.
|
|
Die Erstellung der Skripte erfolgt anhand der bereits beschriebenen \code{CMakeLists.txt}-Datei.
|
|
Das Programm \code{colcon} analysiert diese und generiert die Skripte.
|
|
Um das Paket im System zu registrieren, muss der Nutzer die generierten Skripte ausführen, was die benötigten Umgebungsvariablen setzt.
|
|
Hierfür wird meist ein weiteres Skript verwendet, was alle im Workspace befindlichen Pakete nacheinander der Umgebung hinzufügt.
|
|
|
|
Dieser Vorgang erlaubt zum Beispiel das Auffinden von Paketen anhand deren Namen im Dateisystem.
|
|
Das erleichtert die Verwaltung durch die Unabhängigkeit von spezifischen Pfaden im entwickelten System.
|
|
Außerdem wird die Laufzeitumgebung für alle Programme konfiguriert, was definierte Bibliotheken für diese verfügbar macht.
|
|
|
|
\item[Abhängigkeitsverwaltung]\hfill \\
|
|
ROS kann durch die in den Paketen deklarierten Abhängigkeiten prüfen, ob diese in der aktuellen Umgebung ausführbar sind.
|
|
Die generierten Warnungen bei fehlenden Paketen helfen dem Anwender, Abstürze und undefiniertes Verhalten bei der Ausführung von Nodes zu vermeiden, die diese Pakete benötigen.
|
|
|
|
\item[Datenübertragung]\hfill \\
|
|
Um Daten zwischen Nodes austauschen zu können, müssen die Nodes miteinander auf einem festgelegten Weg kommunizieren können.
|
|
Ein solcher Aufbau erlaubt den Austausch von Daten in vorher nicht durch die Entwickler bedachten Anwendungsfällen.
|
|
Die von ROS gebotene Schnittstelle zur Datenübertragung wird in Form mehrerer Bibliotheken für unterschiedliche Programmiersprachen bereitgestellt.
|
|
|
|
Der Datenaustausch geschieht in sogenannten Topics, die Nachrichtenkanäle zwischen den Nodes darstellen.
|
|
Eine Node kann entweder als Server ein Topic anbieten, was durch andere Nodes gelesen wird, oder als Client auf solche bereitgestellten Topics zugreifen.
|
|
Durch die Kombination mehrerer Topics ist eine komplexere Interaktion abbildbar, die zum Beispiel Rückgabewerte zum aktuell ausgeführten Steuerbefehl liefert.
|
|
|
|
\item[Parameterübergabe]\hfill \\
|
|
Um Nodes auf neue Anwendungsfälle anpassen zu können, wird ein Konfigurationsmechanismus benötigt.
|
|
In ROS geschieht dies durch die Übergabe sogenannter Parameter, die durch die Node gelesen werden können.
|
|
Diese eignen sich zur Übergabe von Informationen, wie zum Beispiel Daten über ein verwendetes Robotermodell.
|
|
Um neue Konfigurationen zu unterstützen, kann das Umbenennen von Topics einer Node notwendig werden, was auch mit einem Parameter erfolgen kann.
|
|
|
|
\item[Startverwaltung]\hfill \\
|
|
In sogenannten ``launch''-Files können verschiedene Nodes und andere ``launch''-Files zu komplexen Startvorgängen zusammengefasst werden.
|
|
Das Einstellen von bestimmten Parametern erlaubt die Anpassung der Funktionen an den gewünschten Anwendungsfall.
|
|
|
|
\end{description}
|
|
|
|
Eine solche Umgebung erlaubt die Zerlegung der geplanten Simulation in mehrere Komponenten.
|
|
Die daraus erfolgte Abgrenzung erhöht die Übersichtlichkeit der einzelnen Bestandteile.
|
|
Dies vereinfacht die spätere Wartung des Projekts.
|
|
|
|
\section{Simulationsumgebung}
|
|
|
|
\subsection{Auswahl}
|
|
Als Simulationsumgebung eignen sich verschiedenen Programme, die sich hinsichtlich ihres Funktionsumfangs stark unterscheiden.
|
|
Hierfür kommen beispielsweise dedizierte Werkzeuge zur Robotersimulation, aber auch universell einsetzbare Gameengines in Frage.
|
|
Ein Vergleich dieser Werkzeuge ist hierbei sinnvoll, da sich der gebotene Funktionsumfang der Softwares stark unterscheidet.
|
|
Auch andere Aspekte, wie Lizenzen oder die schwer bewertbare Nutzerfreundlichkeit, sind hierbei zu betrachten.
|
|
Eine Auswahl der als Simulationsumgebung in Frage kommenden Programme wird hier vorgestellt.
|
|
|
|
CoppeliaSim \cite{coppelia}, früher auch V-REP genannt, ist eine Robotersimulationsumgebung mit integriertem Editor und ROS-Unterstützung.
|
|
Es unterstützt viele Sprachen (C/C++, Python, Java, Lua, Matlab oder Octave) zur Entwicklung von Erweiterungen des Simulators.
|
|
Der Simulator selbst unterstützt menschliche Aktoren, diese können aber nur Animationen allein oder in Kombination mit einer Bewegung abspielen.
|
|
CoppeliaSim existiert in 3 Versionen, die sich hinsichtlich Funktionsumfang und Lizenz unterscheiden.
|
|
Jedoch besitzt nur die professionelle Version Zugriff auf alle Funktionen und Verwendungsszenarien.
|
|
|
|
Gazebo Ignition \cite{gazebo} ist wie CoppeliaSim eine Robotersimulationsumgebung, besitzt aber keinen integrierten Editor und direkte ROS-Unterstützung.
|
|
Gazebo setzt wie CoppeliaSim auf Erweiterungen, um zusätzliche Funktionen einbinden zu können.
|
|
So existiert zum Beispiel auch eine ROS-Brücke, die die Anbindung an ROS ermöglicht.
|
|
Auch hier unterstützt der Simulator nur Animationen für menschliche Aktoren.
|
|
Das Projekt ist Open Source, unter der Apache Lizenz (Version 2.0), was die Verwendung in jeglichen Szenarien erleichtert.
|
|
|
|
Unity \cite{unity} hingegen ist primär eine Grafikengine für die Nutzung in Computerspielen.
|
|
Es existieren mehrere Systeme zur Anbindung der Engine an ROS, vor allem das offizielle ``Robotics Simulation''-Paket und ZeroSim.
|
|
Beide Systeme erlauben die Erweiterung der Gameengine um die Simulation von Robotern.
|
|
Unity besitzt eine gute Dokumentation, die vor allem auf die Nutzung im Einsteigerbereich zurückzuführen ist.
|
|
Auch die Optionen zur Menschensimulation sind umfangreich, da diese häufig in Spielen verwendet werden.
|
|
Ein großer Nachteil hingegen ist die Lizenz, die nur für Einzelpersonen kostenfrei ist.
|
|
|
|
Die Unreal Engine \cite{unreal} ist wie Unity eine Grafikengine aus dem Spielebereich.
|
|
Auch hier ist die Menschensimulation aufgrund oben genannter Gründe gut möglich.
|
|
Jedoch existiert für Unreal Engine keine offizielle Lösung zur Anbindung an ROS2.
|
|
Die Programmierung der Engine erfolgt in C++, was die Erstellung eines Plugins zur ROS-Anbindung der Unreal Engine ermöglichte, die von Nutzern gewartet wird.
|
|
Die Lizenz der Unreal Engine erlaubt die kostenfreie Nutzung bis zu einem gewissen Umsatz mit der erstellten Software.
|
|
|
|
Eine weitere Möglichkeit zur Simulation stellt die Grafikengine Godot \cite{godot} dar.
|
|
Im Vergleich zu Unity und Unreal Engine ist Godot quelloffene Software unter der MIT-Lizenz.
|
|
Auch hier stellt die Simulation von menschlichen Aktoren eine Standardaufgabe dar, jedoch befinden sich Teile des dafür verwendeten Systems derzeit in Überarbeitung.
|
|
Auch für diese Engine existiert eine ROS2-Anbindung, jedoch ist diese nicht offiziell.
|
|
|
|
Alle vorgestellten Softwares besitzen ein integriertes Physiksystem, dass die Simulation von starren Körpern und Gelenken erlaubt.
|
|
Diese Funktionen erlauben den Aufbau eines Roboterarms, der durch eine ROS-Brücke gesteuert wird.
|
|
|
|
Um den Fokus dieser Arbeit auf die gestellte Aufgabe zu ermöglichen, ist die Auswahl einer Umgebung mit bereits existierender ROS-Unterstützung sinnvoll.
|
|
Durch diese Einschränkung scheiden sowohl Unreal Engine aber auch Godot aus.
|
|
Sie bieten zwar diese Funktionalität, jedoch werden sie nur durch Nutzer gewartet und sind demzufolge nicht offiziell unterstützt.
|
|
Für einen späteren Einsatz ist eine offene Lizenz von Vorteil, da diese einen Einsatz unter nahezu allen Umständen erlaubt.
|
|
|
|
Die Wahl der hier zu verwendenden Simulationsumgebung fiel deshalb auf Gazebo Ignition, welche gleichzeitig bereits im ROS-Ökosystem etabliert ist.
|
|
Dabei erlauben die offizielle ROS-Anbindung und die offene Lizenz eine zuverlässige Verwendung in unterschiedlichsten Szenarien.
|
|
\subsection{Welt- und Modellbeschreibung}
|
|
Gazebo nutzt das .sdf-Dateiformat, um die Simulationsumbebung zu beschreiben \cite{sdf-format}.
|
|
Dieses Format basiert auf XML und wird zur Definition gesamter Welten, aber auch einzelner Objekte innerhalb dieser Welten benutzt.
|
|
Eine Welt ist in Gazebo eine Umgebung aus mehreren Objekten, welche simuliert werden sollen.
|
|
Die Welt beschreibt außerdem die simulierte Physikumgebung und deren Konstanten, wie zum Beispiel die Gravitation.
|
|
|
|
Um verschiedene Versionen des Formats zu unterstützen, enthält das einzige sdf-Element die gewünschte Versionsnummer.
|
|
Eine solche Datei kann, wie bereits oben beschrieben, unterschiedliche Daten enthalten.
|
|
Im Falle eines Objekts ist dies eine einzige Instanz von entweder einem Modell, Actor oder Licht.
|
|
Andernfalls können in der Datei eine oder mehrere Welten definiert werden.
|
|
|
|
Eine Welt definiert in Gazebo den kompletten Aufbau des Simulators.
|
|
Zuerst enthält ein Welt-Element die Daten über die physikalischen Konstanten der Simulationsumgebung.
|
|
Zudem werden alle benötigten Teile der Nutzeroberfläche deklariert, die im ausgeführten Simulator verfügbar sein sollen.
|
|
Letztendlich ist die Definition mehrerer Modelle, Aktoren und Lichter in der Welt möglich.
|
|
Diese können auch aus anderen URIs stammen, die in der Welt deklariert wurden.
|
|
Dies erlaubt zum Beispiel das Laden von vorher definierten Objekten oder Objekten aus der offiziellen Bibliothek \cite{gazebo-app}.
|
|
|
|
Ein Modell enthält einen Roboter oder ein anderes physikalisches Objekt in der Simulation.
|
|
Die Deklaration eines weiteren Untermodells ist möglich, um komplexere Strukturen abbilden zu können.
|
|
Über ein include-Element können auch andere .sdf-Dateien, die nur ein einzelnes Modell enthalten, zu einem Modell hinzugefügt werden.
|
|
|
|
Jedes Modell wird über eine Translation und Rotation im Simulationsraum verankert.
|
|
Dies geschieht immer relativ zum Referenzsystem des überliegenden Modells.
|
|
Außerdem können im Modell Einstellungen für dessen Physiksimulation vorgenommen werden.
|
|
|
|
Ein Modell enthält meist mindestens ein Link-Element, dass zur Darstellung von dessen Geometrie verwendet wird.
|
|
Mehrere Link-Elemente können dabei mit der Welt oder anderen Link-Elementen über Joint-Elemente verbunden werden.
|
|
Diese Joint-Elemente können jedoch nicht von außerhalb gesteuert werden, was das Dateiformat ungeeignet für Roboterdefinitionen macht.
|
|
|
|
Lichter besitzen einen Lichttyp, der die Ausbreitung des Lichtes im Raum bestimmt.
|
|
Die erste Art ist direktionales Licht, dass parallel zur gewünschten Achse auftrifft.
|
|
Solche Lichter werden vor allem zur grundlegenden Raumausleuchtung genutzt.
|
|
Weiterhin sind Punktlichtquellen verfügbar, deren Licht von einer Position im Raum ausgeht.
|
|
Neben den Punklichtquellen existieren auch noch Spots, die nur einen gewissen Winkel ausleuchten.
|
|
|
|
Die Actor-Komponente wird für animierte Modelle in der Simulation eingesetzt.
|
|
Sie besteht aus einem Namen für das Modell, einer Skin, welche das Aussehen des Modells definiert und mehreren Animationen.
|
|
Diese können durch in einem Skript definierte Trajectories ausgeführt werden, was eine einfache, aber statische, Simulation des Menschen erlaubt.
|
|
|
|
Eine solche Befehlsfolge kann nicht von außerhalb der Simulation zur Laufzeit angepasst werden.
|
|
Diese Funktionalität wurde im Rahmen der Arbeit hinzugefügt.
|
|
|
|
\subsection{Robotersimulation}
|
|
Für die Robotersimulation wird ein Modell des Roboters benötigt, in dem dieser für die Simulationsumgebung beschrieben wird.
|
|
Gazebo und ROS nutzen hierfür .urdf-Dateien \cite{urdf-format}, die auf XML basieren.
|
|
In diesen werden die einzelnen Glieder des Roboterarms und die verbindenden Gelenke beschrieben.
|
|
|
|
Jedes Glied des Modells besitzt eine Masse, einen Masseschwerpunkt und eine Trägheitsmatrix für die Physiksimulation in Gazebo.
|
|
Außerdem werden Modelle für die visuelle Repräsentation des Roboters in Gazebo und die Kollisionserkennung in der Physiksimulation hinterlegt.
|
|
Für beide existieren einfache Modelle wie Zylinder, Boxen und Kugeln.
|
|
Da diese Formen nicht jeden Anwendungsfall abdecken und in der visuellen Repräsentation nicht ausreichen, können auch eigene Modelle hinterlegt werden.
|
|
Hierbei werden die Modelle für die Physiksimulation und das Aussehen des Roboters unterschieden.
|
|
|
|
Gelenke werden separat von den Gliedern definiert und verbinden jeweils zwei Glieder miteinander.
|
|
Durch das Aneinanderreihen von mehreren Gliedern und Gelenken ist die Beschreibung eines beliebigen Roboteraufbaus möglich.
|
|
Jedes Gelenk besitzt eine Position und Rotation im Raum.
|
|
Diese werden für die Berechnung der Effekte genutzt, die vom spezifischen Gelenktyp abhängen.
|
|
Aspekte wie Reibung und Dämpfung können auch hier für die Nutzung in der Physiksimulation beschrieben werden.
|
|
Folgende Typen von Gelenken können in urdf-Dateien genutzt werden:
|
|
\begin{description}
|
|
\item[freie Gelenke]
|
|
ermöglichen vollständige Bewegung in allen 6 Freiheitsgraden (Rotation und Translation). Sie stellen den normalen Zustand der Glieder zueinander dar.
|
|
\item[planare Gelenke]
|
|
erlauben Bewegungen senkrecht zur Achse des Gelenks. Sie werden zum Beispiel für Oberflächen eingesetzt, auf welchen Objekte gleiten sollen.
|
|
\item[feste Gelenke]
|
|
sperren alle 6 Freiheitsgrade und werden häufig zur Fixierung von Objekten in einer Szene genutzt.
|
|
\item[kontinuierliche Gelenke]
|
|
erlauben die beliebige Rotation um die Achse des Gelenks. Sie sind nur selten in rotierenden Gelenken mit Schleifkontakten oder anderen frei rotierbaren Übertragungsmechanismen zu finden.
|
|
\item[drehbare Gelenke]
|
|
verhalten sich wie kontinuierliche Gelenke, haben jedoch minimale und maximale Auslenkungen. Sie sind die häufigste Art von Gelenken in Roboterarmen.
|
|
\item[prismatische Gelenke]
|
|
ermöglichen die lineare Bewegung entlang der Achse des Gelenks. Sie werden zur Umsetzung von Linearaktuatoren in der Simulation verwendet.
|
|
\end{description}
|
|
\subsection{Menschensimulation}
|
|
Gazebo besitzt bereits ein simples Animationssystem für bewegliche Aktoren, dass auch für Menschen nutzbar ist.
|
|
Für diesen existiert bereits ein Modell mit mehreren Animationen, die allein abgespielt, oder an Bewegungen gekoppelt werden können.
|
|
Dadurch ist zum Beispiel eine Laufanimation realisierbar, die synchronisiert zu einer Bewegung abgespielt wird.
|
|
|
|
Dies setzt jedoch voraus, dass der gesamte Bewegungsablauf zum Simulationsstart bekannt ist.
|
|
Der Grund dafür ist auf die Definition der Pfade zurückzuführen, die Aktionen wie Bewegungen und Animationen auslösen.
|
|
Diese können nur als dem Actor untergeordnetes Element in der .sdf-Datei definiert werden, was Veränderungen zur Laufzeit ausschließt.
|
|
Durch diesen Umstand ist der damit realisierbare Simulationsumfang nicht ausreichend, um die gewünschten Szenarien abzubilden.
|
|
|
|
Um diese Einschränkung zu beheben, ist die Entwicklung eines eigenen Systems zum Bewegen und Animieren des Menschen unausweichlich.
|
|
Dieses System muss, wie im Konzept beschrieben, Steuerbefehle von außen empfangen, umsetzen und Feedback liefern können.
|
|
Dafür soll ein ROS Action-Server verwendet werden, der die Befehle entgegennimmt, unter konstantem Feedback ausführt und nach erfolgreicher Ausführung den Empfang des nächsten Befehls zulässt.
|
|
|
|
Ein solches System soll als Gazebo-Plugin einbindbar sein, um Modifikationen an der Simulationsumgebung selbst auszuschließen, die konstant weiter entwickelt wird.
|
|
Dies vereinfacht die Wartung, da bei Updates der Simulationsumgebung nicht die Menschensimulation an den neuen Code angepasst werden muss.
|
|
\section{Roboterumgebung}
|
|
MoveIt2 \cite{moveit-docs} ist das meist genutzte ROS2 Paket für die Bewegungsplanung von Robotern.
|
|
Deshalb existiert eine umfangreiche Dokumentation für die zahlreichen Komponenten, was die Entwicklung neuer Komponenten erleichtert.
|
|
Außerdem sind zahlreiche direkte Integrationen mit anderen ROS-Paketen verfügbar, was die Nutzung dieser zusammen mit MoveIt erlaubt.
|
|
Aufgrund dieser Eigenschaften ist MoveIt eine vorteilhafte Bewegungsplanungsumgebung für dieses Projekt.
|
|
|
|
MoveIt besteht aus mehreren Komponenten, die in ihrer Gesamtheit den Bereich der Bewegungsplanung abdecken.
|
|
Der Nutzer kann mit MoveIt auf verschiedenen Wegen Steuerbefehle für den Roboter absenden, die durch die Software umgesetzt werden.
|
|
|
|
Die erste Inbetriebnahme ist über das mitgelieferte RViz-Plugin und die demo-Launch-Files möglich.
|
|
Diese wurden mit dem mitgelieferten Setupassistenten für den Roboter generiert.
|
|
Durch die Ausführung dieser Demo startet RViz, eine Test- und Visualisierungsumgebung für ROS.
|
|
In der Demo können Roboterbewegungen unter Zuhilfenahme von Markierungen in RViz geplant und ausgeführt werden.
|
|
|
|
Da sich eine Bewegungsplanung in einer Nutzeroberfläche nur beschränkt zur Automatisierung durch Software eignet, müssen die der Demo zugrundeliegenden Schnittstellen genutzt werden.
|
|
Für die Sprache Python existierte für die Vorgängerversion von MoveIt das moveit_commander Paket, welches den Zugriff auf MoveIt in Python erlaubt, aber für MoveIt2 noch nicht portiert wurde \cite{moveitpython}.
|
|
|
|
Die direkte Nutzung der C++-API ist aktuell die einzige offizielle Möglichkeit, mit MoveIt2 direkt zu interagieren.
|
|
Dabei können sowohl die Planung und die Ausführung von Bewegungen ausgelöst aber auch Exklusionszonen eingerichtet werden.
|
|
Außerdem können Objekte virtuell mit dem Roboter verbunden werden, wodurch sich diese in RViz mit dem Roboter bewegen.
|
|
Natürlich können die Befehle auch direkt an die entsprechenden Topics gesendet werden, um einzelne Bereiche des Systems zu testen.
|
|
|
|
Um die durch den Setupassistenten generierten Informationen an MoveIt zu übergeben, wird intern ein RobotStatePublisher verwendet.
|
|
Dieser lädt alle Daten des Robotermodells und übergibt sie an andere Programme, die Roboterparameter zur Laufzeit anfordern, unter diesen auch MoveIt selbst.
|
|
|
|
Durch die vorher erwähnte C++-API erhält die MoveGroup die Informationen über die gewünschte Bewegung.
|
|
Dabei können auch bestimmte Einschränkungen des Arbeitsraums, spezielle Trajektorien oder Limitierungen der Gelenke in der Planung berücksichtigt werden.
|
|
|
|
Diese Daten können durch eine OccupancyMap ergänzt werden, welche die Bereiche beschreibt, die sich um den Roboter befinden.
|
|
Eine solche Erweiterung erlaubt die automatische Nutzung von Kollisionsvermeidung mit Objekten im Planungsbereich.
|
|
|
|
Die Planung der Bewegung wird durch einen der in MoveIt implementierten Solver realisiert, der durch die MoveGroup aufgerufen wird.
|
|
Um die generierte Bewegung umzusetzen, werden die gewünschten Gelenkpositionen als Abfolge an die \code{ros_control} Controller des Roboters weitergegeben.
|
|
|
|
Diese Abstraktion erlaubt die Nutzung von sowohl simulierten, aber auch echten Robotern.
|
|
Dazu werden für echte und simulierte Roboter unterschiedliche ros_control Controller verwendet.
|
|
Der Erfolg der gesamten Pipeline kann dabei durch einen Feedbackmechanismus überwacht werden.
|
|
|
|
Im Falle von Gazebo wird \code{ign_ros_control} genutzt, dass die benötigten \code{ros_control} Controller in die Simulation einbindet.
|
|
Diese können dann wie normale Controller von \code{ros_control} genutzt werden.
|
|
|
|
Der Ablauf der Bewegungsplanungspipeline von MoveIt ist im Anhang unter Abbildung \ref{moveitpipeline} visualisiert.
|
|
|
|
\section{Programmiersprache}
|
|
Als Programmiersprache kommen in ROS standardmäßig Python \cite{python} und C++ \cite{cpp} zum Einsatz.
|
|
Beide Sprachen sind in der Softwareentwicklung beliebt, unterscheiden sich jedoch stark im Funktionsumfang und im Entwicklungsprozess.
|
|
|
|
Python ist eine interpretierte Skriptsprache, die zu den hohen Programmiersprachen zählt.
|
|
Sie wird in ROS zum Beispiel in \code{.launch.py}-Dateien eingesetzt, die den Start von Diensten in der Umgebung verwalten.
|
|
Die Sprache kann aber auch für die Programmierung von Nodes innerhalb des ROS-Systems verwendet werden.
|
|
|
|
C++ hingegen ist eine kompilierte, statisch typisierte, maschinennahe Programmiersprache.
|
|
In ROS wird C++ für Code verwendet, der entweder häufig oder in zeitkritischen Szenarien ausgeführt wird.
|
|
Aus diesem Grund wird C++ in Nodes verwendet, die schnell auf große Datenmengen reagieren müssen.
|
|
|
|
Die Nutzung eines Kompilierers beschleunigt C++ deutlich im Vergleich zu Python, ist jedoch weniger geeignet für häufige Modifikation.
|
|
Dies ist vor allem in häufig geänderten Programmen ein Nachteil, die nach einer Änderung erneut kompiliert werden müssen.
|
|
Aus diesem Grund wird Python vor allem in .launch.py-Dateien verwendet, welche die Interaktion der anderen Programme in der Umgebung verwalten.
|
|
|
|
Um die gewünschten Funktionen für die Simulation umzusetzen ist die Verwendung der Programmiersprache C++ nahezu unumgänglich.
|
|
Zum Beispiel sind Gazebo-Plugins in C++ erstellt, was die Nutzung anderer Sprachen stark einschränkt.
|
|
|
|
Ein weiterer Grund für die Nutzung von C++ ist die hohe Geschwindigkeit, die bei einer hohen Anzahl von Simulationsschritten pro Sekunde benötigt wird.
|
|
Außerdem kann MoveIt2 derzeit nur mit C++ direkt gesteuert werden.
|
|
|
|
Die Verwendung von C++ für die zu entwickelnden Nodes erscheint deshalb aus oben genannten Gründen naheliegend.
|
|
In den Launch-Skripten wird jedoch Python verwendet werden, da hier die Vorteile einer Skriptsprache überwiegen.
|
|
|
|
\section{Behavior Trees}
|
|
Zur Verwaltung der Abläufe sollen Behavior Trees genutzt werden, die durch die Bibliothek \code{BehaviorTree.CPP} bereitgestellt werden.
|
|
Diese Bibliothek wurde in C++ geschrieben, und ist somit in ROS und dem geplanten Konzept integrierbar.
|
|
|
|
Es existieren viele Beispiele und eine gute Dokumentation über die erweiterten Funktionen der Bibliothek, die im Folgenden vorgestellt werden.
|
|
|
|
\begin{description}
|
|
\item[Asynchrone Nodes]
|
|
sind in \code{BehaviorTree.CPP} leichter umsetzbar, da diese in Form verschiedener Zustände der Nodes beim Konzept der Bibliothek mit bedacht wurden.
|
|
Dies resultiert in Nodes, die ohne spezielle Logik langanhaltende Aktionen ausführen können, ohne die Ausführung des Behavior Trees zu behindern.
|
|
\item[Reaktives Verhalten] ist ein neues Konzept, um die Handhabung von asynchronen Nodes zu vereinfachen.
|
|
Diese Strukturelemente erlauben die parallele Ausführung von mehreren Zweigen, die die aktuell ausgeführte Aktion beeinflussen können.
|
|
Darunter fällt die Modifizierung von Parametern der Aktionen, aber auch der vollständige Abbruch einer Aktion durch äußere Einflüsse.
|
|
\item[Das .xml-Format der Behavior Trees] ermöglicht einen Austausch des Verhaltens, ohne die unterliegenden Programme verändern zu müssen.
|
|
Dies ist vor allem in kompilierten Sprachen wie C++ sinnvoll, da Änderungen im Verhaltensablauf keiner Neukompilierung bedürfen, was die Iterationszeit für Änderungen verbessert.
|
|
\item[Plugins] können zum Start geladen werden, um weitere Nodes dem ausgeführten Programm hinzufügen zu können.
|
|
Dies vereinfacht die Erweiterung um neue Funktionen und das mehrfache Nutzen von Code.
|
|
\item[Das Blackboard] ist eine Interaktionsebene, die den Datenfluss zwischen den Nodes erlaubt.
|
|
In diesem System kann unter Verwendung einer Zeichenkette als Identifikator ein Wert in Form einer Referenz hinterlegt werden.
|
|
Sogenannte Ports erlauben Nodes, Daten aus dem Blackboard zu lesen und auf dieses zu schreiben.
|
|
\item[Integriertes Logging] erlaubt es, Zustandsänderungen im Behavior Tree zu visualisieren, aufzunehmen und wieder abzuspielen.
|
|
Dies erleichtert das häufig schwierige Debuggen von Zustandsmaschinen erheblich, da das Verhalten genau untersucht werden kann.
|
|
\end{description}
|
|
|
|
Behavior Trees werden bei Verwendung von \code{BehaviorTree.CPP} in Form von .xml-Dateien gespeichert.
|
|
Diese Dateien enthalten die Anordnung der Nodes selbst, aber auch weitere Konfigurationsmöglichkeiten in Form von Ein- und Ausgabeports.
|
|
|
|
Ports können verwendet werden, um Nodes generischer zu gestalten.
|
|
Durch veränderbare Parameter im später erstellten Tree können Nodes ohne Programmänderung verändert werden.
|
|
Falls die Nodes mit Bedacht erstellt wurden, kann so auf viele spezialisierte Nodes verzichtet werden.
|
|
Um dies zu ermöglichen, kann deren Funktion durch mehrere andere Nodes in einem Subtree mit Parametern abgebildet werden.
|
|
Diese in den Ports übertragenen Daten können sowohl aus einem String ausgelesen, aber auch aus dem sogenannten Blackboard entnommen werden.
|
|
|
|
Um die Übersetzung aus einem String zu ermöglichen, muss eine entsprechende Funktion implementiert werden, die einen String in den gewünschten Zieltyp übersetzt.
|
|
Viele primitive Datentypen, wie Ganzzahlen und Gleitkommazahlen, werden von Behavior Tree.Cpp bereits durch native Funktionen unterstützt.
|
|
|
|
Das Blackboard ist ein System, dass die Nutzung von Variablen als Parameter für Ports erlaubt.
|
|
Diese werden im Hintergrund als eine Referenz auf den eigentlichen Wert gespeichert.
|
|
Eine solche Funktion erlaubt das weitere Zerlegen von Vorgängen innerhalb des Behavior Trees.
|
|
Solche kleineren Nodes sind durch ihren limitierten Umfang universeller einsetzbar, da sie nur kleinere Teilprobleme betrachten, die zu komplexeren Strukturen zusammengesetzt werden können.
|
|
|
|
Um die dadurch wachsenden Strukturen besser überblicken zu können, lassen sich Gruppen von Nodes als sogenannte Subtrees abspeichern.
|
|
Diese bilden in ihrer Gesamtheit eine neue Node, die im Behavior Tree eingesetzt werden kann.
|
|
Um den Einsatz von Variablen innerhalb eines Subtrees zu ermöglichen, besitzt jeder Subtree ein separates Blackboard.
|
|
Dadurch kann auch ein Eingriff durch äußere Einflüsse verhindert werden.
|
|
|
|
Natürlich sollte es auch möglich sein, Variablen an solche Subtrees zu übergeben.
|
|
Diese können, wie auch bei normalen Nodes, als Parameter an den Subtree übergeben werden.
|
|
Die Bibliothek \code{BehaviorTree.CPP} verbindet dann diese Werte und erlaubt die Datenübergabe zum und vom Subtree.
|
|
|
|
\subsection{Asynchrone Nodes}
|
|
Da nicht jeder Prozess sofort vollständig durchgeführt werden kann, muss die Möglichkeit geschaffen werden, lang anhaltende Prozesse abzubilden.
|
|
Dies geschieht in \code{BehaviorTree.CPP} durch asynchrone Nodes.
|
|
|
|
Eine asynchrone Node besitzt neben den Zuständen SUCCESS und FAILURE einer normalen Node auch die beiden neuen Zustände RUNNING und IDLE.
|
|
Außerdem werden mehrere Funktionen definiert, die den Lebenszyklus der Node definieren.
|
|
|
|
Wird eine Node durch den Aufruf der \code{onStart}-Funktion gestartet, geht diese in einen der Zustände RUNNING, SUCCESS oder FAILURE über.
|
|
|
|
Der Zustand RUNNING steht dabei für eine Node, die sich noch in der Ausführung befindet.
|
|
Solange dieser Zustand anhält, wird die Node nicht noch ein weiteres Mal gestartet, sondern nur der Zustand in der neuen \code{onRunning}-Funktion abgefragt.
|
|
|
|
Der IDLE-Zustand ist ein besonderer Zustand, der nur durch eine vollständige Ausführung erreichbar ist.
|
|
Er wird von der Node angenommen, nachdem deren Ausführung durch SUCCESS oder FAILURE beendet wurde.
|
|
|
|
Im Falle eines Abbruchs, der durch andere Nodes im Baum ausgelöst werden könnte, muss die Ausführung der Node vorzeitig beendet werden können.
|
|
Dies geschieht mit der neuen \code{onHalted}-Funktion, welche ausgeführt wird, wenn die Ausführung der Node abgebrochen werden soll.
|
|
\subsection{Dateiformat}
|
|
Das in Behavior Tree.Cpp verwendete Dateiformat, um Behavior Trees zu erstellen, basiert auf XML.
|
|
Jedes Dokument beginnt dabei mit einem Root-Element, dass alle Behavior Trees und eine Referenz auf die ID des Hauptbaumes enthält.
|
|
Diese wird benötigt, da auch Unterbäume im selben Dokument deklariert und genutzt werden können, die aber sonst nicht vom Hauptbaum unterscheidbar sind.
|
|
|
|
Jeder Baum beginnt mit einem Behavior Tree-Element, das als Attribut die ID des Baumes besitzen muss.
|
|
Als untergeordnete Elemente des Baumes werden die Nodes entsprechend der gewünschten Baumstruktur angeordnet.
|
|
|
|
Als Beispiel wird der bereits im Konzept verwendete Behavior Tree (siehe Abbildung \ref{choice_tree_xml}) in die entsprechende XML-Repräsentation umgewandelt.
|
|
Dabei ist zu beachten, dass die Root-Node in der Datei nicht existiert, da diese nur den Eintrittspunkt in die Struktur darstellt.
|
|
Außerdem können selbst definierte Nodes sowohl direkt mit ihrem Namen, aber auch über den Namen Action mit ihrem Namen als ID-Parameter, referenziert werden.
|
|
\begin{figure}[hpt]
|
|
\includegraphics[width=\textwidth]{img/MA-tree-demo}
|
|
\centering
|
|
\caption{Beispiel eines Behavior Trees}
|
|
\label{choice_tree_demo}
|
|
\end{figure}
|
|
\begin{figure}[hpt]
|
|
\begin{minted}[breaklines,frame=single,linenos]{xml}
|
|
<?xml version="1.0"?>
|
|
<root main_tree_to_execute="demoTree">
|
|
<Behavior Tree ID="actorTree">
|
|
<Sequence>
|
|
<Fallback>
|
|
<Action ID="IsDoorOpen"/>
|
|
<Action ID="OpenDoor"/>
|
|
<Action ID="BreakDoor"/>
|
|
</Fallback>
|
|
<CanWalkThrough/>
|
|
<WalkThrough/>
|
|
</Sequence>
|
|
</Behavior Tree>
|
|
</root>
|
|
\end{minted}
|
|
\caption{Beispiel eines Behavior Trees als .xml}
|
|
\label{choice_tree_xml}
|
|
\end{figure}
|
|
|
|
\section{Virtualisierungsumgebung}
|
|
|
|
Bei Virtualisierungsumgebungen wird zwischen virtuellen Maschinen und Containerumgebungen unterschieden.
|
|
|
|
Bei einer virtuellen Maschine (VM) werden alle Komponenten der Maschine simuliert, was die Nutzung anderer Betriebssysteme ermöglicht.
|
|
Dies beinhaltet auch die Abstraktion von Speichermedien und anderen Geräten.
|
|
Eine virtualisierte Umgebung erzeugt kleine Performanceverluste durch die Abstraktion.
|
|
|
|
Eine Containerumgebung nutzt den Kernel des Hostsystems mit, was die Virtualisierung auf die Ebenen über dem Betriebssystem beschränkt.
|
|
Die auszuführende Umgebung muss also mit dem Systemkernel lauffähig sein, um in einem Container ausgeführt werden zu können.
|
|
Die Performanceverluste dieser Umgebung sind kleiner als die einer virtuellen Maschine, da grundlegende Teile des Systems nicht mehrfach ausgeführt werden müssen.
|
|
|
|
Da bereits eine Linux-Maschine zur Entwicklung vorhanden ist, wäre die Virtualisierung eines weiteren Linux-Kernels nur mit weiterem Performanceverlust verbunden.
|
|
Außerdem soll in der Virtualisierungsumgebung Grafikbeschleunigung genutzt werden, wozu in einer VM eine Grafikkarte an das Zielsystem durchgereicht wird, die dann von der VM exklusiv genutzt wird.
|
|
In einer Containerumgebung kann die Grafikeinheit des Hostsystems mit genutzt werden, indem das durch das Hostsystem bereits abstrahierte Gerät in den Container hereingereicht werden.
|
|
|
|
Diese Punkte sprechen für die Nutzung einer Containerumgebung.
|
|
Docker ist eine etablierte Umgebung für die Ausführung von Containern, die aufgrund der extensiven Dokumentation und Verfügbarkeit auf allen gängigen Linux-Systemen ausgewählt wurde.
|
|
|
|
Ein Container wird in Docker über sogenannte Build-Files definiert.
|
|
Das Build-File enthält exakte Instruktionen, wie der Container aus anderen Containern, Dateien oder einer Kombination beider erstellt werden kann.
|
|
Der so erstellte Container wird anhand dieser Definition durch den Host erstellt.
|
|
Um diesen Prozess weiter zu beschleunigen, ist auch der Einsatz eines Buildservers möglich, der benötigte Container als Download bereitstellt.
|
|
|
|
Jeder Container enthält ein eigenes Dateisystem, das aus dem im Buildfile definierten Dateien und einem Overlay besteht.
|
|
In diesem Overlay werden temporär Änderungen gespeichert, die am Container während dessen Laufzeit vorgenommen werden.
|
|
Sofern nicht definiert, werden diese Änderungen beim Neustart des Containers wieder entfernt.
|
|
|
|
Um dies zu vermeiden, kann entweder ein Volume, eine Art virtuelles Laufwerk in einem Systemverzeichnis des Hostsystems, oder ein ``bind mount'' eingerichtet werden.
|
|
Ein ``bind mount'' ist eine direkte Verbindung zu einem Ort des Host-Dateisystems, dass in den Container hereingereicht wird.
|
|
|
|
Docker-Compose stellt eine Erweiterung von Docker dar.
|
|
Diese Erweiterung verwaltet die Inbetriebnahme der Container über ein spezielles Dateiformat.
|
|
Eine solche Funktion erlaubt das wiederholte Einrichten von Containern mit gleichen Parametern.
|
|
In dieser Datei werden weitere Optionen angegeben, die in die Umgebung des laufenden Containers eingreifen.
|
|
Dazu gehört zum Beispiel das automatisierte Übergeben von Umgebungsvariablen, Einrichten von Netzwerkumgebungen und Erstellen von Volumes und ``bind mounts''.
|
|
|
|
Diese Automatisierung erleichtert die initiale Einrichtung eines Containers auf einem neuen System, da alle benötigten Aspekte leicht angepasst werden können.
|