Projekt: System- und Rechnerarchitektur

Vorbemerkungen

Raum, Hardware und Labor

Im SRA Laborraum gelten die üblichen Regeln für Laborräume: - Essen und Trinken sind im Labor ist verboten. - Die Spielfläche darf nicht mit Schuhen betreten werden. - Euer Betreuer wird euch zu Beginn eurer Laborzeit an einem der Rechner anmelden. - Roboter und Rechner sind pfleglich zu behandeln. Was man zu den Robotern beachten sollte: - Die Betreuer geben die Roboter zu Beginn einer jeden Laborzeit aus und sperren sie am Ende wieder weg - oder auch vorzeitig bei schlechter Behandlung. - Die Software hat ein Notfall-Aus. Durch Drücken von `Strg+C` (im Terminal) könnt ihr euer Programm beenden (auch auf dem Roboter). - Die Roboter dürfen nur auf dem vorgesehenen Feld und im "Laufstall" fahren. - Wenn ihr die Roboter auf dem Tisch abstellt, dann bitte auf den dafür vorgesehenen Ablageflächen (fragt den Tutor) - Sollte ein Fehler auftreten, meldet euch bei eurem Betreuer.

Ziel des Labors

Zu den Programmieraufgaben

Bestehen des Labors

Das Labor ist bestanden, wenn alle Aufgaben im festgelegten Zeitraum erfüllt sind. Dazu gehören:

Git-Repository

Zur Verwaltung eurer Daten nutzt ihr bitte euer git-Repo. Um Zugang dazu zu erhalten, meldet euch bitte auf https://scm.sra.uni-hannover.de:8181/scm/ mit euren Zugangsdaten an. Hier findet ihr unter anderem ein Repo mit dem Namen KheperaStudent-progrp(eure Gruppennummer). Klickt darauf und in der unteren Leiste werden euch Informationen dazu angezeigt. Unter anderem steht dort, mit welchem Befehl in der Konsole/Terminal ihr das Git-Repo clonen könnt. Das könnt ihr auf euren privaten Rechnern auch gern machen, aber auf euren Accounts im Labor ist das bereits geschehen.

Informationen zu den Robotern

Geschwindigkeit

Die Roboter haben eine Minimalgeschwindigkeit von 4000 (ca. 4,4 cm pro Sekunde). Darunter werden die Bewegungen ungenau oder die Räder drehen sich vielleicht gar nicht. Die Maximalgeschwindigkeit liegt bei ca. 30000 (ca. 33,3 cm pro Sekunde).

Bewegungsrichtung

Die Motoren können mit den Befehlen der Klasse 'machine' angesteuert werden. Positive Werte sorgen sinnvollerweise für eine Vorwärtsbewegung. Rückwärts analog. So ist eine Drehung um die eigene Achse also möglich, wenn die Motoren mit betragsmäßig identischen Werten mit unterschiedlichen Vorzeichen angesteuert werden. An dieser Stelle wird davon abgeraten dies bei hoher Geschwindigkeit zu tun, da die Fliehkräfte doch ein wenig zu stark werden. Wir sind uns ziemlich sicher, dass die Geräte nicht dafür konstruiert wurden sich auf dem Rücken zu drehen.

Sensoren

Die Roboter sind mit 11 Sensoren ausgestattet. 9 sind horizontal angebracht und 2 befinden sich auf der Unterseite. Wie gesagt sollen die Bots nicht auf den Tischen fahren, womit die unteren Sensoren für eure Aufgaben nicht zu beachten sind. Ein wichtiger Punkt, den man immer berücksichtigten muss ist, dass die Sensoren nicht absolut identisch sind. Sensor 1 kann auf derselben Distanz andere Werte haben als Sensor 2.

Aufgabe 0 – Erste Schritte - Zeitraum: erster Termin

