EinführungIch habe mich entschieden, einen Blog einzurichten, um meine Gedanken festhalten zu können. Der Vorteil davon ist, dass ich so im Internet - von überall aus verfügbar - die Fortschritte zu Papier bringen kann, damit auch andere Beteiligte, wie z.B. mein Betreuer, sehen kann, wie sich meine Simulation weiterentwickelt.
Fortschritt bis Einführung zum Blog
Als erstes ging es darum, eine Umgebung für meine Roboter zu schaffen. Ich entschied mich für die irrlicht Engine, da sie sehr einfach zu gebrauchen ist und für meine Zwecke völlig ausreicht. Um die Physik zu simulieren nutze ich die PhysX-Engine, die auch in vielen professionellen Spielen Verwendung findet. Das Einrichten der Umgebung ging relativ schnell voran, da ich mit beiden Engines früher schon Erfahrung gesammelt hatte. Nun kam mein erstes Experiment: Der Hopper. Bei diesem Roboter ging es darum zu schauen, ob sich meine Idee bewährte und ob ich die Maturarbeit, wie ich sie mir vorstellte, durchführen konnte. Es handelte sich um einen Roboter, der ein automatisches Sprunggelenk (algorithmisch gesteuert, nicht neuronal) besitzt und somit kontinuierlich springt. Als Steuerung setzte ich im Prinzip ein neuronales Netz ohne Hidden-Layers ein (also in der Form: output = weight1*input1 + weight2*input2 + ... + weightn*inputn). Der Roboter war in der Lage, auf den Körper direkt ein Drehmoment auszuwirken, was physikalisch eigentlich nicht korrekt ist (normalerweise können Roboter nur ihre Gelenke steuern, nicht aber direkt Kräfte auf sich einwirken lassen). Dieser Drehmoment wurde mit dem simplen neuronalen Netz berechnet, also Inputs dienten verschiedene Informationen über die aktuelle Lage des Roboters wie Höhe über Boden, Winkel, Touch-Sensor und noch ein paar andere. Die Weights des neuronalen Netzes wurden dann evolutionär optimiert (dazu komme ich zu einem anderen Zeitpunkt noch). Es zeigte sich, dass relativ rasch (innerhalb weniger Generationen) Gewichte gefunden werden konnten, die den Roboter sehr effizient fortbewegen liessen, das Entwicklungspotenzial (d.h. wie effizient der Roboter noch werden kann) war aber auf Grund der relativ einfachen Aufgabestellung (sich möglichst schnell fortbewegen) und wegen der physikalischen Inkorrektheit sehr rasch erschöpft:

Diese Abbildung zeigt, wie sich die Fitness der Roboter (d.h. wie schnell sie sich fortbewegten) entwickelte. Die blaue Linie repräsentiert jeweils das beste Individuum in der Population, die Pinke den Durchschnitt.
Ich habe einen Film hochgeladen, der zeigt, wie sich der Roboter fortbewegt - bemerkenswert ist dabei, dass er sich physikalisch inkorrekt fortbewegt.
http://www.4shared.com/file/14912865/f15a14ba/firstexperiment.htmlMit diesem Experiment zeigte sich aber, dass es bei sich bei meinem Konzept um ein realistisches und realisierbares handelt, da ich mit relativ wenigem Zeitaufwand erste Resultate erzielen konnte.
Als nächstes implementierte ich dann ein richtiges neuronales Netz mit hidden Layers, da mir die bisherige Steuerung zu einfach und zu beschränkt war. Danach suchte ich einen neuen Phänotypen für den Roboter, da der Hopper wohl noch zu komplex für mich war (wenn er physikalisch korrekt simuliert werden sollte) und ich zuerst Erfahrungen bei einfacheren Robotern sammeln wollte.
Das Resultat war dann ein 2-dimensionaler Wurm mit 5 Teilen:

Hier ist mit 2-dimensional gemeint, dass er sich entlang einer Geraden und in die Höhe bewegen kann, nicht aber auf einer Ebene.
Der Wurm hat die Möglichkeit, jedes seiner 4 Gelenke über ein neuronales Netz zu steuern. Ich wählte 2 Hidden Layers mit je 12 Neuronen. Als Inputs dienten die 4 Winkel zwischen den jeweiligen Wurm-Teilen und die des letzten Frames, dies damit das neuronale Netz ein sich repetitiver Bewegungsablauf generieren konnte. 4 Output-Neuronen steuern dann die gewünschten Winkel zwischen den Wurm-Teilen. Die Physik Engine versucht dann mit entsprechenden Drehmomenten, diese zu erreichen.
Auch dieses Resultat lässt sich sehen: Im folgenden Video sieht man die Entwicklungen mit den Generationen: Jeweils der beste Roboter jeder Generation wird simuliert, zu hinterst die 1., zu vorderst die letze Generation.
http://www.4shared.com/file/14913483/371c0200/2dworm.htmlWas ich heute gemacht habe
Mein Ziel war es, den Wurm so weiterzuentwickeln, dass er bei jedem Gelenk 2 Freiheitsgrade steuern kann. Der Vorteil ist, dass ich so von der 2D-Umgebung wegkomme. Die Folgen davon sind, dass die Bewegungsabläufe komplexer werden. Mein Wurm hat inzwischen ca. 400 Gene - die zu optimieren, ist keine einfache Aufgabe für den Computer. Ich könnte mir vorstellen, dass es viele Generationen braucht, damit sich der Wurm immer schneller fortbewegen kann.

Bei diesem Task war vor allem schwierig, das Rotations Target für das Gelenk zu berechnen. In der PhysX-Dokumentation wurde ich nicht schlüssig, wie ich die Rotation in 2 Teilrotationen aufsplitten kann, damit das neuronale Netz es einfacher hat, den Roboter zu steuern (eigentlich wäre ein Quaternion gefragt, welcher 4 Attributen besitzt, allerdings handelt es sich um ein Universal-Gelenk, das 2 Winkel als Target verlangt (siehe Grafik links)).
Die Lösung des Problems waren dann Euler-Winkel. Diese sind eigentlich genau die richtige Möglichkeit für mich, Rotationen zu beschreiben. Das Objekt wird zuerst entlang der einen Achse rotiert, danach wird es um die nächste Achse rotiert, wobei die Achse, um die rotiert wird, von der 1. Rotation bereits rotiert wurde.

Das Gleiche gilt für die dritte Achse. Man kann es auch mit einem Flugzeug vergleichen:
Dieses Prinzip kann man auch für Target-Rotationseinstellungen (wie die Rotation von den beiden Bodies, die am Gelenk angeschlossen sind, im Verhältnis sein soll) von Gelenken anwenden, dort wird ein Quaternion verlangt, denn man aber aufgrund von Euler-Winkel berechnet.
http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_anglesNun hatte ich dieses Problem also gelöst. Als Folge davon war das neuronale Netz mit der Zeit in der Lage, unseren 5-teiligen Wurm so zu steuern, dass er nach wenigen Generationen sich mehr oder weniger Effizienz fortbewegte. Im Release-Modus allerdings kam es immer wieder zu einem Crash. Das Problem ist, dass dieser Fehler nicht debug-bar ist, da er nur im Release-Modus und zudem in der DLL der Physikengine auftritt. Ich werde sehen, wie ich diesen Fehler wegkriege.