onsdag den 3. november 2010

Lab lesson 7: Braitenberg Vehicles

Lab session 7 - Braitenberg vehicles

Date : 28th of October 2010
Time used: 6 hours
Participants: Kim, José Antonio, Maria

Goal

The goals for this lab session is to work with and understand autonomous agents, specifically the Braitenberg vehicles [1], by implementing three of them.

Construction of the vehicles
We used the same car we have been using for the last sessions, and changed the sensor types and position.

We added first two light sensors to work with vehicle 2.




And then we added a sound sensor for vehicle 1.

Vehicle 1

Vehicle 1 is supposed to use only one motor, but to make re-usability possible, we used both motors, but applying the same amount of power to both all the time.

The code for vehicle 1 is very simple a separate threads just reads the sound sensor and the readings are used to control the motor driving forward.

Thread (SoundCtrMotor) controlling the motor based on sound readings:

public void run ()
 {
    int read;
    while (true)
    {
      try  {
       
          read = sound.readValue();
          motor1.controlMotor(read, forward);
          motor2.controlMotor(read, forward);
     
          Thread.sleep(dT);   
    
           } catch (InterruptedException ie)  {   
      }  
    }    
 }


Vehicle 2

We use a lighter to create light in front of the light sensor. This gives a scale from 20% light when the lighter is not present to 50% when we place the lighter in front of the sensor.

The code for vehicle 2 creates a separate threads for each light sensor. Light sensor readings are used to control the motor driving forward adding an offset to ensure there is sufficient power to drive the motor.

Threads  (LightCtrMotor) controlling the motor based on light sensor readings:

public void run ()
 {
    int read;
    while (true)
    {
      try  {
       
          read = light.readValue(); // Values in between 28 - 51 (light)
          motor.controlMotor(read+30, forward); // Add offset
     
          Thread.sleep(dT);   
    
           } catch (InterruptedException ie)  {   
      }  
    }    
  }

Code snippet from main program that creates and start the two threads and a “user interface” thread that waits for the program to be terminated:

    leftLightCtrMotor = new LightCtrMotor(SensorPort.S1, MotorPort.C);
    leftLightCtrMotor.setDaemon(true);
    leftLightCtrMotor.start();
   
    rightLightCtrMotor = new LightCtrMotor(SensorPort.S4, MotorPort.B);
    rightLightCtrMotor.setDaemon(true);
    rightLightCtrMotor.start();
   
    Vehicle2 vehicle = new Vehicle2();
    vehicle.run();

Vehicle 2a - Driving away from the light

This vehicle just controls the power of the motor based on the 2 light sensors as described in [2].

Vehicle 2b - Driving towards the light

To have the robot drive towards the light we used exactly the same program, but switched the connection to the two motors.

Video for vehicle 2b

Modifications to vehicle 2 - using sound sensors

Using the same code but replacing the light sensors with sound sensors seems to work, but it has a small problem: the sound level is the same in both sensors, even though you shout from one side. That means that it is mostly driving forward, not turning.

Separating the sound sensors solved this issue so the robot could react differently depending on where the sound comes from.



Vehicle 2 - Driving towards the sound


Vehicle 3 - reacting on sound and light:

This vehicle is a combination of reacting on both light and sound. 2 sound sensors and 2 light sensors were mounted letting the vehicle move in direction of light and sound.

Code snippet from main program that creates and start the four threads:

    leftSoundCtrMotor = new SoundCtrMotor(SensorPort.S2, MotorPort.B);
    leftSoundCtrMotor.setDaemon(true);
    leftSoundCtrMotor.start();
   
    rightSoundCtrMotor = new SoundCtrMotor(SensorPort.S3, MotorPort.C);
    rightSoundCtrMotor.setDaemon(true);
    rightSoundCtrMotor.start();
   
    leftLightCtrMotor = new LightCtrMotor(SensorPort.S1, MotorPort.B);
    leftLightCtrMotor.setDaemon(true);
    leftLightCtrMotor.start();
   
    rightLightCtrMotor = new LightCtrMotor(SensorPort.S4, MotorPort.C);
    rightLightCtrMotor.setDaemon(true);
    rightLightCtrMotor.start();


Vehicle 2 - adaptive:

So far all vehicles have been autonomous agents driving around interacting with the environment fulfilling individual goals. In this part of the exercise we have changed the light controlled vehicle 2 to be “adaptive” by implementing an algorithm that scales the power to the motors dynamicly. The algorithm adjusts the min and max light values measured over time and uses the min and max adjusted values to scale the motor power.

Code snippet for modified thread that normalizes the power based on filtered min/max values:

 public void updateFilteredMinMax(int sample)
 {
     // Filter max and min values based on last sample readings
     if (sample_1 >= sample_2 && sample_1 > sample)
    max = maxFilter.averageFilter(sample_1); // Local maximum
     if (sample_1 <= sample_2 && sample_1 < sample)
    min = minFilter.averageFilter(sample_1); // Local minimum

     sample_2 = sample_1;
     sample_1 = sample;
 }

 // Scaling the power base on sample, min and max values
 public int normalize(int sample)
 {
     int scale = max - min;
     int tmp = sample - min;
     return tmp * (60/scale); // Chosen based on max power (100) and min power (60)
 }

 while (true)
 {
      try  {
          read = light.readValue(); // Values in between 28 - 51 (light)
          updateFilteredMinMax(read);
          read = normalize(read);
         motor.controlMotor(read+min_power, forward); // Add offset
          Thread.sleep(dT);  
      }
 }  

The average filtering of the min and max values are done by performing a first order IIR filtering see [2]. In this case the coefficient “beta” is set to a value (0.5) that is used to average the min and max based previous samples.

A separate filter class is implemented to handle the filtering:

public class Filter {

 private double z_1;
 private double beta;

 public Filter (int start, double b)
 {
      z_1 = (double)start;
      beta = b;
 }

 public int averageFilter(int sample)
 {  
      // First order IIR filtering
     z_1 = (beta * sample) + ((1 - beta) * z_1);
      return (int)z_1;
 }

}

Link to complete code for the Braitenberg vehicles:

http://code.google.com/p/josemariakim/source/browse/#svn/trunk

lab7_1 : Vehicle 1: Sound controlled moving forward
lab7_2:  Vehicle 2a, 2b: Light controlled moving towards or away from light
lab7_3:  Vehicle 3: Moving in direction of sound or light controlled by 4 threads
lab7_4:  Vehicle 2: Light controlled with dynamic scaling and reacting on min/max light observations

[1], Braitenberg, V. 1984. Vehicles, Experiments in Synthetic Psychology London, Cambridge: The MIT Press.

[2] Infinite Impulse Response - filtering: http://en.wikipedia.org/wiki/Infinite_impulse_response
[3], Tom Dean, Introduction to Machina Speculatrix and Braitenberg Vehicles

Ingen kommentarer:

Send en kommentar