Startet den QT-Creator (grünes Symbol, Leiste links, Aufschrift "QT"). Drückt nun strg+shift+o um ein Projekt zu laden. Ein Fenster öffnet sich. Geht in das Verzeichnis KheperaStudent und öffnet die Datei KheperaStudent.creator. Das Projekt wird geöffnet. Wählt hier nun das Verzeichnis "RobLab". Macht euch mit student.cpp und student.h vertraut. Das sind die wesentlichen Dateien, die verändert werden müssen. Es gibt eine Funktion namens „student_run(...)“, die von der main.cpp ausgeführt wird. In ihr läuft eine Endlosschleife, die die Funktion hinter dem Funktionspointer stp.state.hook immer wieder ausführt. Durch Manipulation dieses Pointers wird die Funktionsweise einer Statemachine abgebildet. Das wird einmal in student_init() und in jedem "state" gemacht (Siehe letzte Zeile in student_init()).

Ändert in der Datei KheperaStudent/Khepera-Lib/constants/constants.h die Konstante USEHOST auf die IP des Rechners, an dem ihr gerade sitzt. Die Nummer eures Rechners im Labor steht direkt unter dem Notebook-Bildschirm.

Kompiliert nun das Basisprogramm und starten es. Öffnet hierzu ein Terminal (strg+alt(links)+t) und wechseln in denselben Ordner ( cd KheperaStudent/RobLab ). Nun gebt ./compileAll.sh ein. Es wird alles kompiliert.

Nützliche Befehle:

(X = Botnummer)

Öffnet ein Terminal und navigiert zu "KheperaStudent/Khepera-Lib/mapserver". Führt nun ./gridmap.sh aus. Hier könnt ihr euch die Karte anzeigen lassen. Startet nun in einem anderen Terminal ./KheperaStudent/Roblab/main. Ihr seht den Verlauf einer kleinen Testfahrt. Die Darstellung zeigt hier nur den Pfad, den der Bot gefahren ist.

Auf dem Terminal könnt ihr verfolgen, in welchem Zustand sich der Roboter gerade befindet. Achtet insbesondere darauf, in welchem Zustand sich der Bot als erstes befindet und wie er in den nächsten Zustand wechselt. Falls euch das zu schnell geht erhöht den Wert der Konstanten SIMSLEEPTIME in student.h. Hierbei handelt es sich um Millisekunden pro Schritt in der Statemachine.

Aufgabe 1 – Erkunden einer Wand - Zeitraum: 2 Wochen

In Roblab/simdata findet ihr Simulationsdaten. Diese beinhalten jeweils alle Positions-, Sensor- und Orientierungsdaten einer Testfahrt des Bots auf einer bestimmten Karte. In student.h müsst ihr nun den Pfad in "USEDATAPATH" zu simdata/simA1_1.txt ändern. Jetzt noch kompilieren und schon könnt ihr die Simulation mit ./main auf eurem Rechner (nicht Bot) starten. Mit ./gridmap.sh könnt ihr die Map beobachten.

Die Darstellung zeigt hier nur den Pfad, den der Bot gefahren ist. Jede Position hat 3 mögliche Status: UNKNOWN, FREE, WALL. Der Status kann mit

setPointStatus(map, x, y, status);

gesetzt werden. Aktuell wird in der Methode student_run() immer die aktuelle Position gesetzt.

setPointStatus(stp.map, real2grid(stp.ot.result.x), real2grid(stp.ot.result.y), FREE);

Erklärung:

Mit

int sensorVal = khepera3.infrared_proximity.sensor[IR_LEFT];
float dist = sensorDist(sensorVal);

erhaltet ihr eine grobe Distanz zur Wand. Achtung! Der Distanzwert ist nur während der Wandverfolgung als Distanz nutzbar, da man sonst nicht garantieren kann, dass der Sensor senkrecht auf eine Fläche gerichtet ist. WICHTIG: Es wird zwischen Bot- und Mapkoordinaten unterschieden. Wenn der Bot x = 0.08 hat, so hat die Map x = 8 (siehe real2grid und grid2real). Außerdem sind im Roboterkoordinatensystem positive und negative y-Richtung vertauscht und somit ist die positive Drehrichtung auch invertiert (also rechts herum positiv)

Erklärung:

1.1 Wände einzeichnen

Eure Aufgabe ist nun, die Methode getWallPos(...) (siehe student.cpp) zu implementieren, die die korrekte Wandposition in Abhängigkeit der Botposition bestimmt und an den Adressen x, y abspeichert. Die korrekte Wandposition ist links vom Bot in der Distanz vom Mittelpunkt des Bots zur Wand. Für diese Aufgabe braucht ihr:

