zurück zum Artikel

Einführung in das Robot Operating System

Know-how
Einführung in das Robot Operating System

Das ROS ist ein komfortables Framework, dessen Design-Philosophie speziell auf die Entwicklung wiederverwendbarer Software für autonome Systeme zugeschnitten ist.

Die Entwicklungsarbeiten an dem heute als Robot Operating System (ROS) bekannten Software-Framework begannen im Jahr 2007 unter dem Namen "switchyard" am Stanford Artificial Intelligence Laboratory. Seit 2008 wurde ROS hauptsächlich durch das von Scott Hassan privat finanzierte US-amerikanische Unternehmen beziehungsweise Robotikforschungsinstitut Willow Garage in Kooperation mit verschiedenen Partnern vorangetrieben. Anfang 2014 wurde Willow Garage geschlossen und die Verantwortung für die Pflege und Weiterentwicklung von ROS an die neu gegründete Open Source Robotics Foundation übertragen.

Die aktuelle ROS-Version trägt den Codenamen "Kinetic Kame" und wurde am 23. Mai 2016 veröffentlicht. Die Vorgänger waren nach chronologisch absteigender Reihenfolge sortiert: Jade Turtle, Indigo Igloo, Hydro Medusa, Groovy Galapagos, Fuerte Turtle, Electric Emys, Diamondback, C Turtle, Box Turtle, ROS 1.0.

Design-Philosophie

Dem Design von ROS liegen fünf Gedanken zugrunde, die in ihrer Summe die ROS-Philosophie ergeben:

Peer-To-Peer: ROS wurde für den Einsatz in komplexen Servicerobotern entwickelt. Diese verfügen über mehrere im Roboter befindliche Computer, die via Ethernet miteinander verbunden sind. Zusätzlich übertragen sie Daten über WLAN an leistungsstarke Rechner außerhalb des Roboters, um dort rechenintensive Aufgaben wie Spracherkennung oder Bildverarbeitung durchzuführen.

Bei Verwendung eines Software-Frameworks mit einem zentralen, außerhalb des Roboters befindlichen Hauptrechner müssten alle Daten über die WLAN-Datenverbindung fließen. Da die meisten Nachrichtennetze ohnehin in sich geschlossen sind und sich entweder innerhalb oder außerhalb des Roboters befinden, erfolgt auf diese Weise ein unnötig großer Datenaustausch über die langsamste Verbindung, was die Leistungsfähigkeit des Systems beeinträchtigt. Bei einer Peer-to-Peer-Architektur unter Verwendung von Eingangs- beziehungsweise Ausgangsdatenpuffern lassen sich die Engpässe vermeiden. Dazu ist lediglich ein Auskunftsmechanismus nötig, der den Prozessen das Auffinden ihrer Kommunikationspartner zur Laufzeit ermöglicht.

Werkzeugbasiert: Um eine geringe Komplexität und gleichzeitig eine hohe Stabilität von ROS zu erreichen, ist das ROS im Mikrokerneldesign umgesetzt. Eine Vielzahl von Werkzeugen ist für die Ausführung der zahlreichen ROS-Komponenten verantwortlich. Nachfolgend ist eine unvollständige Auswahl der Aufgaben aufgelistet, die die Werkzeuge durchführen:

Eine Übersicht über die gebräuchlichsten Werkzeuge ist im ROS Cheat Sheet [1] zu finden.

Mehrsprachig: ROS verfügt über Anbindungen für die Programmiersprachen C++, Python und Lisp in Form sogenannter ROS Client Libraries. Des Weiteren existieren unter anderem Module für Java, Haskell und Lua. Auf der ROS-Seite befindet sich eine vollständige Liste [2] aller Client-Bibliotheken.

Schlank: Viele der für zahlreiche Roboter entwickelten Algorithmen ließen sich theoretisch ebenso gut außerhalb der konkreten Projekte einsetzen. Die Wiederverwendbarkeit ist jedoch typischerweise dadurch eingeschränkt, dass die meisten Methoden dermaßen mit den anderen hardwarenahen Modulen des Roboters verzahnt sind, dass eine Extraktion der Programmlogik unmöglich ist. ROS umgeht das Problem, indem die Entwicklung von Algorithmen unabhängig von der konkreten Hardware in Bibliotheken erfolgt.

