Evolutionary Robotics Programming Assignment 10 of 10
by user
Comments
Transcript
Evolutionary Robotics Programming Assignment 10 of 10
CS206: Evolutionary Robotics Programming Assignment 10 of 10 Description: In this final assignment, you will connect the Python application you developed in assignments 1 through 3 with the robot simulator you have created in assignments 4 through 9. When you are done, the two applications will work together as follows: • The Python hill climber will start up the robot simulator and send it a collection of random synaptic weights. • The robot simulator will read in these weights, and use them to set the synaptic weights of the artificial neural network you created in the last assignment. • The robot simulator will run for 1000 time steps, and then record the final position of the robot’s main body. It will save this value to a file and then exit. • The Python hill climber will read in this value and treat it as the fitness of the synaptic weights it just sent. • It will create a copy of these weights, and mutate them slightly. It will then start up the robot simulator again, send it this new set of weights, and so on. Let us get started. 1. Create an empty directory called Assignment10. 2. Copy your Assignment3.py file from assignment 3 into this directory and rename it Assignment10.py. 3. Recall that the Python code implements a hill climber, a simple evolutionary algorithm that optimizes a neural network to exhibit some desired behavior. Comment out each line of the main function so that when you run the code it starts and then immediately terminates: #numGenes = 10; #numGenerations = 1000; ... #fits = Evolve(numGenes , ...); 4. Recall that in the function Evolve, a 10 × 10 matrix of synaptic weights was evolved. We now need to evolve a 4 × 8 matrix of synaptic weights: one synaptic to connect each of the four sensors to each of the eight motors. So replace the numGenes=10 line with numSensors = 4; numMotors = 8; #numGenerations = 1000; ... 1 5. Now uncomment the Evolve function, and change the parameters sent to it: fits = Evolve(numSensors , numMotors , ...) 6. Comment out all of the lines in the Evolve function so that your code still runs yet does not do anything (yet). 7. Now uncomment and modify the first four lines in Evolve accordingly: these lines create a vector for saving the best fitness as evolution proceeds; they create a random matrix of synaptic weights; and they evaluate the fitness of those weights: fits = Matrix_Create(1,numGenerations); parent = Matrix_Create(numSensors,numMotors); parent = Matrix_Randomize(parent)*2-1; parentFit = Fitness3_Get(parent); 8. The new function Fitness3 Get starts up the robot simulator and sends the matrix of weights to it; it waits for the robot simulator to terminate (after the simulator has saved out the fitness of those weights); reads in the fitness value; and deletes the files that allow the two programs to communicate with each other. def Fitness3_Get(synapses): weightsFileName = ’weights.dat’; fitFileName = ’fit.dat’; Send_Synapse_Weights_ToFile(synapses,weightsFileName); Simulate_Robot(); Wait_For_Fitness_File(fitFileName); fitness = Fitness_Collect_From_File(fitFileName); Delete_File(weightsFileName); Delete_File(fitFileName); return( fitness ); 9. Comment out all of the lines below Send Synapse Weights ToFile, and then implement only this function. This function should save all 32 weights to file weights.dat in the same directory as the python and robot simulator executables. Given that the rest of the Python code is commented out, when you run your code it should save this file and then quit. 2 10. Let us turn now to your robot simulator code. Make a copy of Assignment 9, and name the copy Assignment 10. Make sure that the simulator executable is compiled into your new Assignment10 directory. 11. We need to ensure that the robot simulator, when initiated, runs for 1000 time steps and then terminates. To do so, we need to define a new variable int timeStep, set it to zero in initPhysics, and then increment it during each pass through clientMoveAndDisplay. (Make sure also that the application always starts unpaused now.) 12. Once 1000 timeSteps have elapsed, the application should terminate: void RagdollDemo::clientMoveAndDisplay() { ... timeStep++; ... if ( timeStep==1000 ) exit(0); } 13. Run the executable several times. You should see the robot move for 1000 time steps and then see the simulation terminate. 14. You should have code in initPhysics that sets the elements of matrix weights to random values. Modify this code so that instead the elements are set to the values stored in weights.dat. 15. Now we need to capture the final position of the robot’s main body. So modify the code in clientMoveAndDisplay as follows (you will need to make use of Bullet’s getCenter OfMassPosition function): void RagdollDemo::clientMoveAndDisplay() { ... if ( timeStep==1000 ) { Save_Position(body[0]); exit(0); } } Within the function, capture the (x,y,z) position of the main body, and print the z-component of this position to the screen. This component reports how much the robot moves toward the viewer (negative values) and how much it moves ‘into the screen’ (positive values). 16. You may need to pause execution after you print the value, because the application will terminate immediately after printing the value. (The following will pause execution until the user presses ‘Enter’.) 3 printf... char ch = getchar(); 17. Within Save Position, write this value to the file fits.dat immediately after printing it. Verify that the number in the file and the number printed to the screen are the same. 18. Now run the executable several times. Note that it is reading in the same set of weights each time, so the robot’s behavior (and its final position) should always be the same. You may see that the behavior is different from one execution to the next. This is because it is sometimes difficult to get the physics engine to behave deterministically, even though in theory it should do so at all times. 19. If you do see that the final positions differ from one run to the next, the culprit often lies in the detection and resolution of contacts. This sometimes results in the touch sensors only being updated once every few time steps, and sometimes this updating is not deterministic. You can fix this by replacing m_dynamicsWorld->stepSimulation(ms / 1000000.f); in clientMoveAndDisplay with the following: while ( (touches[2]==0) (touches[4]==0) (touches[6]==0) (touches[8]==0) && && && ) m_dynamicsWorld->stepSimulation(ms / 1000000.f); (This assumes that the third, fifth, seventh and ninth body parts are the four lower legs respectively.) This new code continuously updates the motion of the robot until at least one of the touch sensors fires. 20. If you add this code and you are still seeing different final positions from one run to the next ensure that (1) you are reading in the same 32 synaptic weights in initPhysics each time; (2) you are running the simulation for exactly 1000 time steps each time; and (3) all eight motors receive the same desired velocity each time enableAngularMotor is called. If you are still observing non-deterministic behavior, contact the instructor. 21. Remove the line that prints the main body’s final position and the line that pauses the simulator so that the simulator now runs and then terminates without any user intervention. 22. Now return to your Python code. Immediately after Fitness3 Get sends the weight matrix to a file, it must start the robot simulator. You can use the os package which allows system commands to be executed from within Python code: 4 import os; ... def Fitness3_Get(...): [send weight matrix to file weights.dat] # If you are using a Windows machine... os.system(’App_RagdollDemo_vs2010.exe’); # If you are using a Mac or Linux machine... #os.system(’./AppRagdollDemo’); When you run your Python code now, you should see the robot simulator start automatically and then terminate after 1000 time steps. There should be both a weights.dat and fit.dat file sitting in the directory. 23. We must now instruct the Python application to wait until the fit.dat file appears. First, make sure to delete fit.dat in the directory by hand and then add the code: import time; import sys; ... def Fitness3... os.system(...) while (exists(’fit.dat’) == False): time.sleep(0.2); sys.exit(0); Now, when you run your Python application, you should see it stay open while the robot simulator runs. When the simulator terminates, so too should the Python application. 24. Remove the sys.exit(0) line, and follow it with code that reads in the single value stored in fit.dat. This value should be stored in the variable fitness, which is returned when Fitness3 Get terminates. 25. But before this function terminates it must delete the two files weights.dat and fit. You can accomplish this using the Python command os.remove(fileName). 26. Now when you run your Python code you should should observe the following: (1) the Python application stays open while the simulator runs; (2) both applications terminate together; and (3) weights.dat and fit.dat are no longer in the directory. 27. You can now uncomment the remaining lines of Evolve, so that the hill climber runs. Remember to use the new Fitness3 Get function when evaluating the fitness of the child set of synaptic weights: 5 Figure 1: Visual display of a high-fitness robot and a running print out from the hill climber that produced it. ... parentFit = Fitness3_Get(parent); for g in range(0,numGenerations): ... childFit = Fitness3_Get(child); print g, parentFit, childFit; if ( childFit > parentFit ): ... 28. You should observe a series of robots now. Over a few minutes, you should observe robots evolving the ability to locomote increasingly further ‘into the screen’. Capture one such robot in a screenshot, alongside a print out of your hill climber running. The first value in each row should report the current generation; the second value reports the furthest any robot has yet travelled ‘into the screen’ (parentFit); and the third value should report the distance travelled by the previous robot (childFit). Upload this single screenshot to the Wiki. 6