Um eure Methode zu testen kompiliert wieder simA1_1.txt und startet das Programm. Wird der Roboterpfad nun von einer rot dargestellten Wand umschlossen (abgesehen von dem kleinen Teil, in dem er geradeaus zur Wand fährt) und entspricht der Istwert der Distanz zwischen Bot und Wand immer dem Sollwert, so ist diese Aufgabe bestanden. Wenn 2-3 kleine Lücken auftauchen (eine Lücke = ein fehlender Pixel) ist das erstmal nicht schlimm.

Vergesst nicht einen commit für eure Aufgaben zu erstellen!

1.2 Landmarken und Pfadkorrektur

Setzt nun zunächst in student.h die Konstante A1_2 auf 1, A1_1 auf 0 und USEDATAPATH auf "simdata/simA1_2.txt".

Während der Bot eine Wand verfolgt wird ein track angelegt. Hier wird jede Position, Ausrichtung und der linke Sensorwert gespeichert. Damit euer Bot sich zurechtfindet braucht er Orientierungspunkte, sogenannte Landmarks. In diesem Projekt sind das Eckpunkte. Ist eine Wand vollständig abgefahren, so werden aus einem track die Eckpunkte gesammelt. Diese werden zur Korrektur der Map genutzt.

Eure Aufgabe ist nun mithilfe dieser Daten einen Track zu korrigieren. Verwendet hierfür simA1_2.txt. Das ist im übrigen auch die größte Map, die vorkommen kann. Wenn ihr den Verlauf auf der Map gut beobachtet, werdet ihr erkennen, dass die "rechten Winkel" nicht wirklich rechtwinklig sind. Das liegt daran, dass die Odometrie des Roboters denkt, dass er sich in den Kurven um mehr als 90° bzw. PI/2 drehen musste. Dieser Fehler sorgt dafür, dass der Bot seinen Startpunkt verpasst.

Ihr müsst nun dafür sorgen, dass dieser Fehler korrigiert wird. Dazu muss der Bot

Wie ihr vielleicht an den Ausgaben im Terminal gesehen habt wird bereits erkannt, ob der Bot seinen Startpunkt verfehlt. Die Genauigkeit hier liegt bei 1cm. Um das zu prüfen werden zwei Radien genutzt. Der innere Radius (1cm) muss erreicht werden, um den Pfad als "Fehlerfrei" anzusehen. Der äußere Radius dient der Überprüfung, ob der Bot in der Nähe des Startpunktes liegt. Die Fehlerbedingung lautet wie folgt:

Ein weiterer wichtiger Punkt, den ihr für die Eckpunkte im Hinterkopf behalten solltet ist, dass auch geprüft wird, ob der Bot in eine ähnlich Richtung gut, wie er sie am Startpunkt hatte. Das ist wichtig, da der Roboter unter Umständen auch unerwünscht in den äußeren Radius gelangen kann (z.B. wenn der Startpunkt auf der anderen Seite einer sehr engen Passage ist). Jetzt aber zur Fehlerkorrektur.

Hier kann man die Arbeit gut wie folgt aufteilen.

Teil 1

Die Similarity Transform wird in den Videos zum Kurs SLAM von Prof. Claus Brenner sehr gut erklärt (auf Englisch). Implementiert hierzu bitte die dafür vorgesehen Klasse und ihre Methoden in KheperaStudent/Khepera-Lib/simTrans/simTrans.h. Die Methoden sind similarityTransform(...) und useTransformSingle(...). Der Parameter perc ist erstmal nicht wichtig und bleibt auf 1. Die entsprechende Videoreihe geht von SLAM B 01 bis SLAM B 03 bzw.: zu Youtube

Kurze Zusammenfassung der einzelnen Schritte von Similarity Transform:

  1. Erkennen von Landmarks (Hier Eckpunkte)
  2. Heraussuchen der zugehörigen bereits vorher gefundenen Landmarks
  3. Berechnen der Vektorschwerpunkte von alten und neuen Landmarks
  4. Reduzierte Koordinaten aus linker, rechter Liste berechnen
  5. cs, ss, rr, ll berechnen
  6. lambda, c, s berechnen
  7. tx, ty berechnen

Teil 2

