October 28

Braitenberg Vehicles

vehicles

Vehicle 1

A first agent has one sensor (e.g. light-detector) that directly stimulates its single wheel in an excitatory way. The vehicle can standstill or move forward. The behaviour of this vehicle can be interpreted as:

  • More light produces faster movement.
  • Less light produces slower movement.
  • Darkness produces standstill.

This behavior can be understood as a creature that is afraid of the light and that moves fast to get away from it. Its goal is to find a dark spot to hide.

Vehicle 2a

A slightly more complex agent has two (left and right) symmetric sensors (e.g. light detectors) each stimulating a wheel on the same side of the body. It obeys the following rule:

  • More light right → right wheel turns faster → turns towards the left, away from the light.

This is more efficient as a behavior to escape from the light source, since the creature can move in different directions, and tends to orient towards the direction from which least light comes.

In another variation, the connections are negative or inhibitory: more light → slower movement. In this case, the agents move away from the dark and towards the light.

Vehicle 2b

The agent has the same two (left and right) symmetric sensors (e.g. light detectors), but each one stimulating a wheel on the other side of the body. It obeys the following rule:

  • More light left → right wheel turns faster → turns towards the left, closer the light.

As a result, the robot follows the light; it moves to be closer to the light.

 

Braitenberg_Vehicle_2ab

Many emergent “personalities” are possible:

Image2

Especially with great complexity:

url

This actually works:

 

Casey Reas, co-creator of Processing, uses fleets of Braitenberg Vehicles to create paintings:

reas_tissue_p_2

reas_microimage_s2_0

MicroImage (Software 2) from Casey REAS on Vimeo.

 


Turtle Graphics

The Turtle object has the following methods:

var turtle = new Turtle(x, y) // make a turtle at x, y, facing right, pen down
turtle.left(d);             // turn left by d degrees
turtle.right(d)             // turn right by d degrees
turtle.forward(p);          // move forward by p pixels
turtle.back(p);             // move back by p pixels
turtle.penDown();           // pen down
turtle.penUp();             // pen up
turtle.goto(x, y);          // go straight to this location
turtle.setColor(color);     // set the drawing color
// turtle.setColor(color(r,g,b)); can be used to set color with r, g, b, values
turtle.setWeight(w)         // set the line width to w
turtle.face(d);             // turn to this absolute direction in degrees
turtle.angleTo(x, y);       // what is the angle from my heading to location x, y?
turtle.turnToward(x, y, d); // turn by d degrees toward location x, y
turtle.distanceTo(x, y);    // how far is it to location x, y?

Turtle Example 1

To post code on WordPress, I think you need to include all in one file. That’s what I did here.

turtle-ex1

// for posting on WordPress, I think we need everything in one file, so here's the Turtle
// code in compact form followed by my program.

function Turtle(x,y){this.x=x;this.y=y;this.angle=0.0;this.penIsDown=true;this.color=color(128);this.weight=1;this.left=function(d){this.angle-=d};this.right=function(d){this.angle+=d};this.forward=function(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;var newy=this.y+sin(rad)*p;this.goto(newx,newy)};this.back=function(p){this.forward(-p)};this.penDown=function(){this.penIsDown=true};this.penUp=function(){this.penIsDown=false};this.goto=function(x,y){if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);line(this.x,this.y,x,y)};this.x=x;this.y=y};this.distanceTo=function(x,y){return sqrt(sq(this.x-x)+sq(this.y-y))};this.angleTo=function(x,y){var absAngle=degrees(atan2(y-this.y,x-this.x));var angle=((absAngle-this.angle)+360)%360.0;return angle};this.turnToward=function(x,y,d){var angle=this.angleTo(x,y);if(angle<180){this.angle+=d}else{this.angle-=d}};this.setColor=function(c){this.color=c};this.setWeight=function(w){this.weight=w};this.face=function(angle){this.angle=angle}}


function setup() {
    createCanvas(400, 400);
    background(0);
    var turtle = new Turtle(130, 80);
    turtle.penDown();
    turtle.setColor(255);
    for (var i = 0; i < 1000; i++) {
        turtle.forward(150);
        turtle.right(141.5);
        turtle.forward(60);
        if (i % 20 === 0) {
            turtle.forward(70);
        }
    }
    noLoop();
}

function draw() {
}

  

Turtle Example 2

The above example calls turtle commands inside control constructs and could draw a number of different things sequentially. If you want to see animated turtles, you can issue commands in draw without erasing (calling background()). In this case, draw becomes your loop and at most you have time and frameCount and global variables as a way to get changing behavior.

turtle-ex2
Here’s an example of chasing Perlin noise:

// for posting on WordPress, I think we need everything in one file, so here's the Turtle
// code in compact form followed by my program.

