Universität Erlangen

Werbung
Universität Erlangen-Nürnberg
Lehrstuhl für Informatik 8
Künstliche Intelligenz
Studienarbeit:
Graphenbasierte Robotersteuerung,
Konzeption und Implementierung einer
autonomen Erkennung von Hindernissen und
Abweichungen.
Sami Ben Younes Abidi
Fachbereich: Informatik
Betreuer:
Prüfer:
Dr.-Ing. Bernd Ludwig
Prof. Dr. Herbert Stoyan
1
Inhaltsverzeichnis:
1. Einleitung und Aufgabenstellung ........................................................................................ 3
1.1. Motivation und Einordnung der Arbeit ......................................................................... 3
1.2. Zielsetzung .................................................................................................................... 3
1.3. Weiterer Aufbau der Arbeit ........................................................................................... 5
2. Einführung in den Roboter Robertino und Stand der Technik ....................................... 6
2.1. Beschreibung von Robertino ......................................................................................... 6
2.2. Zugriff auf Robertino .................................................................................................... 7
2.3. Stand der Technik .......................................................................................................... 8
3. Plandarstellung .................................................................................................................... 13
3.1 Einführung in die Graphentheorie ................................................................................ 13
3.2 Modellierung eines Plans ............................................................................................. 14
3.2.1 Positionen und Abstände ........................................................................................... 14
3.2.2 Winkeln ..................................................................................................................... 17
4. Wegberechnung .................................................................................................................. 20
4.1 Der Dijkstra-Algorithmus ............................................................................................ 20
4.2 Einsatz von Dijkstra bei der Wegberechnung .............................................................. 22
5. Nachrichtenübertragung..................................................................................................... 24
5.1 Abbildung Kommandos/Nachrichten ........................................................................... 24
5.2 Implementierung der Abbildung in Java ...................................................................... 25
5.3 Ablaufsbeispiel ............................................................................................................. 28
6. Fehlererkennung und Korrekturverfahren ....................................................................... 30
6.1 Erkennung von Hindernissen ....................................................................................... 30
6.2 Korrekturverfahren bei Hindernissen .......................................................................... 31
6.3 Erkennung von Abweichungen ................................................................................... 32
6.4 Korrekturverfahren bei Abweichungen ........................................................................ 33
6.4.1 Lineare Regression .................................................................................................... 33
6.4.2 Korrekturverfahren .................................................................................................... 35
7. Architektur und Zusammenspiel der in Java implementierten Komponenten ........... 37
7.1 Einführung in UML (Unified Modelling Language) ................................................... 37
7.1.1 UML-Klassendiagramm ............................................................................................ 37
7.1.2 UML-Sequenzdiagramme ......................................................................................... 38
7.1.3 UML-Aktivitätsdiagramme ....................................................................................... 38
7.2 Überblick auf die Klassenarchitektur ........................................................................... 39
7.3 Die Klasse Plan ............................................................................................................ 41
7.4 Die Klasse Show_the_way ........................................................................................... 42
7.5 Die Klassen Client, DriveDClient und MouseDClient ................................................ 43
7.6 Die Klassen ClientInputThread und MouseClientInputThread.................................... 44
7.8 Die Klasse Controller ................................................................................................... 44
7.9 Die Klasse ObtacleDetected ......................................................................................... 45
7.10 Die Klassen Deviation und Regression ...................................................................... 45
7.11 Zusammenspiel der Komponenten ............................................................................. 46
8. Tests und Ergebnisse ......................................................................................................... 51
9. Zusammenfassung / Ausblick ........................................................................................... 52
10. Literatur............................................................................................................................... 54
2
1. Einleitung und Aufgabenstellung
1.1. Motivation und Einordnung der Arbeit
Um unser Leben zu erleichtern werden heutzutage verschiedene Roboter fast überall
eingesetzt. Diese Roboter können für uns mehrere Aufgaben von den ganz einfachen
Aufgaben (z.B. Waschen mit einer Waschmaschine) bis zu den ganz komplizierten
(z.B. Exploration der Marsoberfläche) erledigen. Für die ganz komplizierten Aufgaben
wurde eine neue Generation von Robotern entwickelt. Diese Roboter verfügen sogar
über künstliche Intelligenz, so dass sie unabhängig vom Menschen die Umwelt
beobachten können und Entscheidungen selbstständig treffen.
Nach [Go00] bedingt die Konstruktion von Robotern als autonome intelligente
Systeme ein enges interdisziplinäres Zusammenwirken der Gebiete mechanisches
und elektrisches Design der aktorischen Komponenten mit den sensorisch-kognitiv
orientierten Bereichen: Signalverarbeitung, Mustererkennung, Wissenrepräsentation
und Inferenz, Bilderkennug, Planung, Navigation, Lernen, Dialogführung MenschMaschine, Architektur.
Aus Sicht der künstlichen Intelligenz klassifiziert [Go00] die Roboter in drei
Kategorien. Bei den stationären Robotern verfügt der Roboter über einen Arm und
einen Greifer. Es geht hier neben der Planung kollisionsfreier Bewegungen des Armes
um die Erkennung und Verfolgung von Objekten sowie die exakte Bestimmung ihrer
Lage für den Greifvorgang.
Bei den mobilen Robotern verfügen der Roboter meistens über Räder und mehrere
Sensoren. Mit den Rädern lässt sich der Roboter fahren. Mit den Sensoren exploriert
er seine Umgebung. Die Hauptaufgabe besteht hier weiterhin in der Navigation, die in
unterschiedlich stark strukturierten, dynamischen und ggf. auch unbekannten
Umgebungen zuverlässig arbeitet.
Die humanoiden Roboter stellen die „Krone der Robotik“ dar. Die Fähigkeiten dieser
Roboter sollten weitgehend dem Menschen nachgebildet werden. Diese Roboter
sehen strukturell wie die Menschen aus und können sogar laufen und Treppen
steigen.
1.2. Zielsetzung
Haben Sie einmal in einem großen Flughafen den Weg zum Terminal nicht gefunden?
Es ist absolut möglich, dass man in einem Flughafen wie Frankfurt den richtigen Weg
zu einem bestimmten Terminal nicht findet, obwohl viele Flughafenmitarbeiter am Ort
3
sind und gerne helfen. Stellen Sie sich vor, dass am Flughafen viele kleine Autos auf
Sie warten. Diese Autos (Roboter) verfügen über ein Sprachsystem zur Begrüßung
und können Sie bis zum gewünschten Gate begleiten. So sind Sie fast sicher, dass
Sie den Flieger nicht verpassen werden, was natürlich sehr schön wäre. Nennen wir
diese Anwendung Flughafenbegleiter.
Der Lehrstuhl für Künstliche Intelligenz an der Universität Erlangen-Nürnberg verfügt
über einen kleinen Roboter namens Robertino. Mit diesem Roboter wird versucht eine
ähnliche Anwendung wie den Flughafenbegleiter zu implementieren. Man kann diese
Anwendung wie folgt beschreiben: Der Roboter steht vor der Tür des Aufzugs des
Lehrstuhls und wartet. Wenn die Tür aufgeht, muss Robertino erkennen, ob der
Aufzug leer oder nicht ist. Wenn eine Person im Aufzug erkannt ist, begrüßt Robertino
den Besucher und fragt ihn, wo er hin möchte. Er erkennt das gewünschte Ziel und
fordert den Besucher auf, ihn zu folgen. Es klingt alles so einfach, ist aber sehr
kompliziert zu realisieren. Es könnte auch Hindernisse auf dem Weg zum Zielraum
geben. Deswegen muss Robertino so intelligent sein, dass er die Hindernisse
selbstständig erkennt und Umwege berechnen kann. Robertino kann auch aus
irgendeinem Grund aus seinem Weg abweichen. Das muss er auch automatisch
erkennen und den Fehler rechtzeitig korrigieren.
Im Rahmen dieser Studienarbeit werden folgende Teilaufgaben untersucht und in
Java implementiert.
1. Plandarstellung und Wegberechnung
2. Fehlererkennung und notwendige Korrektur
Bei der Plandarstellung wird der Lehrstuhlplan in einer geeigneten Form modelliert.
Der Roboter soll in der Lage sein, diese Darstellungsform zu verstehen, damit er sich
auf dem Gang des Lehrstuhls orientieren und positionieren kann.
Die Teilaufgabe Wegberechnung hat als Ziel, dem Roboter zu ermöglichen sich
zwischen verschiedenen Positionen auf dem Plan zu bewegen. Es wird spezifiziert,
wie Robertino den kürzesten Weg zu einem Ziel berechen kann.
Die Teilaufgaben Fehlererkennung
und notwendige Korrektur untersuchen die
automatische Erkennung von Hindernissen oder möglichen Abweichungen von
Robertino auf dem Weg zu seinem Ziel. Bei Fehlersituationen muss eine automatische
Korrektur ohne Eingriff des Menschen erfolgen.
4
1.3. Weiterer Aufbau der Arbeit
Begonnen wird diese Studienarbeit mit dem Kapitel 2, in dem eine Beschreibung des
Roboters Robertino und der Zugriffsmöglichkeiten vorgestellt wird. In Kapitel 3 wird
zunächst die Graphentheorie eingeführt. Anschließend wird diese Theorie in die
Modellierung der Lehrstuhlkarte eingesetzt. Der Kapitel 4 widmet sich dem Einsatz
eines bekannten Algorithmus bei der Wegberechnung des Roboters. In Kapitel 5 wird
die Nachrichtenübertragung zwischen dem Roboter und den Steuerkomponenten
vorgestellt. Die verschiedenen Fehlersituationen und Korrekturverfahren werden in
Kapitel 6 behandelt. Die Beschreibung der in Java implementierten Klassen sowie des
Zusammenspiels
dieser
Klassen
folgt
in
Kapitel
7.
Kapitel
8
beschreibt
Testergebnisse der im Rahmen dieser Studienarbeit entwickelten Lösung.
Abschluss dieser Arbeit bilden eine Zusammenfassung und ein Ausblick auf weitere
Erweiterungsmöglichkeiten der entwickelten Komponenten.
5
2. Einführung in den Roboter Robertino und Stand der
Technik
2.1. Beschreibung von Robertino
Abbildung 2-1: Robertino [Li02]
Der Roboter Robertino (Abbildung 2-1) besitzt 3 Motoren in einem Abstand von 120
Grad. Er verfügt auch über 3 Räder, die ihm Bewegungen in die X-Richtung und die
Y-Richtung sowie Rotation um die eigene Achse ermöglichen. Um die Abstände
messen zu können verfügt Robertino über 6 Infrarotsensoren. Mit seiner Kamera kann
Robertino auch Bilder aufnehmen, deren Auflösung 640x480 ist. Unter dem Roboter
wurde auch eine optische Maus eingebaut, deren Nutzen später erwähnt wird.
Das „Gehirn“ von Robertino ist
ein industrieller Rechner mit den folgenden
Charakteristiken:

500MHz Intel Mobile-Pentium III

128MB RAM, 20GB Hard disk (IDE)

Graphics adapter

2x USB, 2x RS232, 1x Parallel port

3x Firewire, 2x CAN-Bus controller (active), 2x 32bit

PC-Card slots

10/100 MBit LAN, IEEE802.11a wireless LAN

Betriebsystem: Debian GNU/LINUX
6
2.2. Zugriff auf Robertino
Der Zugriff auf die Hardware von Robertino erfolgt über so genannte Dämonen, die
entweder in C oder in Java geschrieben sind.
Die in Rahmen dieser Studienarbeit verwendeten Dämonen sind:
1. Drived: ist ein TCP/IP Server auf Port 30000 und empfängt vom Client Nachrichten
in der Form 26##omega(100),vx(100),vy(100)#. Die Zahl 26 entspricht in diesem
Beispiel der Länge der Nachricht.
Mit diesen ASCII-String-Nachrichten kann man die Geschwindigkeit des Roboters
auf der x-Achse und die y-Achse sowie seine Rotationsgeschwindigkeit einstellen.
omega(100)
setzt die Winkelgeschwindigkeit auf 100 mdeg/s. vx(100) setzt die
Geschwindigkeit auf der x-Achse auf 100 mm/s. vy(100) setzt die Geschwindigkeit auf
der y-Achse auf 100 mm/s.
Dieser Server sendet dem Client als Antwort seine Sensorwerte. Die Antwortnachricht
ist von der Form 99##ADC00(60),ADC01(5),...,va0(0),va1(9),va2(5)#. Der Sensor
ADC00 liefert in diesem Fall den Wert 60 mm zurück. Die Abbildung 2-2 zeigt die
x-Achse und die y-Achse des Roboters. Die Abbildung 2-3 stellt die verschiedenen
Sensoren dar. Beide Abbildungen wurden aus [Li02] übernommen.
Abbildung 2-2: x-Achse, y-Achse
Abbildung 2-3: Sensoren
7
2. Moused: ist ein TCP/IP Server auf Port 30002; er berichtet dem Client über die
Bewegungen der unter dem Roboter eingebauten optischen Maus. Als Mauswerte
bekommt der Client die Koordinaten (x,y) des Roboters im Bezug auf seine
Startposition.
Dazu besitzt Robertino auch den Server:
3. Visiond: ist ein TCP/IP Server auf Port 30001; er liefert Kameraaufnahmen (VGAScans) in JPEG, RAW Format.
Ein Client öffnet zum Beispiel eine TCP/IP -Verbindung
zum Drived-Server und
sendet dem Roboter auf dieser Verbindung die Geschwindigkeitseinstellung. Ein
zweiter Client öffnet eine andere TCP/IP -Verbindung zum Moused-Server. Der
Roboter reagiert mit der notwendigen Bewegung in die gewollte Richtung und sendet
dem Drived-Client die Sensormesswerte und dem Moused-Client die Mauswerte
zurück.
2.3. Stand der Technik
Umgebungsmodellierung:
Bei der Umgebungsmodellierung erstellt man ein Modell auf der Basis der
Informationen, die der Roboter über seine Sensoren von seiner Umgebung erhält. Wir
wollen kurz unterschiedliche Arten von Umgebungsmodellen diskutieren. [Go00]
unterscheidet hierbei zwischen:
a) topologischen,
b) geometrischen,
c) rasterbasierten Modellen.
topologische Karten:
bei einer topologischen Karte der Umgebung werden annotierte Graphen verwendet.
Die Kanten dieser Graphen stellen für den Roboter relevante Orte der Umgebung dar.
Eine Kante verbindet dann zwei Knoten, wenn sie unmittelbar voneinander erreichbar
sind.
Der
Vorteil
dieser
Repräsentation
im
Vergleich
zu
den
anderen
Modellierungsmöglichkeiten liegt in der Kompaktheit. Diese Karten sind auch sehr gut
für die Wegplanung geeignet, weil das Problem in diesem Fall auf die Erreichbarkeit in
Graphen reduzieren lässt. Es gibt schon Systeme, die toplogische Modelle für die
8
Navigation nutzen [Hi96]. Diese Art von Modellierung wird im Rahmen dieser
Studienarbeit implementiert.
geometrische Modellierung:
2D- und 3D-Modelle stellen die detaillierteste Modellierungsform dar. Diese Modelle
erfordern geeignete Verfahren zur Detektion und Lokalisierung der einzelnen Objekte.
Deswegen liegen ihrer Nachteile in ihrer schwierigen Lern- und Aktualisierbarkeit.
Rasterbasierte Modelle:
Rasterbasierte oder Occupancy probability grid maps ist eine sehr populäre
Repräsentationsform für autonome mobile Roboter. Dieses Modell besteht aus einer
Diskretisierung der Umgebung des Roboters in üblicherweise kleine Quadrate. Jede
Zelle in dieser Gridkarte enthält die Wahrscheinlichkeit, dass die entsprechende Stelle
der Umgebung durch ein Hindernis belegt ist.
Lokalisierung
Ein weiteres grundlegendes Problem der mobilen Robotik
ist
das Problem der
Lokalisierung oder der Positionsbestimmung. Wenn der Roboter über ein Modell der
Umgebung verfügt, lässt sich das Lokalisierungsproblem als die Aufgabe beschreiben,
die wahrscheinlichste Position des Roboters gegeben alle Sensorinformationen und
alle durchgeführten Navigationsoperationen zu berechnen.
Die Markow-Lokalisierung ist ein sehr allgemeiner Ansatz zur Schätzung der Position
eines
mobilen
Roboters.
Man
versucht
bei
diesem
Ansatz
eine
Wahrscheinlichkeitsverteilung P(L = l) über dem Zustandsraum des Roboters in seiner
Umgebung zu schätzen. Der Zustandsraum des Roboters enthält in diesem Fall alle
möglichen Positionen und Orientierungen des Vehikels.
Formal
besteht
das
Problem
der
Positionsschätzung
daraus,
eine
Wahrscheinlichkeitsverteilung P(Lt) über eine Zufallvariable Lt zu schätzen. Die Werte l
der Variablen Lt sind die 3-Tupel der Form l = (x,y,ß), wobei x und y die Position und ß
die Orientierung des Roboters angeben.
Für jeden möglichen Zustand des Roboters beschreibt die Verteilung P(L t) die
Wahrscheinlichkeit, dass sich der Roboter genau in diesem Zustand befindet. Diese
Wahrscheinlichkeitsverteilung P(Lt) wird aktualisieret, wenn der Roboter Informationen
9
über
seine
Umgebung
Sensorinformationen.
aufnimmt.
Sei
d
der
gesamte
Datenstrom
von
Die Markow-Lokalisierung schätzt eine Posterior-Verteilung
über LT bedingt über allen erhaltenen Informationen:
P(LT = l | d) = P(LT = l | d0,d1,..,dT)
[Go00] bietet eine ausführliche Beschreibung der Markow-Lokalisierung an.
Pfadplanung
Pfadplanung gehört zu den klassischen Problemen der mobilen Robotik. Das Ziel der
Pfadplanung ist die Berechnung eines möglichst kurzen Weges von einer aktuellen
Position des Roboters zu einer gegebenen Zielposition.
Es existieren mehrere Verfahren für die die Berechnung solcher Trajektoren. Eine
häufige Voraussetzung aber ist, dass die Umgebung des Roboters vollständig bekannt
ist. Eine zweite Voraussetzung ist, dass die Umgebung während der Fahrt des
Roboters unverändert bleibt. Bekannte Techniken dieser Art sind zum Beispiel VornoiDiagramme oder Sichtbarkeitsgraphen. Der Unterschied zwischen diesen Verfahren
ist, dass Sichtbarkeitsgraphen Weglänge minimieren, während Vornoi-Diagramme
versuchen, den Abstand zu Hindernissen zu maximieren.
Das Buch [La91] ist dem Pfadplanungsproblem komplett gewidmet.
Wenn sich die Umgebung aber dynamisch verändert, wird die Potentialfeldmethode
eingesetzt. [Kh86] bietet eine detaillierte Beschreibung dieser Methode.
Es gibt auch eine andere Methode, die speziell für Occupancy grid maps geeignet ist.
Diese Methode heißt Value Iteration und wird in [Go00] ausführlich beschrieben.
Wenn sich die Umgebung des Roboters aber verändert und Hindernisse plötzlich auf
dem Pfad stehen werden typische Techniken wie reaktive Kollisionsvermeidungen
eingesetzt. Im Rahmen dieser Studienarbeit werden solche Techniken auch
eingesetzt.
Systeme
Die oben beschriebenen Techniken werden bei verschiedenen Systemen für die
Navigation autonomer mobiler Roboter eingesetzt.
Beispiele hierfür sind die Roboter Xavier, Kurt, Rhino und Minerva. Xavier wird zur
Navigation in einem Bürogebäude eingesetzt. Kurt kann Kanalsysteme autonom
inspizieren. Die Systeme Rhino und Minerva wurden in den Jahren 1997 und 1998 im
Deutschen Museum Bonn sowie in National Museum of American History in
Washington DC über mehrere Tage als interaktive Museumsführer eingesetzt. Beide
10
Roboter waren sehr zuverlässig und führten tausende von Besuchern durch die
Ausstellung und erklärten Exponate über ihre Displays.
Rhino hat 47 Stunden operiert und eine Distanz von 18,6 km zurückgelegt. Das
gewünschte Exponat wurde nur in 6 von 2400 Fällen nicht erreicht.
In Nagoya, Japan wurde 1997 die erste Weltmeisterschaft fußballspielender Roboter
ausgetragen. Deutsche Teams waren dabei und waren sehr erfolgreich.
Xavier [Li03]
Rhino [Li04]
Kurt [Li05]
Minerva [Li06]
Ein Team der Universität Stanford hat zusammen mit dem Volkswagen Electronics
Research Laboratory (ERL) und seinem auf den Namen "Stanley" getauften VW
Touareg die DARPA Grand Challenge 2005 in der Mojave-Wüste gewonnen. Ziel des
Wettbewerbs war es, mit autonomen Fahrzeugen einen vorgegeben Parcours von 130
Meilen möglichst schnell zu absolvieren.
Stanley [Li07]
Der von den Entwicklungsingenieuren „Stanley“ getaufte Prototyp, ist ausgerüstet mit
Sensoren und von vier Laser-Detektoren. Ergänzt werden die Systeme durch StereoSichtgeräte, hoch entwickelte 24-GHz-Radaranlagen und ein besonders exakt
analysierendes, satellitengestütztes GPS-Navigationssystem, das die genaue Position
des Fahrzeugs auf den Millimeter genau digital abbildet. Verarbeitet werden die
Informationen von sieben zusammengeschalteten Pentium M-Motherboards mit einer
Rechenleistung von 1,6 GHz pro Prozessor. Die gesammelten Daten werden von
diesen Rechnern ständig kontrolliert und die die notwendigen Fahranweisungen
11
werden daraufhin ermittelt. Im Rahmen dieser Studienarbeit wird ein ähnlicher Ansatz
implementiert.
12
3. Plandarstellung
Beim Autofahren, brauchen wir meistens eine Karte. Diese Karte wird entweder auf
Papier gedruckt, ist elektronisch verfügbar (z.B. GPS) oder wird einfach in unseren
Gehirnzellen gespeichert. Ähnlich braucht unser Roboter eine Karte, um sich zu
orientieren. Aus einem Plan wird eine Karte erzeugt. Wie könnte man aber diese Karte
modellieren, so dass Robertino ihre Inhalte leicht verstehen kann.
Ich habe mich für Graphen entschieden um Pläne (bzw. Karten) darzustellen. Diese
Entscheidung hat aber ihre Gründe. Graphendarstellung ist eine ausgereifte Technik,
die sehr effiziente Algorithmen bietet. Diese Algorithmen sind von enormer Bedeutung
für dieses Projekt, weil sie die Arbeit sehr vereinfachen. Deswegen gibt es zunächst
eine kleine Einführung in die Graphentheorie.
3.1 Einführung in die Graphentheorie
Das Thema Graphentheorie wird im Buch [Kla00] gründlich behandelt. Hier gibt es
aber nur die wichtigsten Begriffe und Definitionen aus diesem Buch.
Ein Graph G = (V, E) ist ein Tupel mit nicht leerer, endlicher Knotenmenge
V = {v1,…, vn} und Kantenmenge E = {e1,…, em}. Jede Kante hat zwei Endknoten und
wird mit e = [i, j] bezeichnet.
Ein Digraph G = (V, E) ist wie ein Graph aber jede Kante e Є E hat eine Richtung. In
diesem Fall bezeichnet man die kanten e mit (i, j) wobei i der Anfangspunkt t(e) und j
die Spitze h(e) von e ist.
t(e) und h(e) sind die Endpunkte von e.
Eine Adjazenzmatrix A(G) ist eine n x n-Matrix mit den Werten:

aij = 1
falls [i, j] Є E

aij = 0
sonst
(oder (i, j) Є E für Digraphen)
Ein Weg P = (i1,…ip, ip+1,…, ie) ist eine Folge von Knoten mit:

[ip, ip+1] Є E
für Graphen

(ip, ip+1) Є E oder (ip+1, ip) Є E
für Digraphen
Ein zusammenhängender (Di-)Graph besitzt die folgende Eigenschaft: Je zwei
Knoten in G sind durch einen Weg verbunden.
13
Beispiel
Die Abbildung 3-1 zeigt links einen Graphen und rechts einen Digraphen. Darunter
sind
die
zugehörigen
Adjazenzmatrizen
dargestellt.
Beide
Beispiele
sind
zusammenhängende (Di-)Graphen.
Abbildung 3-1: Graph und Digraph
3.2 Modellierung eines Plans
3.2.1 Positionen und Abstände
Graphen bestehen aus Knoten und Kanten. Die Kanten tragen Kosten. Was
modellieren also diese Knoten, Kanten und Kosten?
Die Knoten sind ausgewählte Positionen des Roboters. Die Kanten verbinden diese
Positionen und ihre Kosten entsprechen den tatsächlichen Abständen zwischen den
Positionen. Der Roboter bewegt sich zwischen diesen Positionen und fährt entlang der
dazwischen liegenden Kanten.
14
Abbildung 3-2: Floor des KI-Lehrstuhls und Graph
15
Anhand des Beispiels (Abbildung 3-1) wird diese Modellierung deutlich gemacht.
Die von 1 bis 15 durchnumerierten Knoten sind
für den Roboter ausgewählte
Positionen. Der entstehende Graph ist eine sehr einfache Möglichkeit den Plan zu
modellieren. Natürlich gibt es mehrere bessere Möglichkeiten mit größerer Anzahl von
Knoten und Kanten um diesen Plan zu modellieren. Zum Beispiel könnte man den
einfachen Graph um mehrere Knoten und Kanten erweitern. Je mehr Knoten und
Kanten es gibt, desto besser ist unsere Darstellung. Wenn es mehr Kanten und
Knoten
gibt, gibt es natürlich mehrere unterschiedliche Wege mit dem gleichen
Startknoten und Zielknoten. Wenn ein ursprünglicher Weg aus irgendeinem Grund
nicht befahrbar wäre, hätte Robertino alternative Möglichkeiten.
Bleiben wir jetzt bei der einfachen Modellierung. Es gibt immer eine Strecke, die vom
Fahrstuhl bis zu einer bestimmten Tür führt. Eine Strecke ist eine Folge von Knoten
und Kanten. Der Roboter braucht zusätzlich die Winkel zwischen den benachbarten
Kanten auf seinem Weg zu einem bestimmten Ziel. Zusätzlich zu den Abständen
zwischen den Knoten muss man die notwendigen Winkel berechen und speichern.
Die Abbildung 3-3 ist eine Abstandsmatrix. Sie wird verwendet, um die Abstände
zwischen den Knoten zu speichern.
Knoten
1
1
2
2
3
4
690
3560
5
6
690
1980
7
8
690
690
9
11
12
13
14
690
690
1340
15
590
590
3
690
4
3560
5
690
6
1980
7
690
8
690
1770
9
10
10
690
1770
690
11
4210
4210
12
690
13
690
14
1340
15
690
690
Abbildung 3-3: Abstandsmatrix
In der Zelle [1,2] gibt es zum Beispiel die Zahl 590. Das bedeutet, dass der Abstand
zwischen den Knoten (1) und (2) 590 mm beträgt. Diese Matrix ist symmetrisch, weil
16
der verwendete Graph kein gerichteter Graph ist. Der Roboter kann sich also in zwei
Richtungen auf der gleichen Kante bewegen. Wenn eine Zelle der Abstandmatrix leer
ist, dann existiert keine Kante zwischen den betroffenen Knoten.
Matrizen sind in Java sehr einfach darzustellen. Zuerst erzeugt man die leere Matrize:
int[][] distance_between_nodes = new int[14][14];
Dann füllt man sie mit den notwendigen Abständen. Um den Abstand zwischen den
Knoten (1) und (2) zu speichern braucht man folgende Zuweisungen:
distance_between_nodes[1][2] = 590;
distance_between_nodes[2][1] = 590;
Dazu muss man alle Zellen in der Matrize, die leer geblieben sind, mit „unendlich“
füllen. Eine leere Zelle wie (1,5) z.B. bedeutet, dass es keine Kante zwischen den
Knoten (1) und (5) existiert.
3.2.2 Winkeln
Jetzt muss man eine geeignete Darstellungsform für die Winkel finden. Betrachten wir
die zwei Kanten [2,4] und [4,5]. Der Winkel zwischen diesen Kanten beträgt 90 Grad.
Der Roboter fährt entlang der Kante [2,4]. Wenn er den Knoten (4) erreicht dreht
gegen den Uhrzeigersinn um 90 Grad dann fährt er weiter entlang der Kante [4,5].
Abbildung 3-4: Graphenerweiterung
Um die Strecke (3-4-5) zu fahren, führt der Roboter eine Folge von Befehlen aus.
17
Diese Folge könnte so aussehen:
GO [3560] ; TURN [-90] ; GO[690]
Er benötigt immer den Winkel zwischen der Kante, auf der er sich zur Zeit befindet,
und der nächsten Kante auf seinem Weg zum Ziel.
Man kann eine 3-dimensionale Struktur (Abbildung 3-5) verwenden:
Zelle (1,2,3) mit Inhalt [-90]
3
-90
2
Knoten y
3
1
2
1
1
2
Knoten z
3
Knoten x
Abbildung 3-5: Würfel der Winkeln
Die drei Dimensionen des Würfels sind Knoten [x], Knoten [y] und Knoten [z]. Der
Inhalt der Zelle (x, y, z) ist die Antwort auf die Frage: Um wie viel Grad w muss sich
Robertino drehen, wenn er die Fahrt auf der Teilstrecke [x-y] beendet hat und auf die
Teilstrecke [y-z] weiter fahren muss? (Abbildung 3-6)
z
Dist(y,z)
Dist(x,y)
x
W
y
Drehung um w Grad um auf der
Kante [y-z] weiter zu fahren
aktuelle Bewegungsrichtung von Robertino [ x-y ] 
Abbildung 3-6: Drehung
18
x
Im Beispielswürfel bedeutet der Inhalt -90° der Zelle (1, 2, 3), dass Robertino genau
eine Drehung von -90° machen muss, um von der Teilstrecke [1-2] auf die Teilstrecke
[2-3] zu kommen.
Um diesen Winkelwürfel in Java umzusetzen, kann man ein 3-dimensionales Feld
verwenden. Man erzeugt zuerst den leeren Würfel:
int[][][] angle_between_nodes = new int[14][14][14];
Dann füllt man dieses Feld mit den notwendigen Winkeln. Um den Winkel zwischen
den Kanten [1-2] und [2-3] zu speichern braucht man folgende Zuweisung:
angle_between_nodes[1][2][3] = -90;
Jetzt verfügt Robertino über alle notwendigen Abstände und Winkel. Er bekommt vom
Besucher eine Zieleingabe. Robertino muss in seinen Plan „schauen“ und den
richtigen Weg zum Ziel finden. Dieser Weg muss so kurz wie möglich sein. Weil der
Plan als Graph modelliert wird, kann man hier einen Algorithmus für kürzeste Wege
verwenden.
19
4. Wegberechnung
4.1 Der Dijkstra-Algorithmus
Dieser Abschnitt beruht auf dem Kapitel 6 von [Kla00].
Wir betrachten einen Digraphen G=(V,E) mit den Kosten c(e)=c(ij) für alle e = (ij) Є E
Sei s ein beliebiger aber fest gewählter Knoten s Є V.
Man bezeichnet das folgende Problem als kürzeste Diweg Problem:
Finde für alle i Є V \ {s} einen Diweg Psi von s nach i mit minimalen Kosten c(Psi)
wobei c(Psi) = ∑ c(e) und e Є Psi. Man nennt c(Psi) auch die Entfernung von s nach i in
G bzgl. der Kosten c(e), e Є Psi.
Mit dem Dijkstra-Algorithmus kann man das kürzeste Weg Problem lösen.
Dijkstra-Algorithmus
(Input)
G = (V,E) Digraph mit Kosten c(e) für alle e Є E
(1)
Setze d(i) := ∞ (für alle i= 1,…,n)
d(s) := 0
pred(s) := 0
p := 1
Setze Xp := {s}
für alle i Є V \ Xp
T(i) := c(si) falls (s,i) Є E
T(i) := ∞
sonst
für alle i Є V \ Xp
pred(i) = s
(2)
Finde ip+1 mit T(ip+1) = min i Є V\ Xp T(i)
und setzte d(ip+1) := T(ip+1)
falls T(ip+1) = ∞ (STOP)
Es existieren keine Diwege von s nach i für alle i Є V \ Xp
(3)
Setze Xp+1 := Xp U { ip+1}
Setze p := p+1
falls p = n (STOP) alle kürzeste Diwege Psi gefunden
(4)
für alle i Є V \ Xp
falls T(i) > d(ip) + c(ip,i) setze T(i) := d(ip) + c(ip,i)
pred(i) := ip
Gehe zu Schritt (2)
20
Im Algorithmus stellt d(i) die Kosten des kürzesten Diwegs vom Startknoten s zum
Knoten i dar.
T(i) sind aber vorläufige Werte für die Kosten des Diwegs von s nach i. Die Werte T(i)
werden in jeder Iteration aktualisiert. In jeder Iteration p aktualisiert man für jedes
i Є V \ Xp den Wert von T(i).
Die Bezeichnung pred(i) liefert den Vorgänger von Knoten i in Psi .
Da die Kardinalität |Xp| von Xp in jeder Iteration um 1 größer wird, gibt es maximal n-1
Iterationen.
Wir verwenden jetzt den in Abbildung 4 dargestellten Graph, um die kürzesten Diwege
von s = v1 nach vi, i = 2,…,6
mit dem Dijkstra-Algorithmus zu bestimmen. Die
Kantenbewertungen sind die Kosten c(e).
Abbildung 4-1: Graph
Abbildung 4-2: Schritte des Algorithmus
21
Man kann den Dijkstra-Algorithmus durch eine Tabelle übersichtlicher darstellen. Die
Tabelle in Abbildung 4-2 ist eine solche Tabelle, wobei der im Schritt (2) des
Algorithmus gefundene Knoten ip+1 jeweils eingerahmt.
Wenn man die Markierungen pred(i) zurückverfolgt erhält man die kürzesten Diwege
Psi.
4.2 Einsatz von Dijkstra bei der Wegberechnung
Abbildung 4-3: Beispiel für Wegberechnung
Betrachten wir jetzt den Plan und die Graphdarstellung in Abbildung 4-3. Stellen wir
uns vor, dass Robertino vor der Eingangstür auf dem Startknoten (0) steht. Wir wollen,
dass Robertino uns den Weg zum Knoten (4) zeigt. Man sieht, dass es zum Knoten
(4) zwei mögliche Wege gibt, entweder durch den Raum 1 oder durch den Floor.
Robertino führt zuerst den Dijkstra-Algorithmus mit dem Knoten (0) als Startknoten
aus. Der Algorithmus greift auf die Abstandsmatrix zu und liefert als Ergebnis eine
Tabelle, die alle die nötigen Informationen zur Ermittlung der kürzesten Wege zu allen
anderen Knoten enthält. Wie diese Tabelle in unserem Beispiel aussieht, zeigt die
Abbildung 4-4.
Zielknoten
Vorgänger
1
0
2
1
3
2
4
3
5
6
6
7
7
8
8
1
Abbildung 4-4: Dijkstra-Ergebnis
Robertino braucht aber nur den Weg zum Knoten (4). Er sucht in der Tabelle den
Eintrag 4 und erhält durch Zurückverfolgung der Vorgänger vom Knoten (4) den
kürzesten Weg zu seinem Ziel:
22
[Ziel = 4]  [Vorg(4) = 3]  [Vorg(3) = 2]  [Vorg(2) = 1]  [Vorg(1) = 0]
Robertino weiß jetzt, dass er die Kanten [0,1], [1,2], [2,3], und dann am Ende [3,4]
fahren soll, um die Position 4 zu erreichen. Er greift auf die Abstandsmatrix zu und
ermittelt die benötigten Kantenkosten (die Abstände zwischen den Knoten). Er findet
danach die benötigten Winkel heraus und beginnt mit seiner Fahrt. Nachdem
Robertino den Knoten (4) erreicht hat, kann er auch zu einem anderen Knoten
weiterfahren. Er kann zum Beispiel zum Knoten (0) zurückfahren. Er muss nur den
Dijkstra-Algorithmus mit dem aktuellen Knoten als Startknoten ausführen.
23
5. Nachrichtenübertragung
5.1 Abbildung Kommandos/Nachrichten
Leider versteht Robertino Kommandos wie GO [3560]; TURN [-90]; GO[690] gar nicht.
Deswegen müssen wir diese Befehle in Nachrichten umwandeln, die Robertino
verstehen kann.
Man braucht eine Abbildung, die solche Kommandos in eine Reihe von Nachrichten
derart 24##omega(0),vx(100),vy(0) umwandelt.
?##omega(?),vx(?),vy(?)#
?##omega(?),vx(?),vy(?)#
?##omega(?),vx(?),vy(?)#
………………………????
GO [200];
TURN [90];
……….
Notebook:
Client
Robertino:
Server
Abbildung 5-1: Abbildung Kommandos / Nachrichten
Was passiert, wenn Robertino nur eine Nachricht vom Typ L##omega(a),vx(b),vy(c)
an seinem Serversocket empfängt?
Diese Nachricht macht keine Aussagen über die Distanz, die Robertino fahren muss.
Sie zeigt nur, in welche Richtung und wie schnell Robertino sich bewegen muss.
Wie kann Robertino also unter Verwendung dieser Nachrichten eine bestimmte
Distanz d fahren?
Beim Empfang einer solchen Nachricht bewegt sich Robertino tatsächlich um eine
kleine Distanz n und wenn er keine weiteren Nachrichten empfängt, dann stoppt er.
Je größer die Geschwindigkeit ist, desto größer ist diese Distanz n.
24
Natürlich bewegt sich Robertino auf einem glatten Boden schneller als auf dem
Teppichboden des Lehrstuhls. Diese Distanz n hängt also auch vom Widersand des
Bodens ab, auf dem Robertino fährt.
Ein Paar Messungen auf dem Teppichboden des Lehrstuhls haben folgendes
ergeben:
Geschwindigkeit 10
(mm/s)
Gefahrene
5
Distanz n (mm)
20
30
40
50
70
100
150
160
170
180
200
10
15
20
31
43
62
93
101
108
116
124
Abbildung 5-2: Messwerte
Die Distanz n wächst also linear proportional zur Geschwindigkeit. Jetzt kann man
berechnen, wie oft die Nachricht geschickt werden muss um eine bestimmte Distanz d
fahren zu können.
Sei: d zu fahrende Distanz auf der x-Achse, X die verwendete Geschwindigkeit.
Gesucht: Anzahl m der notwendigen Nachrichten vom Typ: L##omega(0),vx(X),vy(0)
Zuerst sucht man n die gefahrene Distanz pro Nachricht unter Berücksichtigung der
verwendeten Geschwindigkeit.
n = 62 mm für X=100 mm/s
und m = d/n
Man braucht also eine Schleife, die die Nachricht an Robertino m-mal schickt, damit er
die Distanz d korrekt fährt.
5.2 Implementierung der Abbildung in Java
1
500
2
Kürzester Weg zum Knoten 2:
GO[500]
Abbildung 5-3: Beispiel
Betrachten wir hier das einfache Beispiel aus der Abbildung 5-3, um die
Implementierung leichter verstehen zu können.
25
Robertino muss also 500 mm vom Knoten 1 zum Knoten 2 fahren. Wir legen die
Geschwindigkeit auf 50 mm/s fest.
Die Klasse Show_the_way verfügt über eine Methode goDistance die den Befehl
GO[500] auf eine Folge von Nachrichten abbildet.
public void goDistance (int sp , int distance ) {
setOmega(0);
setSpeed(sp);
int dist_l = loopToDistance();
int loops = numberOfLoops(distance, dist_l);
send(loops);
}
public int loopToDistance () {
int distance = (speed*62)/100 ;
return distance;
}
Als Parameter bekommt diese Methode die Geschwindigkeit sp (hier 50) und die zu
fahrende Distanz distance (hier 500).
Zuerst wird mit dem Methodenaufruf setOmega(0) die Winkelgeschwindigkeit omega
auf null gesetzt. Mit setSpeed(sp) wird die Geschwindigkeit vx auf 50 mm/s gesetzt.
Die Methode loopToDistance() berechnet die gefahrene Distanz pro gesendeter
Nachricht. Die Variable dist_l enthält also die berechnete Distanz. Für die
Geschwindigkeit 50 mm/s ist die gefahrene Distanz 31 mm.
Der Methodenaufruf numberOfLoops(distance,dist_l) berechnet, wie oft muss die
Nachricht geschickt werden. Die Variable loops enthält die Anzahl der Nachrichten. In
unserem Beispiel muss die Nachricht 500/31 = 16,12-mal geschickt werden. Unser
Ergebnis loops muss aber eine natürliche Zahl sein. Die Nachricht kann nicht 16,12mal geschickt werden. Die Nachricht nur 16-mal zu schicken, ist auch keine Lösung.
Für loops = 16 würde Robertino nur 16x31= 496 mm fahren. Er muss aber 500 mm
fahren und keine 496 mm.
Diese 4 mm Unterschied sind nicht vernachlässigbar. Mit dem Auftreten weiterer
Präzisionsfehler auf weiteren Teilstrecken könnte Robertino sogar ein Paar Zentimeter
vor dem ursprünglichen Ziel anhalten.
26
Frage: Wie kann man Robertino präziser steuern?
Je langsamer Robertino fährt, desto präziser kann er fahren. Bei einer hohen
Geschwindigkeit ist die Teilstrecke, die der Roboter als Reaktion auf eine empfangene
Nachricht fährt, ziemlich lang (200mm/s  124mm). Bei kleineren Geschwindigkeiten
sind die Teilstrecken kürzer (10mm/s  5mm) und der Roboter lässt sich deswegen
präziser fahren. Die gesamte Strecke mit einer Geschwindigkeit von 10mm/s zu
fahren wäre aber zu langsam für unsere Anwendung. Man muss hier einen
Kompromiss zwischen Präzision und Schnelligkeit finden. Wir lassen Robertino am
Anfang schnell fahren, am Ende seiner Fahrt muss er aber langsamer fahren.
In unserem Beispiel schicken wir z.B. am Anfang 15-mal die Nachricht mit Vx=50.
Robertino fährt also 15*31= 465 mm.
Noch zu fahren sind 500-465 = 35mm. Jetzt kann man die Geschwindigkeit 10mm/s
verwenden. Eine Nachricht mit vx = 10 bewegt Robertino um 5mm. 35/5 = 7-mal muss
man die Nachricht schicken um die letzten 35mm fahren zu können. Mit diesem
Ansatz fährt Robertino genau 500 mm und keine 496 mm.
Die Klasse Show_the_way verfügt auch über die Methode
public void send (int loops) {
for (int i=0 ; i<loops ; i++){
String message = "omega(" + getOmega() + "),vx(" + getSpeed() + "),vy(" + 0 + ")#";
message = message.length() + "##" + message;
char[] messageChars = message.toCharArray();
try {
if (i==0) { System.out.println(message);}
out.writeBytes(message);
out.flush();
Thread.sleep(600);
} catch (Exception e) {
e.printStackTrace();
break;
}
}
}
Diese Methode erzeugt die benötigte Nachricht:
String message = "omega(" + getOmega() + "),vx(" + getSpeed() + "),vy(" + 0 + ")#";
message = message.length() + "##" + message;
char[] messageChars = message.toCharArray();
27
und schreibt sie dann auf dem Clientsocket:
out.writeBytes(message);
out.flush();
Natürlich muss man eine bestimmte Zeit warten, bis Robertino eine Nachricht
bearbeitet hat. Für die Bearbeitung einer Nachricht benötigt Robertino z.B. für eine
Geschwindigkeit von 50mm/s  31/50 s = 0,61s = 600 ms.
Das heißt man darf ihn nicht mit Nachrichten überfluten, sondern muss diese
bestimmte Latenz respektieren. Weil er beim Empfang einer Nachricht eine kurze
Strecke fährt und stoppt, muss die nächste Nachricht am besten genau dann
eintreffen, wenn Robertino stoppt.
Analog zur Methode goDistance gibt es die Methode turn, die den Befehl [Turn 90]
auf eine Folge von Nachrichten abbildet.
5.3 Ablaufsbeispiel
Abbildung 5-4: Ablaufsbeispiel
28
In der Abbildung 5-4 steht Robertino am Anfang auf Position 1. Er muss die
Teilstrecke bis Position 2 fahren. Nach der Durchführung der Berechnungen muss die
Nachricht genau 3-mal geschickt werden, damit Robertino die gesamte Strecke fährt.
Robertino reagiert auf die erste Nachricht und fährt einen Teil der Teilstrecke. Sobald
er anhält, empfängt er die zweite Nachricht und fährt den zweiten Teil der Teilstrecke
weiter. Die kleinen Pausen, die Robertino zwischen den Teilfahrten macht, kann der
Benutzer nicht bemerken, weil ihre Dauer in Millisekundenbereich liegt.
29
6. Fehlererkennung und Korrekturverfahren
In diesem Kapitel werden zwei Probleme behandelt. Zuerst: wie kann Robertino
erkennen, dass es ein Hindernis auf dem Weg gibt? Zweitens: wie kann er eine
mögliche Wegabweichung entdecken? Es werden auch Korrekturansätze für beide
Problemsituationen vorgeschlagen.
6.1 Erkennung von Hindernissen
Wie in Kapitel 2 erwähnt wurde, verfügt Robertino über mehrere Sensoren, die es ihm
ermöglichen Distanzen zu den möglichen Hindernissen zu messen.
Abbildung 6-1: Robertino entdeckt ein Hindernis
Das Erkennungsverfahren hier ist ganz einfach. Die Abbildung oben zeigt ein
Hindernis auf dem Weg von Robertino von Knoten 1 nach 4. Robertino hat zwei
vordere Sensoren, mit denen er ständig die Distanzen zu den möglichen Hindernissen
auf der Strecke berechnen kann. Stellen uns wir vor, dass es nur einen Sensor vorne
gibt und nennen wir diesen Sensor S. Sei a der vom Sensor S zu einem bestimmten
Zeitpunkt t gelieferte Wert. a ist demzufolge der Abstand zum Hindernis auf der
Strecke (1,4). Während Robertino von 1 nach 4 fährt muss er parallel und nach einem
konstanten Zeitabstand die Werte a abfragen. Sobald a kleiner als ein kritischer
Abstand k (a < k) wird, ist ein Hindernis auf dem Weg entdeckt. Die Frage lautet jetzt:
30
wie kommt Robertino von Knoten 1 nach 4, ohne dass irgendjemand das Hindernis
entfernt?
6.2 Korrekturverfahren bei Hindernissen
Um das Korrekturverfahren besser zu verstehen, betrachten wir die Abbildung 6-2.
Auf der Teilstrecke [3,4] befindet sich ein Hindernis und Robertino muss aber den
Knoten 4 erreichten.
Abbildung 6-2: Korrektur bei Hindernissen
Robertino kann Knoten 4 erreichten, indem er einen geeigneten Umweg findet. Die
folgenden Schritte soll er dazu durchgehen:
1. Er muss den Abstand x zum letzten erreichten Knoten (im Beispiel Knoten 1)
berechnen. Das ist möglich wenn man eine Variable verwendet, die auf 0 gesetzt wird
wenn der Roboter einen Knoten erreicht und immer aktualisiert wird, wenn Robertino
die nächste Teilstrecke fährt.
2. Robertino muss den Abstand x bis zum Knoten 1 zurückfahren.
3. In Knoten 1 wird das Programm neu gestartet: Die Kosten der Kante mit dem
Hindernis werden auf unendlich gesetzt. Der Dijkstra-Algorithmus wird erneut
31
ausgeführt, nun aber mit dem Knoten 1 als Startknoten. Der kürzeste Weg von Knoten
1 nach 4 ist jetzt der Pfad (1,2,3,4).
6.3 Erkennung von Abweichungen
Wegen Mängel in der Mechanik, kann Robertino aus seinem Weg abweichen.
Deswegen werden die Mauswerte des Moused-Dämons ständig kontrolliert, um eine
mögliche Abweichung frühzeitig zu entdecken. Die Abbildung 6-3 zeigt uns ein
Beispiel.
Abbildung 6-3: Abweichung
Die Punkte (x,y) sind die gelieferten Mauswerte. Robertino sollte die Teilstrecke [2-3]
fahren, ist aber in die Richtung R gerutscht. Wie kann man also die Mauswerte (x,y)
benutzen, um diese Abweichung zu entdecken. Die schmalen grauen Rechtecke in
Abbildung 6-3 zeigen den Toleranzbereich der (x,y)-Werte. Die x-Werte sollen in dem
Intervall [-d,d] liegen. Wenn sie diesen Bereicht verlassen, wird eine mögliche
Abweichung entdeckt. Die y-Werte sollen bei der erwarteten gefahrenen Distanz
liegen. Sie sollen deswegen in dem Intervall [ye-f,ye+f] liegen. ye ist die erwartete
gefahrene Distanz und f ist eine Fehlertoleranzkonstante. Wenn sie diesen Bereicht
verlassen, wird auch eine mögliche Abweichung entdeckt.
32
Man soll aber nicht sofort mit der Korrektur anfangen, wenn die Mauswerte zum ersten
Mal den Toleranzbereich verlassen. Es wird erstmals abgewartet, bis eine Menge von
fehlerhaften (x,y)-Werten vorliegt. Mit einem einzigen Wert hat man keine Chance,
den Abweichungswinkel abzuschätzen. Wir speichern deswegen diese Menge
fehlerhafter
Messwerte
in
einer
Tabelle
und
versuchen
daraus
den
Abweichungswinkel abzuschätzen. Zuerst sollen wir aber die Anzahl der Elemente
dieser Menge festlegen. Die Größe der Fehlertabelle entspricht dann der
Elementenanzahl dieser Menge. Nach und nach wird die Tabelle mit den fehlerhaften
Werten ausgefüllt. Erst wenn die Tabelle voll mit Messwerten ist, kann man davon
ausgehen, dass eine Abweichung vorliegt. Das Hauptprogramm wird dann
unterbrochen und das Korrekturverfahren wird gestartet.
6.4 Korrekturverfahren bei Abweichungen
Diese Abweichungen und Positionen können nur mit einem statistischen Fehler
gemessen werden. Das Verfahren der linearen Regression berechnet für die
(x,y)-Messwerte eine Regressionsgerade, die dieses Rauschen ausgleicht und uns
eine gute Abschätzung des Abweichungswinkels zur Verfügung stellt.
6.4.1 Lineare Regression
Die Lineare Regression löst die folgende Standardaufgabe:
Gegeben: Paare von Messdaten (xi,yi), i=1,…,n geometrisch eine Punktwolke in der
Ebene. xi und yi können dabei durchaus mehrfach auftreten. Zu gegebenem xi können
mehrere Messwerte yi1,…,yip vorliegen.
Aufgabe: ein lineares Modell y = ß0 + ß1x an die Messdaten anzupassen, also eine
beste gerade durch die Punktwolke zu legen.
Wie bildet man hier das Modell des Regressionsansatzes? Das gesuchte Modell für
den Zusammenhang zwischen x und y ist das lineare Modell y = ß0 + ß1x mit
unbekannten Koeffizienten ß0 und ß1.
Die vorliegenden Messdaten liegen jedoch nicht exakt auf der entsprechenden
Gerade, sondern zeigen Abweichungen εi, i = 1,..,n (Abbildung 6-4):
yi = ß0 + ß1xi + εi
33
Um aus den vorliegenden Daten Schätzwerte ß’0, ß’1 für ß0, ß1 zu gewinnen,
minimieren wir die Summe der Fehlerquadrate:
sodass also ß’0, ß’1 Lösung des Minimierungsproblems :
ist.
Wir wollen hier aber nicht detailliert vorführen, wie man die Schätzwerte ß’0, ß’1 erhält.
Der ausführliche Berechnungsvorgang gibt es in der Literatur [Li00].
Das Ergebnis der Regression ist demzufolge die geschätzte Regressionsgerade
y = ß’0 + ß’1x . Die durch das Modell prognostizierten Werte sind dann y’i = ß’0 + ß’1xi.
Abbildung 6-4: Abweichung εi [Li00]
34
6.4.2 Korrekturverfahren
Abbildung 6-5 : Korrekturverfahren bei Abweichungen
Die Abbildung 6-5 stellt eine mögliche Abweichungssituation dar. Auf der Teilstrecke
[1,2] weicht Robertino ab und bewegt sich in die Richtung R. Nach der Erkennung
einer Abweichung befindet sich der Roboter auf der dem Punkt (x,y).
Das Korrekturverfahren besteht in diesem Fall aus den folgenden Schritten:
1. Die Regressionsgerade R aus der in Kapitel 6.3 beschriebenen Fehlertabelle
bestimmen.
2. Ermittlung des Winkels α:





(x,y) aus der Fehlertabelle ermitteln (letzter Eintrag)
b = z - y ( z = Länge der Teilstrecke [1,2] )
δ = cotan(b/x)
φ = cotan(k) ( k = Koeffizient der Regressionsgerade )
α = 180 - δ - φ
35
3. Ermittlung des Abstands d

d2 = b2 + x2
4. Ermittlung des Winkels β

β = 90 - δ
5. Zum Knoten 2 fahren : Turn[α] & Go[d] & Turn[β]
6. In Knoten 2 Dijkstra-Algorithmus mit dem Startknoten 2 ausführen.
7. Zum Zielknoten weiterfahren.
Die vollständige Implementierung dieses Verfahrens ist im Anhang B zu finden.
36
7. Architektur und Zusammenspiel der in Java
implementierten Komponenten
7.1 Einführung in UML (Unified Modelling Language)
UML ist eine Sprache und Notation zur Spezifikation, Konstruktion, Visualisierung und
Dokumentation von Modellen für Softwaresysteme. Diese Sprache bietet zahlreiche
interessante Modellierungsdiagramme an. Um die im Rahmen dieser Studienarbeit
entwickelte Software zu beschreiben, habe ich mich für Klassendiagramme,
Aktivitätsdiagramme und Sequenzdiagramme entschieden.
7.1.1 UML-Klassendiagramm
Die Abbildung 7-1 zeigt ein UML-Klassendiagramm. Ein Klasse im Klassendiagramm
besteht aus drei Blöcken. Der Block klasse enthält den Klassennamen (z.B.
Klassenbezeichner einer Java-Klasse). Unter Attribute werden die Attribute der Klasse
aufgelistet. Der untere Block Operationen enthält eine Liste der Klassenmethoden.
Syntax für Attribute:
Sichtbarkeit Attributname
Syntax für Operationen: Sichtbarkeit Operationsname (Parameterliste): Rückgabewert
Sichtbarkeit:
+ (public) - (private) # (protected)
Die Pfeile in der Abbildung 7-1 modellieren mögliche Relationen zwischen den
Klassen. Eine Klasse kann z.B. aus einer anderen klasse abgeleitet werden oder ein
Interface implementieren.
Abbildung 7-1: UML-Klassendiagramm
37
7.1.2 UML-Sequenzdiagramme
Man verwendet Klassendiagramme, um statische Informationen darzustellen. Jedoch
interagieren die Objekte in einem funktionierenden System miteinander. Diese
Interaktionen ziehen sich über einen Zeitraum hin. Das UML-Sequenzdiagramm zeigt
die zeitliche Dynamik der Interaktion.
Abbildung 7-2: UML-Sequenzdiagramm
Die Abbildung 7-2 ist ein UML-Sequenzdiagramm. Die Objekte werden in einem
Sequenzdiagramm oben von links nach rechts angeordnet. Von jedem Objekt geht
eine gestrichelte Linie nach unten, die man als Lebenslinie des Objektes bezeichnet.
An der Lebenslinie befindet sich ein schmales Rechteck, die so genannte Aktivierung.
Die Aktivierung repräsentiert die Ausführung einer Operation durch das Objekt. Ein
Pfeil verbindet eine Lebenslinie mit einer anderen und modelliert eine Nachricht, die
ein Objekt einem anderen sendet. Die Zeitdauer beginnt oben und schreitet nach
unten fort. Eine kompakte und einfache Beschreibung der Sequenzdiagramme gibt es
in [Js00].
7.1.3 UML-Aktivitätsdiagramme
Die UML-Aktivitätsdiagramme eignen sich zur Modellierung von Abläufen aller Art,
unabhängig vom Anwendungsbereich. Sie werden beispielsweise zur Modellierung
von
Programmabläufen,
technischen
Prozessabläufen
oder
Arbeitsabläufen
verwendet.
Ein Rechteck mit gerundeten Ecken stellt eine Aktivität dar. Sobald die Verarbeitung
innerhalb einer Aktivität beendet ist, geht sie auf die nächste Aktivität über. Der
38
Übergang von einer Aktivität zur nächsten wird durch einen Pfeil repräsentiert. Das
Aktivitätsdiagramm besitzt einen Anfangspunkt in Form eines
schwarz gefüllten
Kreises und einen Endpunkt in Form eines Ochsenauges.
Ein Entscheidungsknoten wird durch eine Raute dargestellt und stellt eine
Verzweigung dar. Eine Verzweigung hat einen Eingang und zwei oder mehrere
Ausgänge. Jeder Ausgang wird mit einer Bedingung versehen. Trifft eine Bedingung
zu, wird der entsprechende Ausgang ausgewählt und an diesem weitergearbeitet.
Zur Darstellung von Nebenläufigen Pfaden werden Parallelisierungsknoten eingesetzt.
Ein Parallelisierungsknoten ist ein Balken mit einem Eingang und zwei oder mehreren
Ausgängen dargestellt und dient zum Aufspalten eines Ablaufs in zwei oder mehrere
parallele Abläufe. (Abbildung 7-3)
Um die parallelen Abläufe zusammenzuführen werden Synchronisationsknoten
eingesetzt. Synchronisationsknoten sind Balken mit mehreren Eingängen und einem
Ausgang. An diesem Knoten findet eine Synchronisation statt, d.h., es wird gewartet,
bis alle eingehenden Abläufe eintreffen, dann geht der Ablauf an diesem Punkt weiter.
Abbildung 7-3
7.2 Überblick auf die Klassenarchitektur
Die Abbildung 7-4 zeigt ein UML-Klassendiagramm. Dieses Diagramm bietet eine
Darstellung der verschiedenen Klassen an, die im Rahmen dieser Studienarbeit
implementiert worden sind. Die wichtigsten Klassen werden in den nächsten
Abschnitten genauer untersucht.
39
Abbildung 7.4: Klassendiagramm (Teil 1)
40
Abbildung 7.4: Klassendiagramm (Teil 2)
7.3 Die Klasse Plan
Diese Klasse modelliert einen beliebigen Plan als Graph mit Knoten und Kanten. In
einem 2-dimentionalen Feld int[ ][ ] costMatrix werden die Abstände zwischen den
verschiedenen Knoten gespeichert. Die Größe dieses Felds ist gleich der Anzahl der
Knoten im Graph. Ein Eintrag in diesem Feld z.B. costMatrix [1][2] = 5 entspricht dem
41
Abstand zwischen den Knoten 1 und 2. Wenn es zwischen zwei bestimmten Knoten
keine Kante existiert, z.B. zwischen den Knoten 1 und 4, wird der Abstand zwischen
diesen Knoten auf unendlich gesetzt (z.B. costMatrix [1][4] = INFINIT und INFINIT
sehr groß).
Zur Darstellung der Winkel zwischen den Kanten verfügt die Klasse Plan über ein
3-
dimentionales Feld int [ ][ ][ ] angles. Ein Eintrag in diesem Feld z.B. angles [1][2][3] =
90 entspricht dem Winkel zwischen den Kanten [1,2] und [2,3].
Die wichtigste Methode der Klasse Plan ist die Methode int[ ] dij (int from). Diese
Methode führt den Dijkstra-Algorithmus aus und liefert ein Feld zurück, der jedem
Knoten einen Vorgänger zuweist. Nennen wir dieses Feld Priorfeld. Dieses enthält
implizit die notwendigen Informationen, um die kürzesten Pfade vom Knoten from zu
allen anderen Knoten zu ermitteln.
Die Methode int [ ] getNodes (int from, int to) extrahiert aus dem Feld Priorfeld die
Folge der Knoten auf dem kürzestem weg vom Knoten „from“ zum Knoten „to“ und
speichert diese Folge in einem Feld. Nennen wir dieses Feld path.
Die Methode void getDistances (int[ ] path) zerlegt das Feld path in Teilstrecken
(Kanten), greift auf costMatrix zu, um die Abstände (die Kosten der Kanten) zu
ermitteln. Diese Abstände werden nach der Erscheinungsreihenfolge der zugehörigen
Kanten auf path in einem neuen Feld gespeichert. Nennen wir dieses Feld dist.
Die Methode int [ ] getAngles (int [ ] path) verwendet die Knoten im Feld path und die
Einträge im 3-D-Feld angles um die Folge der notwendigen Winkel auf dem Weg zum
Ziel zu ermitteln. Diese Folge wird auch in einem Feld gespeichert. Nennen wir dieses
Feld angle. Aus den zwei oben genanten Feldern dist und angle erzeugt die Methode
String makePath (int [ ] dist, int [ ] angle) eine Zeichenkette, die die notwendigen
Roboterbewegungen zum Zielknoten zusammenfasst. Ein Beispiel für diese
Zeichenketten ist GO[50] & TURN[90] & GO[100].
7.4 Die Klasse Show_the_way
Diese Klasse ist die wichtigste Klasse der Anwendung. Sie enthält die main-Methode
und verfügt über weitere Methoden zur Roboterteuerung. Diese Klasse verfügt auch
über Klassenvariablen, die den Roboterzustand beschreiben.
Die Methode void setSpeed (int sp) setzt die Geschwindigkeit des Roboters auf sp
mm/s und die Methode void setOmega (int omg) setzt die Winkelgeschwindigkeit auf
omg mdeg/s.
42
Wenn der Roboter sich in einer Position (x) auf der Teilstrecke zwischen zwei
verschiedenen Endknoten (a) und (b) befindet, kann man mit den Methoden
int getLastNode() bzw. int getNextNode() ermitteln, welcher Knoten zuletzt besucht
wurde (a) bzw. welcher Knoten demnächst erreicht (b) wird. Die Methode int
getdrivedDistance() liefert in diesem Fall die Länge der Gefahrenen Strecke vom
zuletzt besuchten Knoten (a) zur aktuellen Position des Roboter auf der Teilstrecke
(x).
Die wichtigste Methode ist aber die Methode void drive (int start, int goal, Plan plan).
Anhang A zeigt die komplette Implementierung dieser Methode. Diese Methode sorgt
dafür, dass der Roboter von einem beliebigen Startknoten start den Zielknoten goal
erreicht. Das erfolgt natürlich unter Verwendung von Informationen der Instanz plan
der Klasse Plan. Die Realisierung der einzelnen Teilaufgaben der drive-Methode
erfolgt mit den Methoden void goDistance (int sp , int distance), void turn (int omega,
int angle), void send (int loops). Diese drei genanten Methoden und weitere
Hilfsmethoden wurden schon in einem früheren Kapitel genauer untersucht (siehe
5.2).
Bei Fehlersituationen werden die Methoden void setObstacle (boolean value) bzw.
void setDeviation (boolean value) verwendet um den Roboter in den Zustand
„Hindernis erkannt = true“ bzw. „Abweichung = true“ zu versetzen.
7.5 Die Klassen Client, DriveDClient und MouseDClient
Die Klasse Client ist ein einfacher TCP-Client mit einem TCP-Socket und zwei Ströme
DataInputStream und DataOutputStream.
Die Methode boolean connect (String hostname, int port , int timeout ) baut eine TCPVerbindung zum Host hostname zur Portnummer port auf. Die Methode void
disconnect() baut diese Verbindung nach der Nachrichtenübertragung ab.
Aus der Klasse Client werden die zwei Klassen DriveDClient und MouseDClient
abgeleitet. Beide Klassen besitzen einen Input-Thread, der für die eintreffenden
Nachrichten zuständig ist. Dieser Thread wird mit dem Aufruf der Methode void
receive() gestartet. Der Input-Thread der Klasse DriveDClient z.B. empfängt die
Nachrichten mit den Sensorwerten, die der DriveDServer sendet. Dieser Input-Thread
ist vom Typ ClientInputThread. Diese Klasse wird im kommenden Abschnitt
untersucht.
43
7.6 Die Klassen ClientInputThread und MouseClientInputThread
Die Klasse ClientInputThread ist ein Thread zum Empfang der Nachrichten des
DriveDServers und die Extraktion der relevanten Werte. Wenn die Methode void run()
gestartet wird liest sie die Nachricht aus dem DataInputStream, speichert die
Nachricht in einer Variable received und ruft die Methode boolean extract (String
received).
Die extract-Methode kann die für diese Studienarbeit relevanten Daten aus einer
Nachricht der Form 99##ADC00(9),ADC01(5),...,va2(5)# extrahieren. Relevant sind in
diesem Fall die Sensorwerte ADC12 und ADC50 auf der vorderen Seite des Roboters.
Nach der Extraktion kann man mit den Methoden int get_adc12() und int get_adc50()
beide Sensorwerte abfragen.
Die Klasse MouseClientInputThread ist der Klasse ClientInputThread sehr ähnlich.
Anstatt
Sensorwerte
zu
empfangen,
empfängt
sie
Mauswerte
aus
dem
MouseDServer.
7.8 Die Klasse Controller
Diese Klasse wird aus der Klasse Thread abgeleitet. Sie versucht eine fehlerfreie
Fahrt des Roboters zu gewährleisten.
Ihre Methode void run() enthält eine endlose Schleife. Jede von diesen Schleifen
besteht aus zwei verschieden Phasen. Der ControllerThread schläft während der
ersten Phase und ist nicht aktiv. Diese Schlafphase ist periodisch und dauert jedes
Mal controll_frequency Millisekunden. Der ControllerThread ist danach wieder aktiv
und die Kontrollphase beginnt.
Die Kontrollphase besteht aus drei Methodenaufrufen. Mit der Methode void
collectValues() werden alle Kontrolldaten zum gleichen Zeitpunkt abgefragt. Diese
Kontrolldaten sind die Sensorwerte ADC12 und ADC50 aus dem ClientInputThread
und die Mauswerte X und Y aus dem MouseClientInputThread. Die Methode boolean
sensorValues_OK() überprüft, ob einer der Sensorwerte unter dem kritischen Abstand
critical_distance
liegt. Wenn das der Fall ist, wird ein Hindernis entdeckt. Dann
überprüft die Methode boolean mouseValues_OK(), ob die Mauswerte in einem
Toleranzbereich liegen oder nicht. Wenn mehrere aufeinander folgende Mauswerte
(X,Y) den Toleranzbereich nicht respektieren, werden sie in dem Feld int
mouseCriticalValues [ ][ ] gespeichert. Dieses Feld hat eine begrenzte Größe. Sobald
dieses Feld voll mit fehlerhaften (X,Y) Einträge ist, hat man eine potenzielle
Abweichung entdeckt.
44
7.9 Die Klasse ObtacleDetected
Diese Klasse implementiert das Interface ErrorClass. Die Methode void correct
(Show_the_way way, Plan plan, int goal) dieser Klasse wird verwendet, wenn ein
Hindernis entdeckt wird. Sie implementiert das in Kapitel 6.2 beschriebene
Korrekturverfahren.
Die Methode void informTheVisitor() informiert den Benutzer, dass ein Hindernis
entdeckt wurde und, dass ein Umweg gesucht wird.
7.10 Die Klassen Deviation und Regression
Diese Klasse implementiert auch das Interface ErrorClass. Die Methode void correct
(Show_the_way way, Plan plan, int goal) wird hier aber genutzt, wenn eine
Abweichung entdeckt wird. Sie implementiert das in Kapitel 6.4.2 vorgestellte
Korrekturverfahren. Im Anhang B findet man die Implementierung dieser Methode.
Die Methode void informTheVisitor() informiert den Benutzer, dass eine Abweichung
entdeckt wurde und, dass der Weg Korrigiert wird. Bei der Korrektur wird aber die
Regressionsgerade gesucht.
Die statische Methode double[ ] linear_equation(double rawData[ ][ ], int norder) der
Klasse Regression
berechnet aus den in rawData gespeicherten Messwerten die
geschätzte Regressionsgerade.
45
7.11 Zusammenspiel der Komponenten
Abbildung 7-5: Zusammenspiel der Komponenten
46
Wir haben die verschiedenen Systemkomponenten getrennt beobachtet und ihre
besonderen Funktionalitäten spezifiziert. Doch wie kooperieren diese Komponenten
miteinander, um die globale Funktionalität zu realisieren. In diesem Kapitel wird
anhand zahlreicher Abbildungen das Zusammenspiel der Klassen deutlich gemacht.
Die Abbildung 7-5 ist ein einfaches Schema zur Darstellung des gesamten Systems.
Die Steuerung des Roboters erfolgt auf einem externen Rechner (Notebook). Die
Realisierung der Aufgaben findet aber auf der Seite des Roboters statt. Die
verschiedenen
Clients
und
Servern
kommunizieren
über
ein
W-LAN.
Die Abbildung 7-6 ist ein UML-Sequenzdiagramm. Wir können mit diesem
Sequenzdiagramm ein Ablaufbeispiel genauer untersuchen, um das Zusammenspiel
der im Klassendiagramm dargestellten Java-Klassen besser zu verstehen. Um den
Überblick zu behalten, wurde das Sequenzdiagramm in fünf Teilen zerlegt. Jeder Teil
ist mit einer Buschstabe versehen. Wir erklären hier kurz was bei jedem Teil passiert.
Teil A:
Der Benutzer startet das Programm und gibt sein Wunschziel an. Show_the_way baut
TCP-Verbindungen zu den verschiedenen Servern auf und startet Controller.
Teil B:
Show_the_way holt sich die nötigen Abstände und Winkel aus Plan und ruft seine
drive-Methode auf.
Teil C:
Show_the_way schickt DriveDServer Nachrichten zu und DriveDServer antwortet mit
Sensorwerten. MouseDServer fängt auch an Mauswerte zu senden. Robertino beginnt
seine Fahrt.
Teil D:
Controller sammelt aus den Clients DriveDClient und MouseDClient Mauswerte und
Sensorwerte.
Teil E:
Controller entdeckt ein Hindernis und informiert Show_the_way. Show_the_way ruft
die correct-Methode von ObsatcleDetected auf. ObstacleDetected führt die Korrektur
durch und ruft die drive-Methode von Show_the_way rekursiv auf. Schließlich
übernimmt Show_the_way erneut die Robotersteuerung.
47
Abbildung 7-6 : Sequenzdiagramm (Teil 1)
48
Abbildung 7-6 : Sequenzdiagramm (Teil 2)
49
Am Ende fassen wir die verschiedenen Aktivitäten in einem Aktivitätsdiagramm
zusammen (Abbildung 7-7).
Abbildung 7-7: Aktivitätsdiagramm
50
8. Tests und Ergebnisse
Test 1:
Robertino soll von
einem Startknoten
zu einem Zielknoten
fahren. Er soll den
Dijkstra-Algorithmus
ausführen und den
kürzesten weg zum
Ziel auswählen.
Dieser Test wurde
nicht simuliert
sondern tatsächlich
mit Robertino
durchgeführt.
Betroffene Klassen:
Client
ClientInputThread
DriveDClient
Plan
Show_the_way
Ergebnisse:
Robertino wählt
immer den richtigen
kürzesten Weg zum
Zielknoten. Mit
einigen
Präzisionsfehlern
erreicht er sein Ziel.
Probleme:
Die Räder des
Roboters lassen
sich nicht präziser
steuern. Der
Roboter hält
meistens vor
seinem Ziel an.
Hardwaremängel:
Die Akkus des
Roboters sind
leider nicht mehr
funktionsfähig.
Test 2:
Robertino soll ein
Hindernis
entdecken und
seinen Weg
korrigieren. Dieser
Test wird nur mit
einem
Dummyserver
simuliert, der
zufällige
Sensorwerte liefert.
Betroffene Klassen:
Client
ClientInputThread
DriveDClient
Plan
Show_the_way
Controller
ObstacleDetected
DrivedDummyServer
Ergebnisse:
Robertino reagiert
auf virtuelle
Hindernisse,
berechnet korrekte
Umwege und gibt
die
Bearbeitungsschritte
am Bildschirm aus.
Probleme:
Es wäre
angemessener für
diese
Anwendung, dass
es einen Sensor
genau an der
vorderen Seite
des Roboters gibt.
Die Position der
vorderen
Sensoren links
und rechts ist
nicht optimal.
Test 3:
Robertino soll
Abweichungen
erkennen. Das
Verfahren wurde
komplett
implementiert. An
einem
MouseDServer
arbeitet aber eine
Forschungsgruppe.
Betroffene Klassen:
Client
ClientInputThread
DriveDlient
Plan
Show_the_way
Controller
Deviation
Ergebnisse:
Keine Ergebnisse.
Der Test wurde
nicht durchgeführt.
Bei der
Implementierung
ginge ich davon
aus, dass der
MouseDServer
während der Fahrt
(x,y)-Mousewerte
liefert.
Probleme:
Hardwaremängel.
Der Roboter, der
zur Verfügung
stand, besitzt
keine eingebaute
Maus.
51
9. Zusammenfassung / Ausblick
Zum Abschluss können wir die neuen Fähigkeiten von Robertino zusammenfassen.
Robertino kann jetzt selbstständig den Weg zu einem bestimmten Raum fahren. Er
muss zuerst den kürzesten Weg berechnen. Die Modellierung eines Plans erfolgt mit
Graphen. Um den kürzesten Weg zu berechnen, wird der Dijkstra-Algorihtmus
eingesetzt.
Robertino ist auch fähig, Hindernisse zu entdecken. Wenn er ein
Hindernis entdeckt, berechnet er automatisch einen gültigen Umweg und setzt seine
Fahrt auf dem neuen Weg fort. Seine Sensorwerte werden zu diesem Zweck ständig
kontrolliert
und
auf
die
Präsenz
möglicher
Hindernisse
überprüft.
Die
Umwegberechnung erfolgt wieder mit dem Dijkstra-Algorithmus. Eine weitere
Fähigkeit von Robertino ist die Erkennung von Abweichungen. Wenn Robertino aus
irgendeinem Grund rutscht und die Fahrt in die falsche Richtung fortgesetzt wird, dann
kann er diese Fehlersituation selbstständig erkennen. Die Werte einer unten am
Roboter eingebauten Maus werden in diesem Fall kontrolliert und auf Unzulässigkeit
geprüft. Anhand der Mausmesswerte, ermöglicht uns das Verfahren der Linearen
Regression eine Abschätzung des Abweichungswinkels zu gewinnen.
Diese erreichten Fähigkeiten sind Grundfähigkeiten, die man natürlich erweitern
könnte. Er wäre zum Beispiel schön die spontan zu Sprechen, um mit Robertino zu
kommunizieren. „Ich will zu Herrn Müller“, „Zeig mir den Raum 295“ sind zwei
mögliche spontane Befehle, die Robertino verstehen und ausführen sollte. Es wäre
auch schön, wenn Robertino sprechen würde und den Benutzer begrüßen oder über
mögliche Probleme informiert. Hier könnte man Werkzeuge aus dem Gebiet
Musterkennung, wie Sprachsynthese und Spracherkennung einsetzen. Robertino
muss in der Lage sein solche spontane Befehle in Texte umzuwandeln. Danach muss
er aus diesem Text das vom Benutzer verlangte Ziel extrahieren. Dann folgt die
Abbildung des Ziels auf einen Knoten des in Robertino gespeicherten Graphs.
Robertino kann sogar seine Kamera verwenden um sich besser zu orientieren oder
um Objekte des Umfeldes zu klassifizieren. Nach der Analyse der Kamerabilder wird
zum Beispiel entschieden, ob es eine Person im Aufzug gibt. Bei der Erkennung von
Türen, Hindernissen... könnte die Kamera könnte auch helfen. Ein Teilgebiet der
Mustererkennung
widmet
sich
der
Bilderkennung
und
bietet
verschiedene
Bildklassifikatoren an.
Wenn die Einsatzfläche von Robertino ziemlich groß wird (z.B. Flughafen) können wir
sogar mehrere Instanzen von Robertino verwenden, die nur Teilflächen als
Einsatzgebiet haben. Diese Agenten können von einem zentralen Koordinator
52
gesteuert werden, um eine globale Aufgabe zu erfüllen. Auf seinem Weg zu einem
bestimmten Ziel kann ein Benutzer von mehreren Robotern begleitet werden. Jeder
Roboter begleitet aber nur entlang der Teilstrecke die zu seinem Einsatzgebiet gehört.
Dann übernimmt ein anderer Roboter die Begleitung.
Die Intelligenz dieser Roboter hat unser Leben enorm erleichtert. Leider wird diese
Intelligenz aber häufig missbraucht und in Kriegen eingesetzt. Wir lassen uns aber von
diesem Missbrauch nicht aufhalten. Die Forschung geht weiter und die Roboter
werden noch intelligenter.
53
10. Literatur
[Gk04] Handbuch der Java-Programmierung, Guido Krüger (4-Auflage AddisonWesley, 2004)
[Jk02] Computernetze, James F. Kurose , Keith W.Ross (Addison-Wesley,2002)
[Go00] Handbuch der Künstlichen Intelligenz , G. Görz, G.-R. Rollinger, J.
Schneeberger (3-Auflage Oldenbourg, 2000)
[Kla00] Lineare und Netzwerk-Optimierung, Horst. W. Hamacher , Kathrin Klamroth
(Vieweg,2000)
[Js00] Jetzt lerne ich UML, Joseph Schmuller (Markt + Technik, 2000)
[Bo06] Analyse und Design mit UML 2.1, Bernd Oestereich (8-Auflage Oldenburg,
2006)
[Hi96] Landmark-Based Autonomous Navigation in Sewerage Pipes, J. Herzberg und
F. Kirchner, 1996
[La91] Robot Motion Planning, J. Latombe, 1991
[Kh86] Real-time obstacle avoidance for robot manipulator an mobile Robots. The
interanational Journal of Robotic research, 1986.
[Li00] http://www.mathe-online.at/nml/materialien/innsbruck/regression/
Regression.pdf
[Li01] http://www.angelfire.com/tx4/cus/regress/java.html
[Li02] www.openrobertino.org
[Li03] http://www.cs.cmu.edu/afs/cs.cmu.edu/Web/People/Xavier/
[Li04] http://www.deutsches-museumbonn.de/highlights/100jahremuseum/default.html
[Li05] http://idw-online.de/pages/de/image13460
[Li06] http://www.cs.cmu.edu/~minerva/
[Li07] http://www.golem.de/0510/40897.html
54
Anhang A
public void drive( int start, int goal, Plan plan ) {
setObstacle(false);
setDeviation(false);
int[] path = plan.getNodes(start,goal);
plan.getNodes(start,goal);
System.out.println("\n" + "nodes to visit..");
for (int i = 0 ; i < path.length ; i++) { System.out.print(path[i] + "-"); }
System.out.print("OK!");
int[] dist = plan.getDistances(path);
int[] ang = plan.getAngles(path);
String way = plan.makePath(dist,ang);
System.out.println("\n" + "route calculated..\n" + way + "\n");
try {
for (int i = 0 ; i < ang.length ; i++) {
setLastNode(path[i]);
setNextNode(path[i+1]);
goDistance(50,dist[i]);
turn(5000,ang[i]);
System.out.println("Die Strecke " + path[i] + " ------> " + path[i+1] + " + Drehung erfolgreich! ");
}
goDistance(50,dist[dist.length-1]);
System.out.println("Die Strecke " + path[path.length-2] + " ------> " + path[path.length-1] + " erfolgreich gefahren! ");
setNextNode(path[path.length-1]);
} catch (Exception e) {
if (obstacle == true) {
ObstacleDetected obstacle = new ObstacleDetected(controller);
obstacle.informTheVisitor();
try {
obstacle.correct(this, plan, goal);
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (deviation == true) {
Deviation deviation = new Deviation(controller);
deviation.informTheVisitor();
try {
deviation.correct(this, plan, goal);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
55
Anhang B
public void correct(Show_the_way way, Plan plan, int goal) throws Exception {
double[][] criticalValues = controller.getMouseCriticalValues();
double[] coef = Regression.linear_equation(criticalValues,1);
int from = way.getLastNode();
int to = way.getNextNode();
double k = coef[1];
double fi = Math.atan(k);
double fromto = plan.getDist(from,to);
double y = criticalValues[4][0];
double x = criticalValues[4][1];
int sign;
if (x < 0) sign = -1;
else sign = 1;
double b = fromto - y;
double delta = Math.atan(b/x);
double alfa = 180 - (delta + fi);
int alfa_r = (int) Math.round(alfa);
double d = Math.sqrt(b*b + x*x);
int d_r = (int) Math.round(d);
double beta = 90 - delta;
int beta_r = (int) Math.round(beta);
way.turn(5000,sign*alfa_r);
way.goDistance(50,d_r);
way.turn(5000,sign*beta_r);
way.drive(to,goal,plan);
}
Anlage
CD-ROM mit Quellcode.
56
Herunterladen