Damit der Roboter eine Korrektur durchführen kann, braucht er mehr Informationen. Er muss also weiterfahren, als nur bis zum Startpunkt. Genauer gesagt muss er an zwei Eckpunkten vorbeifahren, um diese zu scannen. In simA1_2.txt (was ihr gerade nutzt) fährt er bereits viel weiter als nötig. Eure Aufgabe ist nun wie folgt:

WICHTIG: Vergesst nicht Kopien des tracks zu nutzen, wenn ihr ihn weiterverwenden wollt.
WICHTIG: Dieser Teil ist eine Erweiterung von state_follow_leftWall() (unter dem Kommentar "Aufgabe 1.2 Landmarks und track-correction")

Teil 1 und 2 zusammenführen

WICHTIG: Speichert eure berechneten Werte aus similarityTransform(...) bitte in den dafür vorgesehenen Variablen: `lambda`, `c`, `s`, `tx`, `ty`

Jetzt müsst ihr nur noch die Variable buildwall auf false setzen, kompilieren und euer Programm starten. Lief alles richtig, so ist eure Map nun korrigiert. Wichtig hierbei ist, dass der Pfad für eure Wand partiell korrigiert wurde und die gesamte restliche Map zu 100%.

In der Ausgabe des Terminals könnt ihr sehen, ob eure Berechnungen korrekt sind. Weichen die Ist- und Sollwerte zu stark voneinander ab habt ihr vielleicht einfach leftlist und rightlist vertauscht. Vergesst nicht, dass an dieser Stelle nicht die Botposition, sondern die ganze Map korrigiert wird. Es kann hier gut sein, dass die map nach der Korrektur über den mapserver nicht vollständig angezeigt wird, weil hier zu viele Daten verarbeitet werden. Mit der Funktion debugPrintMap(stp.map) könnt ihr euch die map aber im Terminal anzeigen lassen. Für diese Aufgabe wird sie bereits eingesetzt.

Vergesst nicht einen commit für eure Aufgaben zu erstellen!

Aufgabe 2 Markierung, Wegfindung und Erkundung - Zeitraum: 2 Wochen

WICHTIG: Die Teilaufgaben dieser Aufgabe können völlig unabhängig und in beliebiger Reihenfolge bearbeitet werden (d.h. ihr könnt sie untereinander aufteilen, wenn ihr wollt). Beachtet aber, dass jede ein gutes Stück komplexer ist als ist vorherige.

Deaktiviert nun erstmal wieder A1_2.

Bisher wurde immer nur eine Wand abgefahren und die einzigen markanten Punkte waren Eckpunkte. Jetzt sollen alle weiteren Wände gefunden werden.

2.1 Markierung

Diesen Aufgabenteil könnt ihr nur im Labor vollständig testen ABER ihr könnt und solltet ihn trotzdem zuhause vorbereiten.

Setzt nun zunächst in student.h die Konstante A2_2 auf 1 und A1_2 auf 0.

Auf einigen der Styroporwände findet ihr Codes. Diese müssen erkannt und ihre Position für später gespeichert werden. Das geht aber ganz schnell, da der Erkennungsalgorithmus schon mit getcode() bereit steht. getcode() liefert euch dabei die Nummer des Codes (1,2,3) als Integer, oder -1 falls kein Code erkannt wurde (was also meistens passiert). Möchte man später den Punkt anfahren, so errechnet man eine angemessen von der Wand entfernte Position, aber dazu später mehr.

Erweitert state_follow_leftWall() so, dass die einzelnen Codepositionen im globalen Array codepositions (bereits vorhanden) gespeichert werden, wenn der entsprechende Code gefunden wurde. codepositions ist mit Nullen initialisiert. Mehr ist hier nicht zu tun. Die Codepositionen werden bei Fehlern der Wandverfolgung bereits mit korrigiert.

Testet euer Ergebnis im Labor. Hierzu braucht ihr folgendes: Öffnet in Roblab compileAll.sh und ändert die Variable COMPGCC auf false. Jetzt wird nicht mehr für euren Rechner sondern für die Roboter-Architektur kompiliert. Falls nicht schon erledigt ändert auch noch die Variable botnr auf eure Botnummer (siehe Botrücken).

Schaltet nun euren Bot ein und wartet bis die WLAN-Karte konstant leuchtet. Setzt nun den start-state auf state_forward(1) und kompiliert euren Code mit ./compileAll.sh. Der Code wird automatisch euren Bot übertragen. Mit

