Our goal for this project was to create two robots, a predator and a prey. The predator would chase the prey, and the prey would try to escape. The hardware design of the predator and prey would attempt to simulate biological predator/ prey eye design. We wanted to determine possible algorithms to use for different eye designs, and which seemed to work best.
Both robots are approximately the same size, and have the same gear ratio (81:1) in order to keep their range of speed about equal. They each have a single bump sensor in front which is mainly for self-preservation (as opposed to information gathering). The exception is when the predator catches the prey (see below).
Each robot has 4 light sensors mounted in pairs on vertical posts. Each sensor can be rotated around its post by small discrete steps. This allows for adjustment of the angle between the two sensors in each pair, as well as between the two pairs. For most test runs, the eyes of the prey were situated to give a 360 degree view, whereas the predator's eyes faced almost directly forward (Figs. 1a, 1b). The prey's light sensors are fused in such a way that it is possible to access each pair of light sensors separately (i.e. the front pair, back pair, left pair, and right pair). The values for each pair are simply the sum of the two sensors in that pair. The predator's sensors are fused into a left value and a right value (no front/back values) by averaging the readings of the two sensors in each pair.
Each robot also has a light bulb mounted on top of it, which is how the other robot senses it. The prey's light bulb is unshielded and sheds light in all directions so the predator can see it from anywhere (provided the predator's light sensors are facting toward the prey). The predator's light bulb is shielded in back and toward the sides. This means the prey cannot see the predator if the predator is facing away. The intention is that since the predator only sees in front of it, the prey is safe when the predator is looking away. (Safety is equivalent to darkness, so by shielding the light, the prey is safe)
Before we began, the desired predator behavior was for the predator to chase the prey. We imagined that the predator would be in a constant chase state, and be attracted to light. It would probably move more quickly as light levels increased. If it hit a wall, it would turn around and continue chasing. If it hit the prey, it would stop.
The prey behavior was to run away from light. As light light levels decreased, the prey would move more slowly, since it was safer. If the prey hit anything, it would turn around. If the light levels dropped below a certain point, the prey would feel safe and start to "graze" - i.e. move around randomly. If the light level got too high, it would start running away again.
Both the predator and prey behaviors are very much dependent on immediate input, and require little state. Therefore, we decided that a reactive approach to the problem would be best.
For our first attempt at the desired behavior, we used the simplest model of reactive behavior we could think of-- we implemented Braitenburg's "cowardice" behavior in the prey and "hate" in the predator. Most of the time, the robots simply responded to immediate environmental conditions by speeding up or slowing down. When a robot bumped something, it backed up and turned around. This required a minimal amount of state to keep backing up for a little while even after the bump sensor went off. In addition, the predator stopped completely if the light values were high when it bumped. This caused it to stop when it hit the prey, but not when it hit a wall.
The bumping behavior worked fine in our first attempt and the only modification we made was to have the predator/prey turn in the direction of more/less light instead of always turning the same way.
The chase/escape behaviors did not work very well, however. The problem was that the light bulbs on the robots were small and not very bright, so in order for the robots to be able to see each other, we had to run the experiment in a very dark room. The result was that most of the time, the light valus were very low, but they could get very high within a small radius of the other robot. The motor values were spread evenly along the whole range, but the robots spent most of their time at the lower end, where they hardly moved at all.
We also had some problems specific to the predator and prey. At this point, the fusion of the prey's light sensors was simpler, and we could only access the left eye and right eye information. Each eye was the average of its forward and backward pointing components. This excacerbated the darkness problem, because one pair of eyes was always facing darkness. More importantly, because the prey could only access left/right information, it couldn't tell whether the predator was in front of it or behind it. If the predator was in front of it, it would move forward as it turned away. Clearly, turning around first or backing up would make more sense.
The problem with the predator was that its eyes pointed almost directly forward, so there was very little light differential between them and the left and right motors got set to almost the same speeds. The predator therefore had a very large turning radius and often went right past the prey.
When we ran the robots for our TA, Chris, he suggested that we try "ramping" the motor values so the robots would move faster in dim light. Before, we were using global maximum and minimum light values over the entire experiment. These had to be set with the frob knob before each run because the values depended on ambient light and brightness of the light bulbs, which varied with the stregth of our battery packs. Now, we implemented the following algorithm:
(We tried adding anywhere from 25% to 50% to the top and bottom of the range and didn't notice much difference. Motor values from 6 to 15 are spread evenly-- i.e. directly proportional to light values-- along the range)
The idea was that with this algorithm, the robot would get much more variation in motor speed with small changes in light, and (hopefully) would move faster more of the time.
When we implemented this design in the prey, we were pleased to discover that it worked amazingly well. We no longer had to frob maximum and minimum values, and the robot ran in any lighting situation at reasonable speeds. The only disadvantage was that the robot no longer slowed down as it moved away from the predator. Essentially, we had introduced a short-term memory, and moved away from an entirely reactive approach (at least, according to Brooks).
Unfortunately, even with ramping, the predator still was not getting enough differential between its eyes to turn effectively. So, we moved on to...
For the predator, we gave up on Braitenburg because the only way to get it to work was to angle the eyes further apart, which defeated the whole purpose of the "predator has stereo vision" idea. Besides, the Braitenburg model really doesn't use the information from both eyes together, as stereo vision should. So instead, we wrote a new algorithm which simply calculated the difference in light between the left and right eyes. We always set the motor on the dimmer side to 15, and the motor on the brighter side to a smaller value -- 13 if the light differential was very small, 8 if it was a bit larger, and 5 if it was very large. This algorithm was rather crude but worked quite well. As with the prey, we lost the behavior of slowing down in dimmer light, but the predator probably would never have been able to catch the prey if it did slow down, since the prey didn't!
The prey still had the problem of moving forward when facing toward the predator. To solve this, we changed the eyes so that each pair of sensor values (front, back, left, right) were accessible. This way the prey could tell whether the predator was in front or behind, simply by comparing front and back light values. We modified the escape alorithm so that if there was more light in front of the prey, it would set the motor values to just what it would if the light were behind it, except the motor on the dimmer side was negative. This way it would turn around before trying to run away.
These alogorithms became our final chase/ escape algorithms, except that we modified the predator's algorithm slightly by setting the bright-motor values to 13, 6, and 3 to give a smaller turning radius because in certain cases the predator still overshot the prey.
Our original idea for the prey was that, when light values dropped below a certain level, it would begin moving around randomly. This was basically intended to counteract the fact that both robots were supposed to slow down when far apart, and to possibly get the prey in sight of the predator. Although the robots don't slow down in dim light, we kept the grazing behavior because it is part of the biology model and makes the experiment more interesting to watch. We realized that trying to get random numbers in Rex would be more difficult than we thought, so we unfortunately didn't implement a random walk. Instead, we just had the prey alternate between moving in a straight line and turning by a certain (fixed) amount. In a perfectly smooth open environment with a perfectly geared robot, this would hardly be random behavior. But given the slight variations in the rug, the friction in the gearing, and the chances of hitting a wall, the grazing was random enough.
The transitions into and out of grazing behavior were based on a constant called min-light. Whenever the light values of both eyes dropped below min-light, the prey began grazing. Once grazing, if the values rose above min-light plus 10 (no particular reason for this constant except it seemed to work pretty well), the prey would stop grazing and start running away again. By changing min-light, we could get the prey to start grazing very close to the predator, or very far away, or not graze at all.
According to original plan, the predator would just be in chase mode all the time. The prey's grazing and the predator's wall-bumping would eventually cause it to be facing the prey, at which point it would chase and catch the prey. However, there were two reasons to abandon this idea. First, it didn't make sense as a biological model. A predator would not waste its energy running around until it just happened to see something to chase. Second, our arena was large enough that it would take a very long time for the predator to just happen to be facing toward the prey and be close enough to actually see it. So we decided to implement a behavior in the predator to take effect in low-light situations, analogous to grazing.
As with grazing, the stalking behavior is initiated by low light, terminated by somewhat higher light, and alternates between a straight phase and a spinning phase. Unlike the prey, however, the predator does not spin by the same amount all the time. Instead, it spins until it is facing more or less toward the brightest point it sees. The algorithm is simple:
In this way it turns toward the light and keeps turning until it starts to turn past the light. The actual implementation adds the light values in each eye over a few ticks and compares the sums, to smooth out any slight fluctuations.
The stalking behavior actually turned out to be rather interesting. If we set min-light to a low value, the predator tended to just spin once and then chase after the prey. But if we set min-light rather high, so that the predator continued stalking even when close to the prey, it looked kind of like a tacking sailboat. The spinning algorithm causes the predator to spin a bit past the prey, so it would spin, then go straight in a direction slightly diagonal to the prey, then spin again and move across the other diagonal. It always got closer to the prey, but not along a direct path. Unfortunately, we didn't have time to really experiment with this very much.
We didn't have as much time to experiment with eye placement as we would have liked, due to problems encountered in the last few days (see below). We tried an alternate eye configuration for the predator (Fig. 2a) which didn't work as well as the usual configuration, and also wasn't particularly interesting. However, when we tried an alternate configuration for the prey in which it couldn't see behind itself as well (Fig. 2b), we found a very interesting result. The prey developed a sort of hitch in its movement, which made it look like it was running away for a little while, then turning to see if the predator was still there, then running a little further, and so on. It did this because when the predator was right behind it, it couldn't see any light, so it went into the grazing behavior and started to spin. As soon as it had turned just a little, it could see the predator again, so it went back into the escape behavior. This effect was difficult to replicate because even in Lubrano with the shades closed, the ambient light values changed at different times of day and affected when the prey started to graze.
In the last few days, we started having problems with the prey's speed. The prey started going really slowly all the time and the predator caught it too soon to be interesting. We weren't sure whether this was due to a bad battery pack, friction in the gearings, or was an effect of the ramping algorithm. So we got a new pack, regeared the robot, and analyzed the ramping algorithm. The improved hardware helped a lot, but we also noticed that the ramping algorithm gave the robot a tendency to stay out of the high and low ends of its motor range. So even when it was about to get caught, it would still only be going at about 13. We introduced two frob constants to experiment with this. The first, ramp-time, controls the length of time between resetting the min and max light values. The second, bound-div, controls the amount added to the top and bottom of the motor range. However, even after experimenting with these, we couldn't get much differenc in the prey's behavior. Perhaps they need to be changed by a great deal before noticing any difference.
As a result, we introduced a frob value into the predator which just subtracted some constant from both motor values all the time. This was kind of a hack, but we couldn't think of anything else to do. As it turned out, once we had both batteries fully charged, the speeds of the robots were pretty equal, so we had this constant set to 1 during the competition. (i.e. the max speed of the predator was 14).
Although our final implementation differed slightly from plan (in that the robots didn't slow down as they got further apart, and we added the stalk behavior), we had a very successful project. We achieved robust behavior, and were able to experiment a bit with eye placement and observe the results. We found that although Braitenburg's models are very useful as a starting point, they need to be modified in some situations (in the prey), or replaced by more appropriate models (in the predator). Our system started out entirely reactive and Brooksian (i.e. no internal counters or memory), but became less so when we itroduced the grazing and stalking behaviors, which switch between straight and spin based on internal counters. Ramping also requires an internal counter. Nevertheless, for a problem like this, which requires dynamic interaction between robots, it is necessary that the robots be constantly sampling their environment. Our final system was still reactive, but performed far better than our original system due to the addition of a few simple states and transitions. I believe that our decision to start with a stateless system and add additional behaviors worked very well.