Entwickler implementieren die vollständigen Algorithmen in Bibliotheken, sodass lediglich eine kleine ausführbare Datei notwendig ist, welche die Funktionen der Bibliothek für ROS zur Verfügung stellt. Ein weiterer Vorteil unabhängiger Bibliotheken ist die einfache Testbarkeit über die definierte Schnittstelle.

Open Source: ROS steht unter der BSD-Lizenz und kann daher sowohl für kommerzielle als auch für nichtkommerzielle Projekte ohne Einschränkungen zum Einsatz kommen. Die einzelnen Module tauschen die Daten über Interprozesskommunikation aus. Entwickler müssen somit nicht mehrere Module zu einer einzigen ausführbaren Datei kompilieren. Dadurch können Anwender Module mit unterschiedlichen, beliebigen Lizenzen von GPL über BSD bis hin zu proprietären Lizenzen in einer Applikation einsetzen. Die Beschränkung des Anwendungsgebiets einer proprietären Lizenz auf das jeweilige Modul verhindert eine etwaige Lizenzverschmutzung.

Bauteile

Die Bauteile des Systems

Die grundlegenden Konzepte für das Verständnis der Funktionsweise von ROS heißen Node, Master, Message, Topic und Service. Ein Node ist ein Softwareprozess, der Daten mit anderen Nodes über Messages austauscht. Eine Message wird zum Transport von Daten verwendet und besteht aus typisierten Einträgen – ähnlich einer C-Struktur. Topic bezeichnet einen Datenbus mit einem eindeutigen Namen, über den Messages ausgetauscht werden und der für unidirektionale Kommunikation zum Einsatz kommt. Da ROS auf Peer-to-Peer-Kommunikation basiert, ist zum Auffinden der Kommunikationspartner zur Laufzeit eine Vermittlungsstelle erforderlich. Diese Aufgabe erfüllt der Master. Die Implementierung der bidirektionalen Kommunikation erfolgt über Services.

Knoten und Kanten

Unter einem Node versteht man einen Prozess, der Berechnungen ausführt. In einem typischen Szenario laufen mehrere Nodes parallel, um die an das System gestellten Anforderungen zu erfüllen. Die Bezeichnung stammt aus der Darstellung aller laufenden Prozesse als Knoten sowie der zwischen den Prozessen ausgetauschten Informationen als Kanten eines gerichteten Graphen.

Darstellung eines gerichteten Graphen mit zwei Nodes unter Verwendung des Werkzeugs rqt_graph (Abb. 1)
Darstellung eines gerichteten Graphen mit zwei Nodes unter Verwendung des Werkzeugs rqt_graph (Abb. 1)

Jeder Node wird durch einen Graph Resource Name eindeutig identifiziert. Die Namen der in Abbbildung 1 dargestellten Knoten lauten /point_publisher_node und /point_subscriber_node. Die Pfeile der Kanten geben die Flussrichtung an. Daten werden immer von einem Knoten publiziert (Quelle) und von keinem, einem oder mehreren Knoten (Senken) abonniert. Jeder Kante ist ein eindeutiger Name zugeordnet, der den Inhalt der übertragenen Informationen identifiziert und das Topic darstellt. Die Knoten in Abbildung 1 publizieren beziehungsweise abonnieren Informationen unter dem Topic /point. Das Werkzeug rosnode zeigt mit folgendem Code alle im System gestarteten Nodes:

$ rosnode list
/point_publisher_node
/point_subscriber_node
/rosout

Folgendes Listing zeigt detaillierte Informationen
zu einem Knoten:

$ rosnode info /point_publisher_node 
--------------------------------------------------------
Node [/point_publisher_node]
Publications:
* /rosout [rosgraph_msgs/Log]
* /point [geometry_msgs/Point]
Subscriptions: None
Services: 
* /point_publisher_node/get_loggers
* /point_publisher_node/set_logger_level
...

Aus dem zweiten Codeauszug ist ersichtlich, dass der Node /point_publisher_node Daten unter den Topics /rosout und /point publiziert. Bei /rosout handelt es sich um den standardmäßigen Logging-Mechanismus von ROS. Daher zeigt ihn die mit rqt_graph erstellte Ansicht im Default-Zustand nicht an. Der Node abonniert keine Themen, bietet aber zwei Services an, die für das Setzen und Auslesen des Logging-Levels verwendet werden und in ROS bei jedem Knoten automatisch vorhanden sind.