k3go +BOTNR

wechselt ihr auf euren Bot. Wechselt nun in euren Gruppenorder.

cd progrp6

für Gruppe 6. Euer Bot darf NICHT auf dem Tisch gestartet werden. Baut euch ein Rechteck aus Styroporwänden (ca. 1/4 der Karte) und setzt noch ein einzelnes Wandelement in die Mitte. Jetzt könnt ihr den Bot mit:

./main

starten.

2.2 Wegfindung

Für die Bearbeitung dieser Aufgabe braucht ihr folgende Variablen:

Um den kürzesten Pfad von einem Punkt zum anderen zu kriegen könnt ihr getPath() nutzen. getPath() implementiert den Floodfill-Algorithmus, also eine einfache Breitensuche. Je nachdem, ob ihr einen Status oder eine Koordinate eingebt liefert euch getPath() entweder den kürzesten Pfad vom Startpunkt zum dichtesten Punkt, der diesen Status hat (z.B. UNKNOWN) oder zu der jeweiligen Zielkoordinate. getPath() verwendet dabei die von euch übergebene map, d.h. ihr könnt auch eine manipulierte Version der Originalmap übergeben. Der ausgegebene Pfad ist ebenfalls in Bot-Koordinaten. WICHTIG!! getPath nimmt den kürzesten Pfad mit einer minimalen Breite von 1cm. Das könnt ihr im Terminal beobachten, wenn ihr den Code mit state_pathfindingTest(1) startet. Ihr kriegt eine Karte für den Startzustand und eine nach der Pfadsuche. Der Startpunkt befindet sich in dem kleinen Kasten (g), der Zielpunkt ist mit b markiert und der Pfad wird in der zweiten Karte mit dem Buchstaben "g" angezeigt (Das ist bereits ein optimierter Pfad, der nur die absolut nötigen Pfadpunkte zeigt). D.h. wenn ihr eure normale Map übergebt kriegt ihr einen Pfad, der auch direkt an der Wand (1 cm Distanz) verlaufen kann (siehe Terminal). Das ist natürlich kritisch, da der Bot nicht nur ein kleiner 1cm²-Block ist, sondern einen gewissen Durchmesser (ca. 14cm) hat. Weiterhin wollt ihr mindestens so weit von der Wand entfernt sein, wie bei der Wandverfolgung, wenn nicht sogar 1-2cm weiter. Eure Aufgabe ist nun eine Möglichkeit zu entwickeln dafür zu sorgen, dass der kürzeste Pfad nicht mehr so dicht an der Wand liegt.

Dieses Problem könnt ihr lösen wie ihr möchtet, aber im Wesentlichen habt ihr folgende Möglichkeiten: 1. Ihr modifiziert getPath() so, dass der Pfad den Abstand einhält. 2. Ihr gebt getPath() eine modifizierte Version der Map mit "fetten" Wänden.

Letzteres ist wesentlich leichter zu realisieren und wird deshalb von uns empfohlen. Achtet dabei aber auch darauf, die Wände nicht so dick zu machen, dass Wege versperrt werden. Weiterhin müsst ihr dafür sorgen, dass Bot und Ziel nicht von den dicken Wänden eingeschlossen werden. Kleiner Tipp: Erst neue map erstellen, dann Bot und Ziel in dieser Map befreien. Egal wofür ihr euch entscheidet, sorgt dafür, dass die Distanz zur Wand leicht zu ändern ist, sprich: durch Änderung einer Variablen bzw. Parameter einer Funktion.

Testet eure Lösung mit dem State state_pathfindingTest(1) und einer Wanddistanz von 3cm (diese Distanz reicht erstmal fürs Testen).

2.3 Erkundung

WICHTIG: Auch diese Aufgabe kann stark zuhause vorbereitet werden. Lest euch die Aufgabe also bitte erstmal vollständig durch, bevor ihr denkt, ihr müsst für alles im Labor sein.

