Hiba Khatib
Project: Engineer Option
In my final project, I improved my A8 assignment and ran it for 300 generations on populations of 10 on 10 random seeds.
Although the preferred task was 500 generations, the run time for my generations made this task unrealistic considering the time deadline. Each generation for a population of 10 was taking approximately 2-3 minutes. For 500 generations, 10 different times, this would have taken at least a week to run all generations. Minimizing the number of requested generations produced great results in comparison to my previous simulations while also running in a timely manner.
Quick gif showing one evolution:
2 minute summary video: https://youtu.be/9DaIDKjyWWY
2 minute video showing numerous evolved body, before and after: https://youtu.be/QLFIh9ZBLcM
For my final project, I evolved random creatures in 3D. As opposed to my previous bodies, these creatures do not have a presupposed body shape and are randomized to a much greater degree.
For every body, all joints contain motors and every pair of neurons contains synapses. There is a motor for every joint but sensors are added randomly with a 50/50 chance upon initial body creation.
A blue colored link indicates that the link does not contain sensors while green indicates that link does contain a sensor.
The bodies are completely randomly generated. The simple recusion employed, as described in the figure below, only enforces the creation of another limb which branches on the previous limb. The main segment grows a segment randomly on its body, which grows another random segment, so on and so forth. The segments do not overlap and form a jumbled mess. The positions and sizes of every segment are stored in a list which is used to generate new segments appropriately on the body.
Prior to brain generation, the robots are able to sense and act but their sensors do not inform their actions. By generating the brain, we connect the robot's "sensor to its motors using a neural network comprised of neurons and synapses" (https://www.reddit.com/r/ludobots/wiki/neurons/). The inclusion of neurons and synapses allows for closed loop control of the robot in which the motor neurons send the angles to motors, which are then converted to torques and applied to joints, changing the robots steps and robot's sensors, and finally the synapses taking the values from the sensors back to the motors neurons.
The brains are regenerated with every new body to accomdate changes within the body.
The diagrams below explains the three different types of mutations. All of these mutations occurred at random. There was a mutation on every best robot per generation. The addition or removal of a link was a 50% chance while the synapse weights and sensor removals/link size changes occurred every time.
This is the original body, prior to mutation:
The following illustrate possible changes to the original body resulting from each of the mutations:
*brief note about this diagram: the link does not exclusively have to be a motor neuron link, this is how I happened to draw the diagram which I now realize may be a little bit confusing. The link being removed/added is any link, including sensor neuron links*
The fitness is calculated as farthest distance from the robot's starting point. In the figure, the better fitness is at values less than 0 because I wanted the robot to move away from our POV, in the negative direction.
At every generation, the robot that moved the farthest was selected as the best and set as the parent. The parent is then mutated and evolution is run where mutations occurred. Then the best robot is selected, and the process repeats until the end of the simulation. The final robot should have the highest fitness, meaning it achieved the farthest distance as a result of its evolution.
There are some points in the graph where there is a significant drop in fitness. This could be due to a bad mutation such as a body already having lost most of limbs, losing another important link and losing good mobility.
From my 30,000 simulations, I was able to conclude the following:
- smaller bodies are preferred as almost every robot, 7/10 of the random seeds, became smaller in size by the end of their evolution.
- complexity leads to less fitness. The bodies that had more complex seeming bodies struggled to move around and often got stuck in place. Below is an example of a complex body which failed vs a simple body which performed well:
- if the body was very complex but longer in the vertical direction, it performed better than less complex and much smaller bodies because it had more limbs touching the ground to attempt to use and move with. This often led to jumping and hopping.
Some of these trends can be seen in this video: https://youtu.be/QLFIh9ZBLcM
After cloning this repo, run the command "python search.py" in your terminal. You will see the initial body, then you will see values print to terminal before being asked to press enter to view evolved body. I recommend going into constants.py to change population size and generation size to view results quicker otherwise it will take several hours.
- The algorithm for evolution is in parallelHillClimber.py based on a hill climber evolution: https://en.wikipedia.org/wiki/Hill_climbing. Also check out the ludobots MOOC which guides you through phc.
- Solution.py is where all the body and brain generation occurs. I would check that out first to see how bodies and brain are generated. Everything else can mostly be found in the ludobots MOOC linked below.
Find pyrosim physics simulator here: https://github.com/jbongard/pyrosim
Find more info about ludobots MOOC here: https://www.reddit.com/r/ludobots/wiki/installation/
Karl Sims' paper which I referenced when building my diagrams: https://www.karlsims.com/papers/siggraph94.pdf
This project is for CS396 Artifical Life taught by Professor Sam Kriegman, professor and creator of xenobots, at Northwestern University. Check out his work here: https://www.xenobot.group/.
Deepest thanks to TA Donna Hooshmand for great support and mentorship throughout.