Date: November 7th 2008
Duration of activity: 8-13
Participants: Kasper, Bent and Johnny
Implement a working Rodney Brooks layered control system on the NXT 1)
We modified the code to be more modular. This was not part of the exercise, but it made it a lot easier to test individual modules. Below follows the modifications made.
tooCloseThreshold
was initially set to be 20 cm, but this was not enough to take into account our modified Marvin which has a plate separating the two light sensors. Therefore this constant was changed to 35 instead.RandomDrive.java
has been changed to accommodate more action, less waiting. We wanted Marvin to move longer before the tread ended. This caused Marvin to be more “exploring.”Prints an “f” (forward) on the screen to show the direction of movement. The thread drives forward with different random numbers between 50 and 100 on each motor. This means that Marvin not necessarily (in fact not likely) will drive straight ahead. It will do this between 1 and 3 seconds. Then print “s” on the screen to indicate a stop and wait between 0.5 and 1 second. All these intervals are computed using a random function from Math library.
Implemented using a sonic sensor. Prints a “b” on the screen to indicate a backwards motion, and set full power to both motors and do this for 1 second to get a away from the obstacle. Afterwards Marvin stops both motors, and sets right motor to full power to make a left turn. Marvin does this for 0.8 seconds, and it seems to correspond to a 90 degree turn to the left. This thread shows a “f” while this happens. Lastly Marvin shows an “s” and stops for 0.5 seconds.
This thread waits for 10 seconds, then stops and plays a sound while printing an “s” on the screen.
The priority handling was in the initial code created by handing pointers to all lower priority behaviour to each behaviour, as shown in the code below:
rd = new RandomDrive("Drive",1); af = new AvoidFront ("Avoid",2,rd); ps = new PlaySounds ("Play ",3,af,rd);
This however makes shuffling of the priorities, as well as making the introduction of new behaviours a very tedious task. We therefore rewrote the priority system to make it more modular and flexible.
Below is the new structure:
ArrayList behaviors = new ArrayList(); RandomDrive rd; AvoidFront af; PlaySounds ps; DriveTowardsLight dl; rd = new RandomDrive("Drive", behaviors); behaviors.add(rd); dl = new DriveTowardsLight("Light ", behaviors); behaviors.add(dl); af = new AvoidFront("Avoid", behaviors); behaviors.add(af); ps = new PlaySounds("Play ", behaviors); behaviors.add(ps);
The idea is to use an array of Behavior objects containing all lower priority Behaviors in each Behavior.
this array is copied and stored in the constructor of each Behavior, and can then be iterated whenever suppression of the lower levels are needed.
private ArrayList behaviors; public Behavior(String name, ArrayList behaviors) { . . . // Clone the Behavior list. this.behaviors = new ArrayList(); for(int i = 0; i < behaviors.size(); i++) { Behavior b = (Behavior)behaviors.get(i); this.behaviors.add(b); } } public void suppressLower() { for(int i = 0; i < behaviors.size(); i++) { Behavior b = (Behavior)behaviors.get(i); b.setSuppress(true); } }
The code in its entirety can be found in the Behavior.java
file in the source tarball4).
The Behavior
class extends Thread
which makes it run as a thread in the JVM. The thread is configured to run as daemon which makes it automatically terminate together with the main thread5).
The DriveTowardsLight
class was implemented based on the code from lab7.
The wanted behaviour is the following:
Here is the most important code from the class:
private LightSensor l1; private LightSensor l2; private int offset = 60; public DriveTowardsLight(String name, ArrayList behaviors) { ... l1 = new LightSensor(SensorPort.S2); l2 = new LightSensor(SensorPort.S3); l1.setFloodlight(false); l2.setFloodlight(false); } public void run() { while (true) { // Read value from light sensors int val1 = l1.readValue() + offset; int val2 = l2.readValue() + offset; suppressLower(); forward(val2, val1); delay(500); unsuppressLower(); }
This code however would take over entirely the control of the car since it is active all the time.
We therefore introduced a light threshold to make the car search for light, only when there is some light to search for.
the code for that is shown below:
private int threshold = 80; public void run() { . . . if(val1 > threshold || val2 > threshold) { suppressLower(); forward(val2, val1); delay(500); unsuppressLower(); } }
The code in its entirety can be found in the DriveTowardsLight.java
file in the source tarball6).
The layered behavior model seems to work very well for the implementation of an autonomous robot. We believe that with an added push sensor Marvin would be able to navigate in any room avoiding any obstacles and find the exit with lights.