Ihr könnt jetzt eine Wand abfahren, die Codes scannen und speichern und einen Pfad woanders hin finden. ABER bis jetzt habt ihr den Bot eigentlich nie gesteuert. Beobachtet jetzt das Verhalten und schaut euch im Code an, wie das realisiert wird. Stoppt den Bot, wenn ihr genug gesehen habt. Öffnet nun in KheperaStudent/Roblab das Script getData.sh und ändert dort die Bot-ID auf die von eurem Bot. Führt getData.sh nun einmal aus. Falls noch nicht vorhanden habt ihr jetzt ein Verzeichnis das mit "k3" beginnt und mit eurer Botnummer endet. Dort wird mit getData.sh immer die aktuelle collectedData.txt Datei heruntergeladen (sofern euer Bot an ist). Diese Datei könnt ihr genauso benutzen wie die bisherigen Simulationsdateien, sprich ihr ändert den Pfad in USEDATAPATH in student.h. Ihr könnt jetzt also jede Testfahrt die ihr macht speichern und exakt am Rechner wiederholen so oft ihr wollt, aber vor allem wesentlich schneller. So könnt ihr im Labor gesammelte Testfahrten auch zuhause nutzen und insbesondere auch wesentlich leichter Debuggen. Nutzt diese Möglichkeit bitte, wann immer möglich. Das spart euch viele Arbeitsstunden. Zum Vergleich: Die Erkundung der gesamten Map kann mit dem Bot ca. 10 Minuten dauern. Auf dem Rechner kann man diese 10 Minuten in einer Sekunde durchführen.

Euer Bot soll jetzt, nachdem er eine Wand erkundet hat, zur nächsten unbekannten Position fahren. Holt euch also einen Pfad zum nächsten unbekannten Punkt mit getPath(). Nun müsst ihr die einzelnen Punkte des Pfades abfahren. Euer Bot muss also eigentlich nur zwei weitere Dinge lernen.

  1. Dreh dich zum nächsten Punkt.
  2. Fahre geradeaus, bis du beim nächsten Punkt bist.

Schreibt dies bitte in den State state_drive2NextUnknown. Zur Wiederholung: Im Roboterkoordinatensystem sind positive und negative y-Richtung vertauscht und somit ist die positive Drehrichtung auch invertiert (also rechts herum positiv).

WICHTIG: Der Bot setzt zur Zeit nur seine eigene Position frei. Damit die Karte zu vervollständigen dauert ewig (bzw. ist unmöglich, da er nicht nah genug an die Wand herankommt). Sorgt dafür, dass ein größerer Bereich freigesetzt wird. Ihr dürft aber keine Wände überschreiben. Prüft also, welchen Zustand die zu setzende Position gerade hat.

Wenn keine unbekannten Positionen mehr erreichbar sind (kein Pfad), dann soll der Bot stehenbleiben (machine_stop()).

Habt ihr alles richtig gemacht, so könnt ihr mit gridmap.sh beobachten, wie der Bot Stück für Stück die Karte ausfüllt. Auf einer größeren Karte wird es zu Fehlern kommen, aber um die kümmert ihr euch in der nächsten Aufgabe.

Vergesst nicht einen commit für eure Aufgaben zu erstellen!

Aufgabe 3 - Zeitraum: bis zum letzten wöchentlichen Termin

Diese Aufgabe ist die Hauptaufgabe, in der alles Vorherige benötigt wird. Lest euch die Aufgabe bitte erstmal vollständig durch bevor ihr anfangt. Das folgende Verhalten soll implementiert werden:

Der Bot wird irgendwo in ein Labyrinth eingesetzt, welches die Hälfte des gesamten Feldes einnimmt. Von hier aus soll er zunächst die gesamte Karte erkunden. Das heißt, er soll in der map alle erreichbaren Positionen und alle erkennbaren Wände dokumentieren. Dabei sind im Labyrinth drei Codemarkierungen mit der Kamera zu finden. Sobald der Bot die Karte vollständig dokumentiert hat soll er die einzelnen Codes besuchen. Hat der Bot die letzte Codeposition erreicht ist die Gesamtaufgabe erfüllt. Der gesamte Ablauf darf dabei maximal 15 Minuten dauern und der Bot darf keine Wände berühren. Während eurer Vorführung müsst ihr angeben können, in welchem Zustand der Bot gerade ist, und erklären können, was der Bot gerade tut.

