We now have a great way to create files regarding the Robot’s brain, along with loading files of previous brains created!
We wanted to be able to store into text files the number of altControls a random brain used, the number of processes the brain used, the constants that each Above or Below Threshold was using, and all the variables (the left turn, right turn, and amount of time), for each MotorControl each random brain used.
Now, there is a savetofile() process which allows us to write a file line by line including all of the above methods. The BufferedWriter() and FileWriter() methods were called to create a new file for each individual random brain. This way we can keep track of what a robot did and run the robot again if we were happy with the brain it used.
In order to run the robot’s brain again, we needed to create a loadfromfile() process. This process takes in a file already created, and breaks it down line by line. The Scanner() method was called in order to read in a file that is given. Again, like above, each line has a different meaning regarding the robots brain (such as the constants it used). This allows for an easy way to see what the robot’s brain created, along with running the brain again to see if it was a worthwhile brain!
This week I focused on creating the evolutionary crossover method. A crossover method needs to take information from one parent robot, information from another parent robot, and swap that information. This mutates our robots without losing information which is what the regular mutation method does. The regular mutation method (changing constants, changing motor directions, adding information pathways, etc) destroys data whereas crossover moves data to a new robot. A different robot may be able to use the data from another in a better way.
After studying our results yesterday and reading a Graph Crossover Article to better our understanding of the process we are trying to make, we decided to calculate our minimum score’s a different way!
Our new calculations consisted of taking the minimum score over every robot generated so far. For example, if we were looking at all twenty robots in each generation up to generation 5, we would take the single minimum score out of the 100 robots seen so far. With these new minimum calculations, we were able to produce the following graph:
This was the graph we produced for a Mutation Rate of 5, having a population of 12 and 20 generations ran. The light blue line, labeled as WallBrain in the key, was our minimum guideline we were following. The unseen scores were produced by a hard-coded robot we new worked. The time alloted for each robot was one minute. After looking at the graph, we saw that for the fifth experiment ran with a Mutation Rate of 5, that there were some robots below the minimum guideline score! We were able to see that the lowest score produced out of all of our runs (even other mutation rates of 10, 15, and mutating only one thing at at time) was 0.77749997377396.
We traced this score back to see that it came from the fifth robot in generation eighteen. Then, we looked back and produced the following directed chart to see what our robots brain looked like!
This robots brain is very simple, but our smartest one yet! It covered the most amount of space in one minute. If there was an above threshold of 1.229, then the robot would slightly turn right. It appears that the robot bounced around our arena, successfully covering the most space we have seen yet!
We have finally made it to the point of running multiple experiments after another for our robots!
In order to get to this point, we added some important methods into our evolutionary algorithm. The steps we followed are:
- Initialize the brains of the robots (giving them their random connections to channels)
- Repeat the following steps until all generations have been formed:
- Evaluate the robot to see how well it did. They are given a score based on our algorithm.
- Select the next set of robots to move onto the next population using our Tournament Selection method.
- Mutate the selected robots and add them to the next population created.
We have updated our evaluation process to just take into consideration the amount of the arena the robot did not travel. Therefore, the robots get a score between 0 and 1 where 0 implies that the robot covered the whole arena and 1 means the robot did not move at all.
Currently, we are in the processes of testing out two different selection methods: Tournament Selection and Proportional Selection. At the moment, we are thinking that Tournament Selection is the better of the two based on the score results we have seen, but tests are still being done.
When running our experiments, we have used a variation of mutation rates. Starting out, we had mutation rates increasing by five, starting at 5 and moving up to a rate of 45. After collecting this data and making graphs, we saw that the best three mutation rates were 5, 10, and 15.
Our current results and graphs are based on the mutation rates of 5, 10, 15, along with our WallBrain for the robot. The WallBrain is the method we have written that we know traverses the arena like it is suppose to. We are using the average score of the WallBrain as our guideline to see where all scores should be. The graph is as followed for the average score of our unseen method:
These experiments are all based on 20 generations of robots, each consisting of a population of 12 robots. The Tournament Selection was the process used. Looking at the different mutation rates, it appears that the mutation rate of 5 has done this best with these processes. This is because the graph has sloped down the most exponentially, along with has the lowest overall scores out of the graphs. The mutation rate of 10 did well too, however it is a bit rocky along the way down. We would like for it to be smoother as it is decreasing.
Another graph made was based on the Minimum scores out of the unseen. They used the same mutation rates and the WallBrain again. It is as followed:
Overall, the minimum scores were closer to our guideline of the WallBrain. Again, mutation rates 5 and 10 had the lowest scores. The graphs overall were a lot more rough compared to just the averages, but we are seeing that we can get some lower scores.
As we are moving into the right direction and running more and more experiments, we are looking at mutation one part of the robot at the time, instead of multiple at a time. We are working on a crossover method to apply in our algorithm.
This blog post is a brief reminder of our project and a summary of all the work that has been completed this summer. If you would like to read the latest progress since the last post, please skip to the section marked with “Recent Progress”.
Last school year Dr. Goadrich, Dr. Jadud, Molly Mattis, and I were able to build and program a robot to enter into the Trinity College Fire Fighting Home Robot Contest. We used an occam-pi library called Plumbing to program the robot. Using a parallel programming language allows for processes to run concurrently and makes changing how the robot acts a much easier task. Our robot was able to place 15th out of 41 contestants. You can see the video here.
Yesterday (7/12/2011) we had used the DOT language and graphviz to create a simple directed graph of one of our random brain’s.
Today, we have updated these graphs. This first graph shown below represents our basic working brain of the robot. This brain allows the robot to walk around each room like it’s suppose to, but the code itself is hardcoded.
This next graph was created with one of our random brain’s that we tested out. Here our code was not hard coded; it was assigned random sensors and thresholds to venture through. This one was one of our more interesting random brain graphs.
The NOWHERE portion of this graph represents when a channel does not have an input or an output. On our “normal brain” you can see that this NOWHERE option is not visible. This is because when the brain works correctly all of the channels take in an input and an receive at least one output.
Our next task is to make our random brains functional so there is no longer a NOWHERE option for these random brains.
While researching this summer I have been extending my knowledge on the parallel language in java, which has led into learning about the occam-pi language. This is a parallel language that allows programs to in a sense multi-task; they can preform unrelated tasks at the same time.
Several papers have been written and published discussing different teachers and students use with occam-pi and how useful they found it. One that I found helpful to my understanding about occam-pi and it’s specific use with creating robots was the Safe Parallelism for Robotic Control. The paper discusses the building of the students’ and professors working together to build a robot that is controlled by the occam langue. It breaks down what a robot might need to do to execute a command and how the occam langue helps the robot run many tasks at a time. It gave some basic example codes which made the paper easy to understand.
Also, as we have been working these last few weeks, we have made progress towards randomize our robots brain and the channels it receives as inputs and what they output. Today, we were able to produce a graph using the DOT language to physically see where the connections have been made with our random brains. One graph example is:
As of Wednesday(07/06/2011) we had our simulator working to where we spit out a score for the robot on how well “it did”. The score keeps track of the Lifetime of the robot (how long it was moving around in the world), along with the Odometer (the distance travelled). With this score, we are able to tell if the robot crashed into a wall, spotted the light, or if it ran out of time. If the robot either ran out of time (it’s allotted five minutes were up) or crashed into a wall, the score would not take into account the distance travelled and therefore have a lower score. If it acknowledged that the light was there, the score then takes into account the distance travelled and the Lifetime of the robot.
Our goal was to find equations that allowed us to minimize both the Lifetime of the robot and the Odometer of the robot. We did this by using to simple equations which then gave us the value for both the distance and time of the robot.
During these trials, we ran into two problems: the first, if the robot was located in the negative x-axis of the world, and “collided” into a wall, instead of colliding all the way through, the robot would bounce of, and then move towards the way again. It kept repeating this pattern until we stopped the program on our own. After an hour of debugging, we found that this was due to our code since we had turned on the setUsePhysics(true) method (part of the environment description class). This use of physics was telling the robot to bounce of the wall.
Our second problem was the light was not set to a bright enough light, which led to the robot not being able to sense it was there. We also saw that in different rooms, the attenuation of the light was different depending on the size of the room and the location of the wall from the light. We looked into the PointLight class to try to understand why this was happening. It reassured us that the brightness of the light depended on where the walls were located with respect to the light. The PointLight class has a method called setAttenuation(), which brings in three constants: the light’s constant attenuation, the light’s linear attenuation, and the light’s quadratic attenuation. We further looked into these constants and found a relative equation which calculates the lights attenuation. This has helped us to better the brightness of our light in all four rooms.
Before we can start evolving new ‘brains’ for our robot, we need to translate our occam/Plumbing code into Java using JCSP. By using JCSP we are able to create a replica of our robot in the Simbad simulator. The first step we needed to take was to make an outline the occam-pi code to make translation easier.
I created this image using iMindMap. The map shows the channel and signal connections between the different processes. Our Java code will not be completely the same – our motor control will be different in the virtual world, for example.
So far, I have been able to translate the flame.detected, above and below threshold, and much of the brain components. Dr. Goadrich helped with this process by creating a version of the adc.get.reading process so that both the light sensors and range sensors can read from above and below threshold. Our robot now avoids walls (sort of) while looking for the candle in parallel. Now I need to translate the process which makes the robot follow the right wall.
As am I getting back into the swing of writing code in java once again, I am expanding my coding skills by adding bounding boxes around all of the possible lights in each room.
At first, we wanted to create bounding polytopes again. The problem we found with using the BoundingPolytope function in java is that all the regions of the polytope have to be convex. This would have worked for some of the rooms, but then some of the regions would have not been convex if we included all possible areas outside of the room where our robot could potentially notice light coming from.
Once understanding a BoundingPolytope would not work, we then decided to just create a bounding box around the rooms themselves. This was decided because Kathryn pointed out with all the overhead lights in the arena, it would be almost impossible for the sensors we are using on the robot to detect light anywhere outside of the room.
With that said, I hard coded a file with all the possible light locations: two in each room; which did include all possibilities for the lights when one of the four rooms was flipped. These next two links will give you a visual on the flipped rooms:
After hardcoding the lights, I was able to create a general code which opened the file and read the lines. The code broke up the numbers in the line in order to read the vector which contained the light location. Also, it retrieved the location of the smaller and larger bounding boxes which are needed for the code. Taking these three pieces, the bounding boxes were created.