Das Werkzeug rosrun startet die Nodes. Der erste Parameter gibt den Paketnamen an und der zweite den zu startenden Knoten. Danach können Entwickler beliebig viele weitere Parameter anführen, die das Tool an den Knoten zur weiteren Verwendung durchreicht:

$ rosrun rosintro point_publisher_node 

Bei einer hohen Anzahl von Parametern ist deren Eingabe bei jedem Neustart eines Knotens mühsam, zeitaufwendig und fehlerträchtig. Des Weiteren startet der Befehl immer nur einen Node. Diese Nachteile können Entwickler durch den Einsatz sogenannter Launch-Dateien beheben. Sie verwenden XML und beschreiben, welche Nodes das System mit welchen Parametern starten soll. Folgender Code startet "point_publisher_node" ohne Angabe weiterer Parameter:

<launch>
<node pkg="rosintro" type="point_publisher_node"
name="point_publisher_node" output="screen"/>
</launch>

Ein Überblick über alle möglichen Parameterkonfigurationen ist im ROS-Wiki [3] zu finden. Zum Ausführen von Launch-Dateien kommt das Werkzeug roslaunch zum Einsatz:

$ roslaunch rosintro point_publisher_node.launch

Meister der Verwaltung

Nutzer starten den Master mit dem Werkzeug roscore. Die Ausführung muss vor dem Start des ersten Knoten erfolgen. Bei Verwendung von roslaunch zum Start eines oder mehrerer Knoten erfolgt der Start des Masters automatisch, sofern er nicht bereits läuft.

Der Master hat folgende Aufgaben:

Das zuvor gezeigte Beispiel dient als Grundlage, den zweiten Punkt zu erläutern. Darin gibt es zwei Nodes: ein point_publisher_node und ein point_subscriber_node. Damit letzterer die Punktdaten des ersten empfangen kann, müssen folgende Abläufe stattfinden:

Der point_publisher_node kommuniziert mit dem Master (Abb. 2).
Der point_publisher_node kommuniziert mit dem Master (Abb. 2).
Der point_subscriber_node kommuniziert mit dem Master (Abb. 3).
Der point_subscriber_node kommuniziert mit dem Master (Abb. 3).
Der point_publisher_node kommuniziert mit dem point_subscriber_node (Abb. 4).
Der point_publisher_node kommuniziert mit dem point_subscriber_node (Abb. 4).
  1. Der point_publisher_node informiert den Master, dass er Punktdaten unter dem Topic /point publizieren möchte (s. Abb. 2). Da noch kein Node das Topic abbonniert hat, erfolgt zunächst keine Datenübertragung.
  2. Der point_subscriber_node informiert den Master, dass er unter dem Thema /point veröffentlichte Punktdaten abonnieren möchte.
  3. Da nun sowohl ein Node existiert, der Daten unter dem Topic /point publiziert, als auch einer, der Daten zum Thema /point abonniert, informiert der Master die beiden Knoten über die Existenz des jeweils anderen, und der Datentransfer kann beginnen.

Nachrichten & Fazit

Strukturierte Nachrichten

Die Kommunikation zwischen den Knoten findet über sogenannte Messages statt. Eine Nachricht besteht aus typisierten Einträgen und hat Ähnlichkeiten mit einer C-Struktur. Das System unterstützt verschiedene Basisdatentypen, Felder und Verschachtelungen der Einträge.

Folgender Eintrag zeigt die Struktur des ROS-Datentyps geometry_msgs/Point unter Einsatz des Werkzeugs rosmsg:

$ rosmsg show geometry_msgs/Point 
float64 x
float64 y
float64 z

Der Zugriff auf die Elemente der Message erfolgt folgendermaßen:

#include <geometry_msgs/Point.h>
...
geometry_msgs::Point msg;
...
msg.x = 1.0;
msg.y = 2.0;
msg.z = 3.0;
...
point_publisher.publish(msg);


Entwickler können eigene Nachrichten durch Textdateien mit der Endung ".msg" spezifizieren. Die jeweilige ROS-Client-Bibliothek enthält Codegeneratoren, die aus den .msg-Dateien beim Build-Vorgang Code für die jeweilige Zielsprache erzeugen.

