Dynamische Zusammenhänge

Um die Arbeitsweise des Agenten zu verstehen, genügt es nicht, nur die verschiedenen Klassen, aus denen er besteht, zu studieren. Wichtig ist vor allem ein Verständnis der dynamischen Zusammenhänge zwischen den Klassen. Dieser Abschnitt beschreibt die Dynamik anhand des Informationsfluß vom Eintreffen von Sensorinformationen am UDP-Port bis zum Abschicken der Kommondos per UDP.

Die Timer-Funktion schedule wird aufgerufen (was alle 10ms passiert). Sie fordert das globale Sensors-Objekt (über den Aufruf der Funktion sense) auf, Informationen vom SoccerServer zu lesen. Solange der Communicator Strings an seinem Port lesen kann, wird ein String entgegengenommen und verarbeitet. Sichtinformationen sehen etwa so aus:

(see 0 ((goal r) 73.7 29) ((flag c t) 12.2 9 -0 0) ((flag r t) 64.7 1) 
((flag p r t) 50.4 18) ((flag p r c) 59.7 36) ((flag g r t) 72.2 26) 
((flag g r b) 75.9 31) ((flag t 0) 12.4 -14 0 0) ((flag t r 10) 22.2 -7 0 0) 
((flag t r 20) 32.1 -5 0 0) ((flag t r 30) 42.1 -4) 
((flag t r 40) 51.9 -3) ((flag t r 50) 62.2 -2) ((flag r t 30) 70.1 4) 
((flag r t 20) 71.5 12) ((flag r t 10) 74.4 20) ((flag r 0) 78.3 27) 
((flag r b 10) 83.1 33) ((flag r b 20) 89.1 38) ((flag r b 30) 95.6 43) 
((ball) 44.7 -44) ((player pt 2) 18.2 -36 0 0 -4) ((player) 60.3 -14) 
((player pt) 22.2 -47 0 0 85) ((Player) 3 -94) ((line t) 2 85) 
((line b) 70.1 85))

Hinweis: Die große Zahl von gesehenen "Flaggen" (besser Orientierungshilfen) ist typisch, da im SoccerServer 4.02 zur besseren Orientierung in 10m-Abständen um das Spielfeld herum Flaggen aufgestellt wurden.

Die Sensorikkomponente erzeugt nun für jede gesehene Flagge und Linie ein Objekt der Klasse StableObject. Dabei werden bereits Gradangaben in Bogenmaß konvertiert und Winkelangaben auf die mathematische Richtung (gegen den Uhrzeigersinn) umgestellt. Für jeden Spieler wird ein Objekt der Klasse MovingPlayer erzeugt, für den Ball ein Objekt der Klasse MovingObject. Auf diese Objekte kann dann mit den entsprechenden Accessor-Funktionen in Sensors zugegriffen werden.

Als nächstes ruft der Timer die Funktion integrateSensorInfo des globalen Weltmodells (die einzige existierende Instanz der Klasse WorldModel) auf, um die eben eingetroffenen Informationen in das Weltmodell zu integrieren.

Diese Funktion erzeugt eine neue Situation mit einem recht aufwendigen Verfahren, bei dem alle Daten, die aus der letzten Situation noch verwertbar sind (z.B. Spieler, die jetzt hinter dem Agenten sind, deren Position aber noch bekannt ist), per Simulation auf den aktuellen Stand gebracht und dann mit den neuen Sensorinformationen integriert werden.

Dabei wird als erstes aus den gesehenen Linien und Flaggen der eigene Standpunkt (ein Objekt der Klasse ViewPoint trianguliert. Innerhalb des Weltmodells werden alle Spieler durch ModelledPlayer-Objekte dargestellt (und der Ball analog durch ModelledBall). Diese Objekte enthalten unter anderem die absolute Position und den absoluten Geschwindigkeitsvektor des Objektes (wenn letzterer bekannt ist). Für schnell veraltende Daten existiert noch ein Reliability-Wert, der angibt, wie lange es her ist, daß der Wert zum letzten Mal wahrgenommen wurde.

Falls jetzt schon eine Aktion ausgeführt werden muß, wird den Effectors die Gelegenheit dazu gegeben. Diesen Teil werden wir nachher genauer untersuchen.

Nun wird die Entscheidungskomponente, der sog. Deliberator, aufgefordert, einen neuen Plan zu entwickeln (über den Aufruf von startDeliberation). Dabei läuft ein von uns entworfener, an das BDI-Modell angelehnter, aber aus Effizienzgründen etwas vereinfachter Entscheidungsprozeß ab.

Im Prinzip passiert dabei folgendes. Zuerst werden aus den möglichen Nebenbedingungen (Subklassen der abstrakten Superklasse Constraint) die in der aktuellen Situation nützlichen ausgewählt. Nun werden aus den Handlungsoptionen (Subklassen der abstrakten Superklasse Option)einige aufgrund ihres erwarteten Nutzens (unter den geforderten Nebenbedingungen) als Wünsche ausgewählt. Der Nutzen wird in Option gecacht und mit expectedUtility erfragt. Tatsächlich berechnet wird er in den einzelnen Subklassen, z.B. in ConserveStaminaConstraint von computeExpectedUtility. Von Wünschen wird dann der beste, tatsächlich umsetzbare als Handlungsabsicht festgehalten, wobei bei einem Wechsel der Absicht die dadurch evtl. entstehenden Nachteile berücksichtig werden. Aus der nun feststehenden Absicht wird mit Hilfe der in Skills definierten Fähigkeiten ein Plan erzeugt, der aus 1:1 vom SoccerServer ausfürbaren Kommandos besteht. Dieser Plan wird den Effectors zum Abschicken übergeben.

Alle 20ms gibt der Timer den Effectors die Gelegenheit, eine Nebenaktion (say, change_view, sense_body) abzuschicken. Alle 100ms darf Effectors eine Hauptaktion (alle anderen, vor allem dash, turn und kick) abschicken. Dazu verwaltet Effectors intern eine Queue von abzuschickenden Kommandos (Action-Objekten). Achtung: Soll eine Hauptaktion abgeschickt werden, werden evtl. in der Queue davorliegende Nebenaktionen verworfen! Ein Plan sollte daher nie mit einer Nebenaktion beginnen (er kann aber mit der Hauptaktion EmptyAction beginnen).

Vor dem Abschicken wird jede Action noch gefragt (isValid), ob sie meint, einen gültigen Command-String erzeugen zu können (was eigentlich immer der Fall sein sollte). Dann wird sie aufgefordert, einen Command-String zu erzeugen (asCommandString, der dann dem Communicator zum Abschicken übergeben wird. Ausserdem wird das Weltmodell informiert (per updateWithAction), dass diese Aktion gerade abgeschickt wurde. Ist die Aktion eine Hauptaktion (getestet mit isMainAction), geht das Weltmodell davon aus, daß seit der letzten Aktion 100ms vergangen sind, und erzeugt per Simulation eine neue Situation, in der die eigene Aktion eingearbeitet ist.

Damit ist ein Entscheidungszyklus in seinen wesentlichen Zügen beschrieben.

alphabetic index hierarchy of classes


Hauptseite

Einleitung | Architektur | Dynamische Zusammenhänge | Referenzhandbuch | FAQ | Anhang A | Anhang B

generated by doc++