/********************************************************************* TEACH SIMWORLD_QUICKSTART Version = 4.0 Beta Teach File Copyright (C) 2002 Matthias Scheutz (mscheutz@nd.edu) Artificial Intelligence and Robotics Laboratory Department of Computer Science and Engineering University of Notre Dame, USA http://www.nd.edu/~mscheutz/ http://www.nd.edu/~airolab/ All rights reserved. This program is licensed and distributed under the terms stated in the accompanying COPYRIGHT file. Last modified: 12-03-02 *********************************************************************/ Synopsis: This file contains instructions on how to use the SIMWORLD simulation. It provides several examples of different simulations as well as various simple exercises. ------------------------------------------------------------------------------ 1. Getting started ------------------ SIMWORLD is a so-called "artificial life simulation". This means that it consists of different kinds of objects, e.g., "agents", which are considered "alive" (in some metaphorical sense). These agents have to perform tasks to survive, usually they have to find "food" and "water". They are controlled by rules that tell them what to do in different situations. To get a quick preview of what the simulation looks like, first make the library available by compiling this line (put the Ved cursor on the line, then press ESC followed by D) uses simworld Then compile the following code: first mark it by moving the cursor to the first line, pressing "", moving the cursor to the last line, and pressing "". Now compile the range using " + d": startsimulation([ ;;; parameter list [[quitif 100]] ;;; entity list [[basic_agent [startup 20]] [obstacle [startup 10]] [plant [startup 25]] [water [startup 15]]] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); The windows you saw popping up are the "environment", in which the agents "live". One window shows the entire environment, while the other presents a zoomed view of a particular area. You can close them by clicking on the close button of the window. Alternatively, you can also close it by running the command below by moving the cursor over the next indented line and hit first the key, then the "d" key. We will abbreviate this by writing + d (note that + d compiles a single line, while + d compiles a marked range): close_environment(); In general, if you want the system to execute a command, simply move the cursor to the line of the command and press + d. We will talk later in detail about what a command is and what kinds of commands you can use. For now, all you need to know is that a command consists of a command word, in this case "startsimulation" followed by open and closed parentheses (possibly with additional characters called "parameters" in between, e.g., "([[[quitif ...])" as in the above case). When the demo ran, it produced some printout in the output.p file. You may find that the long lines were broken, making the printout confusing. If necessary, expand the width of the output.p window. You may need about 110 columns. (If you are using XVed it will automatically detect the new width. If you are using Ved in an Xterm window you will need to run this command to tell Ved to discover the new width from the xterm window: vedxrefresh(); If the demo you just ran was too fast, try to run it in "step mode". A new "output" window will open, in which you will see a number followed by "?". The number indicates for how many steps the simulation has been run, and the "?" tells you that the system is waiting for your input. For now, simply press in the output window to continue the simulation for another step. Try "step mode" by executing the following command: startsimulationstep([ ;;; parameter list [[quitif 100]] ;;; entity list [[basic_agent [startup 20]] [obstacle [startup 10]]] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); You will have to press RETURN 100 times. Replace the number after "quitif" with a smaller one if you are impatient. As you noticed, the environment is a squared area (typically of about 800 by 800 units) populated with various objects: - various kinds of agents (brown circles with a black spot indicating their current heading) - static and moving obstacles of varying size (red squared objects) - food and water sources (small green and blue circles) Agents need food and water (for moving and for their "brain"). So they have to find and consume food and water regularly, otherwise they "die". Remove the old windows: close_environment(); Let's see what happens when an agent does not have any food or water: startsimulationstep([ ;;; parameter list [[quitif 100][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -350][sim_y 0][heading 0][speed 10]]]]]] ;;; resource list is EMPTY [] ]); You should have seen an agent starting on the left side of the environment and running across to the right side. At cycle 49, just after passing the middle of the environment, it suddenly disappeared. That's when it ran out of energy and "died". (You can use +C to abort the process after that.) By the way, the number preceeded by "basic_agent" attached to the agent is the agent's name in the simulation (e.g., "basic_agent43" the 43rd basic_agent in this simulation run). It can be used to access more information about the agent, we will get back to this later. Food and water sources pop up within a particular area and disappear after a pre-determined period of time, if not consumed by agents earlier. Watch food and water pop up and disappear for a while: startsimulation([ ;;; parameter list [[quitif 200]] ;;; entity list [] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); This was probably too fast for you to see anything, so try to use "step mode": startsimulationstep([ ;;; parameter list [[quitif 200]] ;;; entity list [] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); Did you notice how food (green) came up more frequently than water (blue)? These frequencies, called "food frequency" and "water frequency" respectively, can be set. For example, if we want food to appear on average in every step, then we would run the following simulation: startsimulationstep([ ;;; parameter list [[quitif 200]] ;;; entity list [] ;;; resource list [[random [1.00 [plant]]]] ]); Getting crowded, right? By the way, if you don't want to hit return all the time, there is an alternative to "step mode": you can set a delay after each update step using the following command: 100 -> sim_delay; Note that the number on the left is the "delay value" measured in hundredths of a second, the right arrow "->" reads "goes to", and "sim_delay" is simulation parameter, which you can set. That causes a one second delay between cycles. Now watch the slowed down version of the previous simulation: startsimulation([ ;;; parameter list [[quitif 200]] ;;; entity list [] ;;; resource list [[random [1.00 [plant]]]] ]); To turn the delay off, simply set it to 0: 0 -> sim_delay; Or use an intermediate number for an intermediate speed, e.g. 5 cycles per second: 20 -> sim_delay; In the following, we will always use the "simulate" command in our examples, which runs a simulation without halting after each step. If you want the simulation to run slower, set a delay using "sim_delay" as we did above or make the simulation stop after each step using "simulatestep". Usually, a value of 10 for sim_delay works well. NOTE: you can set a delay value by typing a new value on the following line and executing it using + d, as usual: 10 -> sim_delay; Feel free to edit the number above. Any changes to this tutorial are only temporary. So, feel free to use and alter any commands you find in here! ----------------------------------------------------------------------------- Exercise 1.1: Run the very first simulation in this tutorial with a delay of 50 milliseconds--remember that the delay value is in hundreths of a second! Then close the environment window with the appropriate command and reset the delay to 0. (Warning in pop11, decimal numbers require a digit before the decimal point. So 0.15 is OK but .15 is not.) Exercise 1.2: What happens when you set the delay to 50 milliseconds and then try to run the simulation in step mode? Try it out with the agent that starts on the left side of the environment and runs across to the right side. ----------------------------------------------------------------------------- 2. Agents --------- Back to our agents. As we said, agents need food and water to survive, so they need to look out for food and water and when they see it, go there, grab it and eat it (or drink it). Let's watch an agent looking out for food and water. 20 -> sim_delay; startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -350][sim_y 0]]]]] ;;; include one piece of food [plant [startup [[[sim_x 0][sim_y 50]]]]]] ;;; resource list [] ]); The agent started out on the left side of the environment, moving horizontally to the right side. At step 25 it started to "sense" the food item, which caused it to change orientation and move towards it. At step 89 it came to a halt on top of the food item and started consuming it. Agents can only take in a certain amount of food per simulation step, so depending on how much food is stored in the food item, it may take them several steps to consume it. At step 104 the food source disappeared--the agent was done eating. It then started moving again in the direction in which it was facing until it the right boundary of the environment at step 469, after which it ran out of water and died. Let's see what happens if water is present at the same time: startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -350][sim_y 0]]]]] [plant [startup [[[sim_x 0][sim_y 50]]]]] [water [startup [[[sim_x 300][sim_y 0]]]]]] ;;; resource list [] ]); Now see what happens if new food and water items pop up at random locations in the environment (the resource list can be abbreviated to give plant and water the same probability): startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -350][sim_y 0]]]]] [plant [startup [[[sim_x 0][sim_y 50]]]]] [water [startup [[[sim_x 300][sim_y 0]]]]]] ;;; resource list [[random [0.10 [plant][water]]]] ]); As you can see, the agent moves around towards food and water items, comes to a stop on top of them and consumes them (at which time they will disappear). In the meantime, new food and water sources are popping up at random locations. In the previous simulation there was certainly plenty of food and water, in fact, there was too much for a single agent to consume. Hence, some food and water items disappeared without having been consumed. How do you think the situation will change if there are many agents around? Take a minute to think about before you verify your prediction using the following command that runs the same simulation with 20 agents: 0 -> sim_delay; startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup 20]] [plant [startup [[[sim_x 0][sim_y 50]]]]] [water [startup [[[sim_x 300][sim_y 0]]]]]] ;;; resource list [[random [0.10 [plant][water]]]] ]); Did you expect this outcome? Since food and water are rare, many agents go after the same food or water item, which sometimes leads to fatal collisions--every agent involved in a collision with another agent dies. Run the simulation again and observe how groups of competing agents form around food and water items, and how some of these agents die because of collisions. Compare this result to an environment with plenty of food and water: startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup 20]] [plant [startup 20]] [water [startup 20]]] ;;; resource list [[random [0.25 [plant][water]]]] ]); What is similar, what is different? In addition to running the simulation with many agents, we can make environments more dangerous by adding "obstacles" to it, since agents who crash into obstacles will die. Obstacles can be stationary or moving at different speeds. Here is an example of an environment with many static obstacles: startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[obstacle [startup 50]]] ;;; resource list [] ]); and here is one with many moving ones: startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[moving_obstacle [startup 50]]] ;;; resource list [] ]); Obstacles are indestructable, they will stick around even if agents crash into them, take a look: startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup 20]] [obstacle [startup 20]] [moving_obstacle [startup 20]] [plant [startup 20]] [water [startup 20]]] ;;; resource list [[random [0.20 [plant][water]]]] ]); Did you notice how agents try to avoid obstacles, while still moving towards food and water? And maybe you even saw the jerking backwards movements agents make when they come too close to an object? Let's examine these movements more closely using one agent, one obstacle, and one food item (which the agent will try to get). Observe, how the agent will "bounce back" when it gets close to the obstacle without ever touching it (you may need to add a delay to see what is happening): startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -50][sim_y 0][speed 1][energy 1000]]]]] [obstacle [startup [[[sim_x 0][sim_y 0]]]]] [plant [startup [[[sim_x 0][sim_y 0]]]]]] ;;; resource list [] ]); This behavior is created by a "reflex" in the agent, which gets triggered every time an agent moves too close to an obstacle. It will make the agent move back two steps and slighly reorient itself. Repeated triggerings of the reflex will help the agent get around an obstacle that is exactly in the way to food (as in the above case). It will not work always, however. Take a look at the following environment, where the agent has to get around a circluar wall in order to get to food and is eventually trapped on one side: 10 -> sim_delay; startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -100][sim_y 0][speed 1][energy 1000]]]]] [obstacle [startup [[[sim_x 0][sim_y 0]]] [[[sim_x -10][sim_y 40]]] [[[sim_x -10][sim_y -40]]]]] [plant [startup [[[sim_x 35][sim_y -20]]] [[[sim_x 35][sim_y 0]]] [[[sim_x 35][sim_y 20]]]]]] ;;; resource list [] ]); Note, however, how the problem can be solved if food appears at random locations in the meantime: 10 -> sim_delay; startsimulation([ ;;; parameter list [[quitif 500][seed 100]] ;;; entity list [[basic_agent [startup [[[sim_x -100][sim_y 0][speed 1][energy 1000]]]]] [obstacle [startup [[[sim_x 0][sim_y 0]]] [[[sim_x -10][sim_y 40]]] [[[sim_x -10][sim_y -40]]]]] [plant [startup [[[sim_x 35][sim_y -20]]] [[[sim_x 35][sim_y 0]]] [[[sim_x 35][sim_y 20]]]]]] ;;; resource list [[random [0.20 [plant]]]] ]); The agent will eventually sense other food items and try to get them instead of the one behind the wall. ----------------------------------------------------------------------------- Exercise 2.1: Examine in step mode some of the above simulations and make sure you understand what is going on. Re-run them several times to see what is random and what stays the same. ----------------------------------------------------------------------------- 3. Simulation parameters ------------------------ Surely by now you have noticed some relationship between the numbers following the "simulate" command (the simulation parameters) and the kind of simulation started by that command. The following parameters are those most commonly used for the "startsimulation" command (in the given order): - the number of simulation steps (also called "cycles") - the number of moving obstacles - the number of static obstacles - the number of initial food items - the frequency at which new food items are created in terms of a generation probability - the number of initial water items - the frequency at which new water items are created in terms of a generation probability - the number of agents For example, the command used in the beginning: startsimulation([ ;;; parameter list [[quitif 100]] ;;; entity list [[basic_agent [startup 20]] [obstacle [startup 10]] [plant [startup 25]] [water [startup 15]]] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); will start a simulation of 100 cycles with 10 static obstacles, 25 food items (where new ones will be created with a probability of 0.25 per cycle) and 15 water items (with new ones created with of 0.15 per cycle), and 20 basic agents. All entities are placed at random locations within the simulated environment. If you want to place agents in a particular location in the environment, you can do that by specifying its coordinates in a Cartesian coordinate system, where the origin (0,0) is the center of the environment. Coordinates of objects are specified by initializing the slots "sim_x" and "sim_y" in the object's initialization list. Let's take a look at a few examples. Suppose we want to create a simulation with three agents in the locations of the list [[0 0] [-20 -20] [20 20]], with no other objects around. And suppose further, we want to run it for only 2 cycles, then we need to write the following command: startsimulation([ ;;; parameter list [[quitif 2]] ;;; entity list [[basic_agent [startup [[[sim_x 0][sim_y 0]]] [[[sim_x -20][sim_y -20]]] [[[sim_x 20][sim_y 20]]]]]] ;;; resource list [] ]); While "sim_x" and "sim_y" are sufficient to specify the start state of food and water items and static obstacles, for agents and moving obstacles, it is also possible to specify an initial "heading" to point it in a particular direction. Directions are specified in degrees, from 0 to 360, where 0 is east, 90 is north, 180 is west, and 270 is south. The following simulation starts with four moving obstacles in the center of the environment, which all move in four different directions: startsimulation([ ;;; parameter list [[quitif 100]] ;;; entity list [[moving_obstacle [startup [[[sim_x 0][sim_y 0][heading 0]]] [[[sim_x 0][sim_y 0][heading 90]]] [[[sim_x 0][sim_y 0][heading 180]]] [[[sim_x 0][sim_y 0][heading 270]]]]]] ;;; resource list [] ]); Notice (1) that obstacles can move above (or through) each other without getting destroyed, and (2) that they move a different speeds (which are set at random). Re-run the above simulation to see different patterns of obstacle movements emerge. Now we are at a point, where we can "customize" simulations. We can either let the system pick initial positions for agents, food and water items, and obstacles, or set the coordinates ourselves using the sim_x and sim_y slots. Here is one more example of a simulation, which uses a combination of numbers for objects (that will be placed at random) and specified coordinates. The following creates a simulation with two agents placed at location (50,50) and (-50,-50), only one static obstacle placed at (0,0) and 2 random moving obstacles, 25 random food sources, and 15 random water sources. Food and water will subsequently appear at a probability of 0.25 and 0.15 per cycle respectively. startsimulation([ ;;; parameter list [[quitif 100]] ;;; entity list [[basic_agent [startup [[[sim_x 50][sim_y 50]]] [[[sim_x -50][sim_y -50]]]]] [obstacle [startup [[[sim_x 0][sim_y 0]]]]] [moving_obstacle [startup 2]] [plant [startup 25]] [water [startup 15]]] ;;; resource list [[random [0.25 [plant]] [0.15 [water]]]] ]); Try it out! ----------------------------------------------------------------------------- Exercise 3.1: Define a simulation environment for 200 update cycles with static obstacles at (100,-100), (100,100), (-100,100) and (-100,-100), one moving obstacle at (0,0) going northeast, 10 random food and 10 random water sources with update probability 0.20 each, and finally two agents, one at (-50,0) and one at (0,50). ----------------------------------------------------------------------------- For more information about SIMWORLD, read the SIMWORLD TEACH file, which you can access by hitting (this will move the cursor to the command line at the top of this window) and then typing "teach simworld" + . This will bring up another window with an more detailed tutorial on SIMWORLD. You can also get the file by putting the VED cursor between these two words TEACH SIMWORLD and then type + h ----------------------------------------------------------------------------- Solution to Exercise 3.1 startsimulation([ ;;; parameter list [[quitif 200]] ;;; entity list [[basic_agent [startup [[[sim_x -50][sim_y 0]]] [[[sim_x 0][sim_y 50]]]]] [obstacle [startup [[[sim_x 100][sim_y -100]]] [[[sim_x 100][sim_y 100]]] [[[sim_x -100][sim_y -100]]] [[[sim_x -100][sim_y -100]]]]] [moving_obstacle [startup [[[sim_x 0][sim_y 0][heading 45]]]]] [plant [startup 10]] [water [startup 10]]] ;;; resource list [[random [0.20 [plant]] [0.20 [water]]]] ]); ----------------------------------------------------------------------------- --- $poplocal/local/simworld/teach/simworld_quickstart --- Copyright (C) 2002 Matthias Scheutz (mscheutz@nd.edu)