function Turtle(x,y){this.x=x;this.y=y;this.angle=0.0;this.penIsDown=true;this.color=color(128);this.weight=1;this.left=function(d){this.angle-=d};this.right=function(d){this.angle+=d};this.forward=function(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;var newy=this.y+sin(rad)*p;this.goto(newx,newy)};this.back=function(p){this.forward(-p)};this.penDown=function(){this.penIsDown=true};this.penUp=function(){this.penIsDown=false};this.goto=function(x,y){if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);line(this.x,this.y,x,y)};this.x=x;this.y=y};this.distanceTo=function(x,y){return sqrt(sq(this.x-x)+sq(this.y-y))};this.angleTo=function(x,y){var absAngle=degrees(atan2(y-this.y,x-this.x));var angle=((absAngle-this.angle)+360)%360.0;return angle};this.turnToward=function(x,y,d){var angle=this.angleTo(x,y);if(angle<180){this.angle+=d}else{this.angle-=d}};this.setColor=function(c){this.color=c};this.setWeight=function(w){this.weight=w};this.face=function(angle){this.angle=angle}}


var turtle;
function setup() {
    createCanvas(400, 400);
    background(0);
    turtle = new Turtle(190, 200);
}

function draw() {
    turtle.penDown();
    turtle.setColor(255);
    turtle.forward(150);
    turtle.right(141.5);
    turtle.forward(60);
    if (frameCount % 20 === 0) {
        turtle.forward(70);
    }
    if (frameCount > 1000) {
        noLoop();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var t1, t2, t3;
 
function setup() {
    createCanvas(600, 600);
    background(0);
    t1 = new Turtle(width/2 + random(-100, 100), height/2 + random(-100, 100));
    t2 = new Turtle(width/2 + random(-100, 100), height/2 + random(-100, 100));
    t3 = new Turtle(width/2 + random(-100, 100), height/2 + random(-100, 100));
    t1.penDown();
    t1.setColor(color(255, 0, 0));
    t1.setWeight(3);
    t2.penDown();
    t2.setColor(color(0, 255, 0));
    t2.setWeight(3);
    t3.penDown();
    t3.setColor(color(100, 100, 255));
    t3.setWeight(3);
}
 
function draw() {
    t1.forward(1);
    t2.forward(2);
    t3.forward(3);
    var targetX = width * noise(frameCount / 1000);
    var targetY = height * noise(100 + frameCount / 1000);
    strokeWeight(1);
    stroke(128);
    point(targetX, targetY);
    t1.turnToward(targetX, targetY, 1);
    t2.turnToward(targetX, targetY, 1);
    t3.turnToward(targetX, targetY, 1);
    t1.left(random(-5, 5));
    t2.left(random(-5, 5));
    t3.left(random(-5, 5));
}

Turtle Implementation

Caution: there’s an ampersand-LT-semicolon (escaped html less-than symbol) in this code instead of < because of an apparent bug in the pre tag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Turtle(x, y) -- make a turtle at x, y, facing right, pen down
// left(d) -- turn left by d degrees
// right(d) -- turn right by d degrees
// forward(p) -- move forward by p pixels
// back(p) -- move back by p pixels
// penDown() -- pen down
// penUp() -- pen up
// goto(x, y) -- go straight to this location
// setColor(color) -- set the drawing color
// setWeight(w) -- set line width to w
// face(d) -- turn to this absolute direction in degrees
// angleTo(x, y) -- what is the angle from my heading to location x, y?
// turnToward(x, y, d) -- turn by d degrees toward location x, y
// distanceTo(x, y) -- how far is it to location x, y?
//
function Turtle(x, y) {
    this.x = x;
    this.y = y;
    this.angle = 0.0;
    this.penIsDown = true;
    this.color = color(128);
    this.weight = 1;
 
    this.left = function(d) {
        this.angle -= d;
    }
 
    this.right = function(d) {
        this.angle += d;
    }
 
    this.forward = function(p) {
        var rad = radians(this.angle);
        var newx = this.x + cos(rad) * p;
        var newy = this.y + sin(rad) * p;
        this.goto(newx, newy);
    }
 
    this.back = function(p) {
        this.forward(-p);
    }
 
    this.penDown = function() {
        this.penIsDown = true;
    }
 
    this.penUp = function() {
        this.penIsDown = false;
    }
 
    this.goto = function(x, y) {
        if (this.penIsDown) {
            stroke(this.color);
            strokeWeight(this.weight);
            line(this.x, this.y, x, y);
        }
        this.x = x;
        this.y = y;
    }
 
    this.distanceTo = function(x, y) {
        return sqrt(sq(this.x - x) + sq(this.y - y));
    }
 
    this.angleTo = function(x, y) {
        var absAngle = degrees(atan2(y - this.y, x - this.x));
        var angle = ((absAngle - this.angle) + 360) % 360.0;
        return angle;
    }        
 
    this.turnToward = function(x, y, d) {
        var angle = this.angleTo(x, y);
        if (angle &lt; 180) {
            this.angle += d;
        } else {
            this.angle -= d;
        }
    }
 
    this.setColor = function(c) {
        this.color = c;
    }
 
    this.setWeight = function(w) {
        this.weight = w;
    }
 
    this.face = function(angle) {
        this.angle = angle;
    }
}