|
c't Projekte - c't-Bot und c't-Sim -
Mailinglisten
[Voriger (Datum)]
[Nächster (Datum)]
[Voriger (Thread)]
[Nächster (Thread)]
[Nach Datum][Nach Thread]
Absender: Timo Sandmann
Datum: Mi, 27.08.2008 18:52:12
In-reply-to:
<48C139945BA47F4DB4DE05DF62CD57AA03C4FD852D@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
References:
<000001c906ec$5d802ee0$0200a8c0@mexpnew> <3552FBF3-5B11-49C8-BE17-283FDF25DC18@xxxxxxxxxxxxxxx> <48C139945BA47F4DB4DE05DF62CD57AA03C4FD852D@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Hallo Frank,
Am 27.08.2008 um 08:09 schrieb Menzel, Frank IT-OO4:
Hallo Timo,
es gibt für die linke und rechte Spur jeweils ein Beobachter-
Verhalten, welches diese Spur im Auge behält. Darin gibt es schon
einen Timer, um erst nach Ablauf einer bestimmten Zeit auf die Map
zuzugreifen, da es beim echten ja sonst zur Mapüberlastung kommen
würde.
ja das ist mir auch nicht so ganz klar geworden: Wenn nur alle 700 ms
auf die Map zugegriffen wird, ist es aber ja trotzdem ein reines
Lotteriespiel, ob die Map gerade frei ist oder nicht. Dafür gibt es
eigentlich die Funktion map_locked(). Außerdem bringt es ja nichts,
seltener in der Map nachzuschauen, wenn man dafür dann einen größeren
Bereich seit dem letzten Check prüfen muss (dauert dann entsprechend
länger). Am Sinnvollsten erscheint mir, nach X cm gefahrener Strecke
die letzten X cm nebendran zu prüfen. Entscheidend ist eigentlich nur,
ob das Überwachen der Nebenspuren zeitlich noch passt oder nicht, wie
oft man die Abfrage dann macht (solange derselbe Bereich nicht
mehrfach überprüft wird), sollte eigentlich egal sein.
Ist die Map schon erforscht und es wird ein Hindernis auf der
Nebenbahn laut Map (nach Ablauf der Zeitspanne seit letztem Check)
erkannt, dann wird die bis zu dem Hindernis freie Strecke auf dem
Stack vermerkt. Es wird dann wieder nach dem nächsten gültigen
Startpunkt nach dem Hindernis gesucht und so geht es weiter. An
einem Hindernis voraus angekommen entscheidet er sich für eine
Richtung, vorzugsweise rechts, und fährt diesen rechts vom bot
berechneten Startpunkt der Nebenbahn an. Wäre links auch eine freie
Alternative gewesen, wird die linke Strecke (Start- und Endpunkt)
auf den Stack gespeichert. Geht es irgendwann einmal nicht mehr für
den Bot weiter, also rechts oder links von ihm Hindernis oder schon
befahren, wird eine Strecke aus dem Stack geholt (dieser enthält ja
nur unbefahrene Strecken) und angefahren. Beim Anfahren einer vom
Stack geholten Strecke liegt diese ja durchaus relativ weit weg vom
bot und der Weg dorthin kann auch von einem Hindernis verstellt
sein. Zum Anfahren müßte eigentlich ein Pfadplanungsverhalten her,
welches es aber noch nicht gibt. Der bot kann somit diese Strecke
nur direkt anfahren, d.h. einen der beiden Streckenpunkte,
vorzugsweise den nahesten. Ist dieser nicht erreichbar aber der Weg
zum anderen Punkt frei, wird dieser angefahren und versucht, von
dort aus die Strecke zu befahren. Ist diese auch nicht anfahrbar,
wird die Strecke verworfen und die nächste vom Stack geholt. Ohen
den Pfadplaner kann es somit auch zu unbefahrenen Stellen kommen.
Nach dem Stackholen werden auch lange Strecken geradeaus gefahren,
um den neuen Weg zu erreichen. Und hier bin ich aber auf das Map-
Update voraus (der Hindernisse) angewiesen. Das Anfahren erfolgt
hier zweistufig, einmal bis 30cm vorher. Dann wird der Punkt auf
Mapwert geprüft und bei Hinderniswahrscheinlichkeit möglicherweise
der andere Punkt angefahren. Also einfach Abschalten des Map-Updates
bei Geradeausfahrt geht nicht, für die Freistrahlen schon (werden
nicht gebraucht).
Ja du kannst zwar mit set_scan_otf_distance(0) das Distanzsensorupdate
ausschalten, bis voraus ein Hindernis erkannt wird und dann wieder
einschalten, aber das ist natürlich ein bisschen umständlich.
Sollten wir das Distanzsensorupdate vielleicht feiner steuerbar
machen? Also "ganz an" oder "ganz aus" oder "nur Hindernisse
eintragen"? Das könnte sinnvoll sein, weil gerade das Update der
Freistrahlen sehr lange dauert.
Vielleicht funktioniert das Verhalten aber auch mit Distanzsensoren
immer an, müsste man mal ausprobieren, wie viel Zeit das Überwachen
der Nebenspuren wirklich braucht und ob das in die "Lücken" des Map-
Updates passt.
Mit dem Bereitstellen einer allgemeinen "Auslese-Funktionalität"
habe ich nicht so recht verstanden.
Das Problem bei der Map auf einer SD-Karte / MMC ist, dass ein
(Schreib-)Zugriff (512 Byte) unterschiedlich lange dauert, je nachdem,
ob der gewünschte Block noch im selben Cache-Block des MMC-Controllers
wie der letzte benutzte Block ist oder nicht (im ersten Fall dauert es
1 ms und im Zweiten können es auch 50 ms werden, je nach Karte usw.).
Daher kann man keine genaue Aussage treffen, wie lange ein Map-Update
dauert und somit auch nicht exakt planen, ob es in Echtzeit während
der Fahrt geht oder nicht. Darum läuft das Schreiben auf die Karte
jetzt im Hintergrund, also letztlich immer dann, wenn der Bot alles
für einen Zyklus bereits erledigt hat, aber seine Zykluszeit von 10 ms
noch gar nicht aufgebraucht hat. Da ein Schreibzugriff deutlich länger
als 10 ms dauern kann, muss man ihn folglich unterbrechen, um einen
neuen Durchlauf der Bot-Main-Schleife ausführen zu können.
Genau das passiert seit dem Map-Umbau auch. Der Nachteil an der ganze
Sache ist, dass man natürlich während ein Schreibzugriff pausiert ist,
nicht lesend auf die MMC zugreifen kann. Da unbekannt ist, wie lange
ein Schreibzugriff dauert (s.o.), kann man nicht voraussagen, wann man
lesend auf die MMC (und somit auf die Map) zugreifen kann. Die
Funktion map_locked() gibt Auskunft darüber, ob die Karte gerade
gesperrt ist, oder man auf sie zugreifen kann.
Greift man (über eine der Funktionen aus map.h) auf eine gesperrte
Karte zu, wird der Zugriff solange verzögert, bis die Karte wieder
frei ist. Allerdings werden damit auch alle anderen Bot-Aktivitäten
(Sensorupdates, Notfallverhalten usw.) blockiert, es wird alles
angehalten und das Map-Update zu Ende geführt. Nicht besonders
elegant, aber auf Grund der beschränkten Ressourcen des ATmegas ein
Kompromiss.
Der Gedanke dabei ist, dass man die Karte eben nur dann ausliest, wenn
entweder map_locked() == 0 oder wenn der Bot stillsteht, denn dann
schadet es nicht, falls keine Sensorupdates und Notfallverhalten
ausgeführt werden. Soviel erstmal zum allgemeinen Ablauf bei der Map
(ich weiß es fehlt noch eine anständige Dokumentation...)
Was ich mit einer allgemeinen Funktionalität zum Auslesen der Map
meinte: Dein neues Verhalten könnte jetzt entweder mit map_locked()
usw. seine Zugriffe selbst koordinieren, oder wir machen genau wie für
das Map-Update ein Gegenstück zum Auslesen der Map. Also dass man
sagen kann, ich möchte gern die und die Auskunft von der Map
(irgendeine der Funktionen, die es in map.h gibt), die eigentliche
Abfrage wird dann auch im Hintergrund ausgeführt und wenn das Ergebnis
zur Verfügung steht, kann es vom Verhalten, das es braucht,
"abgeholt" werden.
Für ein Verhalten, das die Map benutzen will, lohnt sich das
vielleicht nicht, aber wenn es mehrere Verhalten gibt, die ähnliches
brauchen, macht es vielleicht Sinn, das Ganze zentral vom Map-Code aus
bereitzustellen?
Beim echten bot sollte es eigentlich auch funktionieren, habe mit
diesem aber momentan ein paar Problemchen und kann nicht testen...
Oh sorry, da im Betreff steht "nur für Sim", habe ich es auf dem
echten Bot gar nicht erst ausprobiert, werde ich mal nachholen!
Was mir beim Testen im Sim aufgefallen ist: Wenn der Bot bis zur Wand
rechts (oder links) vorgedrungen ist (die aber noch nicht als
Hindernis in der Map steht), crasht er irgendwann seitlich in die Wand
und hängt dort fest. Das ist eigentlich bei allen Welten im Sim so.
Dadurch kommt es leider nie zu dem Fall, dass das Verhalten den Bot
zur anderen Seite der schon abgefahrenen Fläche schickt, was aber ja
eigentlich einer der interessantesten Fälle ist.
Grüße,
Timo
|
|