Eindeutige Themen

Topic (Thema) bezeichnet in ROS einen mit einem eindeutigen Namen versehenen Datenbus. Der Name ermöglicht den Nodes (unter Einbeziehung des Master) das Auffinden ihrer Kommunikationspartner für den Austausch von Nachrichten zur Laufzeit. Das Erzeugen der Daten ist vom Verbrauch entkoppelt (Producer/Consumer-Pattern). Datensenken (Knoten, die Nachrichten empfangen) greifen auf Daten eines abonnierten Themas zu. Datenquellen (Knoten, die Nachrichten versenden) publizieren Daten zu einem Topic.

Zu einem Thema kann es mehrere Datensenken, aber nur eine Datenquelle geben (1-1- oder 1-n-Verbindung). Dieser Nachrichtenaustauschmechanismus ist für die unidirektionale Kommunikation vorgesehen. Einen Überblick über alle Themen, zu denen es zum Zeitpunkt des Aufrufs sowohl Datenquellen als auch Datensenken gibt, listet das Werkzeug rostopic auf:

$ rostopic list
/point
/rosout
...

Eine weitere nützliche Funktion des Werkzeugs ist die Anzeige der zu einem Topic publizierten Messages:

$ rostopic echo /point 
x: -1.0
y: 0.0
z: 0.0
---
x: -2.0
y: 0.0
z: 0.0
---
...

Dienst für Nachrichtenpaare

Services ermöglichen bidirektionale Kommunikation in der Form von Request/Response-Nachrichten zwischen verschiedenen Nodes, während Topics nur für den unidirektionalen Datenaustausch zum Einsatz kommen. Ein Service besteht immer aus einem Nachrichtenpaar, das die Struktur der Request- und Response-Nachricht definiert:

uint32 opA
uint32 opB
---
uint32 result


Wie die Topics identifiziert den Service eines Knoten ein eindeutiger Name. Der Aufruf des Service erfolgt, indem ein Service-Client-Node eine Request-Nachricht (bestehend aus opA und opB) an den Service-Server-Node verschickt.

Anforderung der Durchführung einer Addition vom /service_server_node (Service Request) (Abb. 5)
Anforderung der Durchführung einer Addition vom /service_server_node (Service Request) (Abb. 5)

Letzterer führt die gewünschte Operation aus und antwortet mit der Response-Nachricht, die das gewünschte Ergebnis (result) enthält.

Rückgabe des Ergebnisses der Addition an den /service_client_node (Service Response) (Abb. 6)
Rückgabe des Ergebnisses der Addition an den /service_client_node (Service Response) (Abb. 6)

ROS-Client-Bibliotheken abstrahieren die Interknotenkommunikation vom Programmierer und stellen den Vorgang wie einen Remote Procedure Call dar.

Fazit

ROS vereinfacht die Softwareentwicklung für komplexe autonome Systeme, indem es voneinander unabhängige Rechenprozesse in verschiedene Knoten aufteilt. Die Prozesse laufen parallel und kommunizieren über Peer-To-Peer-Mechanismen miteinander.

Die Vorgehensweise eignet sich gut für die Modellierung autonomer Systeme, da die Repräsentation durch Knoten den Gegebenheiten in einem solchen System sehr ähnlich ist. Eine umfangreiche Werkzeugpalette ermöglicht das schnelle Auffinden von Fehlern und erleichtert die Arbeit mit ROS erheblich. (rme [4])

Alexander Entinger
ist Gründer und Geschäftsführer der LXRobotics GmbH. Gleichzeitig ist er als Softwareentwickler für eingebettete Systeme bei der Firma DS Automotion tätig und betreut das Studentenprojekt RoboCupRescue an der Fachhochschule Hagenberg, bei dem ein Rettungsroboter für den Einsatz in Katastrophenszenarien entwickelt wird.


URL dieses Artikels:
http://www.heise.de/-3273655

Links in diesem Artikel:
[1] https://github.com/ros/cheatsheet
[2] http://wiki.ros.org/Client%20Libraries
[3] http://wiki.ros.org/roslaunch/XML
[4] mailto:rme@ct.de