Das meiste kommt euch ziemlich bekannt vor. Was kommt also noch dazu? Bisher habt ihr immer nur Pfade zum nächsten unbekannten Punkt gesucht. Jetzt müsst ihr am Ende zusätzlich noch die Codepositionen anfahren. Implementiert dafür den State state_drive2nextcode(), für den ihr das meiste aus state_drive2NextUnknown kopieren könnt. Für den Pfad nutzt ihr dabei weiterhin die Methode getpath(), ABER diesmal setzt ihr natürlich Zielkoordinaten. Der Wert für den Zustand muss jetzt auf "(status_t)-1" gesetzt werden.

Jetzt kommen wir zum Kernpunkt dieser Aufgabe. Macht hier erst weiter, wenn der Teil davor erledigt ist. Beachtet hier bitte die Unterscheidung zwischen state_drive2NextUnknown und state_drive2nextcode: Am Ende von 2.3 haben wir von möglichen Fehlern gesprochen, die der Bot während der Fahrt macht. Bei der großen Karte die ihr am Ende abfahren müsst lassen sich Fehler kaum vermeiden, aber korrigieren (so wie in Aufgabe 1.2). Der Bot darf nicht gegen Wände fahren. Bei einer fehlerfreien Fahrt wäre das nach Aufgabenteil 2.2 Pathfinding kein Problem mehr. Allerdings fahren die Bots nicht fehlerfrei und so kann es dazu kommen, dass der Bot zwischendurch eine Wand "mitnimmt" oder ankratzt. Um das zu vermeiden müsst ihr in state_drive2NextUnknown() Wände unterscheiden können. Ihr unterscheidet hier zwei Fälle.

  1. Die Wand ist bekannt (es handelt sich also um bereits gesammelte Wandkoordinaten)
  2. Die Wand ist neu (ihr müsst die Wand also tatsächlich neu abfahren)

Der zweite Fall ist also der Normalfall. d.h. es kam zu keinem Fehler. Kommt es zum ersten Fall, so müsst ihr diese Wand solange nochmal abfahren, bis ihr mindestens wieder 2 Eckpunkte gefunden habt. Anschließend müsst ihr nur die Position des Roboters korrigieren. Dafür nutzt ihr wieder eure Methoden similarityTransform zur Berechnung der Transformation, und useTransformSingle(...) für die eigentliche Korrektur. Im Gegensatz zu state_follow_leftWall(...) wird hier aber die Botposition korrigiert, und NICHT die Map.

In state_drive2nextcode ist das wesentlich einfacher. Ihr habt die gesamte Karte bereits erkundet. Also gibt es auch keine unbekannten Wände mehr, und jede Wand der ihr zu nahe kommt ist eine bereits bekannte Wand. Die Unterscheidung fällt also weg. Die Korrektur aber natürlich nicht. Implementiert sie noch für diesen State und testet alles ordentlich durch.

WICHTIG: Euch wird der große Bearbeitungszeitraum für diese Aufgabe aufgefallen sein. Seht das bitte nicht als Einladung jetzt lockerzulassen. Nachdem ihr alles implementiert habt werdet ihr sehr wahrscheinlich viel Zeit mit Tests und Korrekturen verbringen. Ein wesentlicher Teil dieser Aufgabe ist nämlich das Anpassen des Fahrverhaltens eures Bots und seiner Parameter. Das bedeutet mehr Arbeit im Labor.

Für das allgemeine Verhalten bei der Wandverfolgung ist die Methode pureFollowLeftWall() zuständig. Mit der if-Bedingung könnt ihr festlegen, wie dicht der Bot in einer Ecke an die Wand heranfährt, bevor er sich dreht. Im else-Teil könnt ihr die Geschwindigkeit mit "speed" manipulieren. In mymachinedrive(...) könnt ihr durch Änderung von "diff" beeinflussen, wie stark er nach links/rechts korrigiert, während er die Wand verfolgt.

In state_forward, state_drive2NextUnknown und state_drive2nextcode geht es im Wesentlich darum, anzupassen mit welchen Sensoren man Hindernisse detektiert, und wie früh man reagiert.

Euer Bot kann das alles? Herzlichen Glückwunsch! Damit könnt ihr bei erfolgreicher Abgabe ein paar Leistungspunkte gewinnen. Ihr solltet allerdings trotzdem noch einen commit erstellen.

Quellen