Skip navigation

…the code

This page will explain in detail how our codes work. For this reason we divided it in three parts: Processing code, Arduino code and how Arduino communicates with Processing. See how it will work there.

Processing code

bloom code screenshoot

The main aim of the Processing code is creating an animation in which different objects interact with each other.
We created two classes for the objects: lilies (Lilly class) and ripples (Ring class).
Both Lilly and Ring’s objects have their own qualities that I will explain below.

LILIES

Our lilies are drawn by the ‘display‘ function and are made of a transparent ellipse upon which an image of a lily is drawn: this image changes (’loadImages‘ function) in order to give the impression of the rotation of the lily. The lily’s diameter is given by a random number between 60 and 100 (pixel) in order to build a various and rich pattern by repeating the same object.

void display(){
noFill();
strokeWeight(1);
stroke(0,10);
ellipse(x,y,d,d);
if ((countimage<1)||(countimage>11)){
costantimage = costantimage * -1;}
countimage = countimage + costantimage;
image(ani[int(countimage)],x-d/2,y-d/2, d,d);}

void loadImages() {
for(int i=1; i<13; i++) {
String imageName = “ninfea” + i + “.png”;
ani[i-1] = loadImage(imageName);}}

Lilies have speeds for their movements on the x and y axes, that change from lily to lily.
They will drift far from the jetty with a constant speed , while they are creating random paths along the y-axe.
Lilies bounce on the top and bottom side of the window and when they reach the left edge of the window their speedX is turn in null.

void movement(){
if(y <= r || y >= (height-r)) {
speedY = speedY * -1;}
y = y + speedY;
counter ++;
if(counter > rangeY){
counter = 0;
speedY = speedY * -1;
rangeY = random(200,height/2);}
if(x > r){
x = x - speedX;}}

Lilies bounce also when they hit another lily, changing their speedY. Moreover when they hit each other they will make a new ripple starting from their x and y coordinates.

void checkHit(){
for(int y = 0; y<lilly.length; y++){
testLilly = (lilly[y]);
for(int x = 0; x<lilly.length; x++){
testLilly2 = (lilly[x]);
if(testLilly != testLilly2){
float Ydist=abs(testLilly.y - testLilly2.y);
float Xdist=abs(testLilly.x - testLilly2.x);
if(Ydist<=((testLilly.d)/2 + (testLilly2.d)/2) && Xdist <= (testLilly.d/2 + testLilly2.d/2)){
testLilly.speedY = testLilly.speedY * -1;
addRing(testLilly.x,testLilly.y,testLilly.d+10,50);}}}}}

Finally our lilies interact with ripples: infact when they are hit by a ripple they will make a sound (’sound‘ function) and a new, little ripple.

void checkIntersect(){
for(int i=0; i<rings.length; i++) {
Object ir = this.intersect(this, rings[i]);
if (ir != null){
m = millis() + 1000;
sound();
addRing(x,y,(rings[i].dt-rings[i].d)/2,rings[i].alph-10);}}
}
Object intersect( Lilly cA, Ring cB ) {
float dx = cA.x - cB.x;
float dy = cA.y - cB.y;
float d2 = dx*dx + dy*dy;
float d = sqrt( d2 );
if ( d>cA.r +cB.r || d<abs(cA.r-cB.r) ) {
return null; // no intersect}
float a = (cA.d - cB.d + d2) / (2*d);
float h = sqrt( cA.d - a*a );
float x2 = cA.x + a*(cB.x - cA.x)/d;
float y2 = cA.y + a*(cB.y - cA.y)/d;
float paX = x2 + h*(cB.y - cA.y)/d;
float paY = y2 - h*(cB.x - cA.x)/d;
float pbX = x2 - h*(cB.y - cA.y)/d;
float pbY = y2 + h*(cB.x - cA.x)/d;
return cB;}

void sound(){
float randomSound = int(random(2,4));
if(randomSound==2){
lilly2Sample.trigger();}
else if(randomSound==3){
lilly3Sample.trigger();}
else if(randomSound==4){
lilly4Sample.trigger();}}

RIPPLES
Our prototype will display six different ripples: they will start from three different points on the jetty’s edge and can be big or little depending on which sensor will be pressed. They have a starting alpha value and they will enlarge (’grow‘ function) and get more transparent (’display‘ function) at the same time.

void grow(){
if (grow == true){
d += random(4,7);
r = d/2;
if(d>dt){
grow=false;}}}
void display(){
noFill();
strokeWeight(3);
al = al - (0.5 + (1000/dt));
if (al <= 0){
visible=false;}
else{
stroke(255, al);
ellipse(x, y , d, d);}
noStroke();}

MAIN CODE
In the main code we principally created the function that simulates the creations of the ripples and lilies, using keys instead of sensors:

void keyPressed(){
//centered big ripples
if(key==’s’||key==’S'){
if(t < millis()){
addRing(760, height/2, 1000, random(100,255));
ripple5Sample.trigger();
t = millis() + 500;}}

In this case, pressing “s” on the keyboard a big, central ripple will appear. 875 and 158 are its coordinates, 1000 is its maximum diameter and random(100,255) is its initial alpha value (we used the same function for all the ripples, the right keys are a,s,d for the bigger ones and z,x,c for the smaller ones).
In the final version of the code, this function is replaced with the one that receives data from sensors:

if( serialValue == 1 ){
addRing(
760, height/2, 1000, random(100,255));
rippleSample.trigger();}

This is the function that simulate the creation of new lilies. In the real version of our installation this function would be controlled by a camera tracking that will check if someone is arrived on the jetty and send this datum to the computer that will create a new lily.
The function checks if there is at least one projected lily: if not the new lily will have random coordinates, else it calls the ‘checkBornPlacefunction, which checks that the new lilies won’t appear over old ones.

//creates new lilies
if(key==’l'||key==’L'){
calculateXY();
//if there is at least one lily, the checkBornPlace function has to check that a new lily won’t appear over an old one
if(lilly.length>0){
checkBornPlace();}
else {
addLilly(coordX, coordY, diameter);}}


void checkBornPlace(){
int j = 1;
while(j==1){
int makeLillyFlag = 1;
for(int i=0; i<lilly.length; i++){
checkLilly = (lilly[i]);
radius = checkLilly.d / 2;
float distance = radius + diameter/2;
minXvalue = checkLilly.x - distance;
maxXvalue = checkLilly.x + distance;
minYvalue = checkLilly.y - distance;
maxYvalue = checkLilly.y + distance;
if(((coordX < minXvalue) || (coordX > maxXvalue)) || ((coordY < minYvalue) || (coordY > maxYvalue))){}
else{
calculateXY();
makeLillyFlag = 0;}}
if (makeLillyFlag==1){
// get out of the while loop
j=0;}}
addLilly(coordX, coordY, diameter);}
void calculateXY(){
coordX = random(450,width-326);
coordY = random(51,height-51);
diameter = random(60,100);}

Arduino code

pin

The pressure sensors are linked to seven pins on the Arduino board.
The main function of this code is reading the data that the sensors send.

Here we declared the ‘variables’:

int ledPin = 13; // choose the pin for the LED
int inputPin1 = 2; // choose the input pin (for a pushbutton)
int lastPin1 = 0;
int inputPin2 = 3;
int lastPin2 = 0;
int inputPin3 = 4;
int lastPin3 = 0;
int inputPin4 = 5;
int lastPin4 = 0;
int inputPin5 = 6;
int lastPin5 = 0;
int inputPin6 = 7;
int lastPin6 = 0;

In the ’setup’ function we set the serial port to communicate between the Arduino and Processing (the port will have a speed of 9600 bit per second) and the data sent from the pressure sensors as our inputs.

pinMode(ledPin, OUTPUT);
Serial.begin(9600);
pinMode(inputPin1, INPUT);

In the ‘loop’ function below we declare the condition for the input reading by the pins:

if (val != lastPin1) { // check if the input is HIGH
lastPin1 = val;
if (val == HIGH ) {
digitalWrite (ledPin, HIGH);
serialWrite (1);
} else {
digitalWrite (ledPin, LOW);
serialWrite(’a');
}
}

We repeat these conditions for all the pins.

How Processing reads input data?

Processing + Arduino

In the Processing code we set these variables for opening the serial port and for reading the values:

import processing.serial.*;
Serial port;
int serialValue;
int[] dataArray = new int[6];
int index = 0;

In the ‘setup‘ function we set the serial port:

port = new Serial(this, Serial.list()[1], 9600);

Then we created the ‘checkSerial‘ function where we said to Processing how to read the input data:

void checkSerial() {
if (port.available() > 0) { // if data is available
serialValue = port.read();
println(serialValue);
port.clear();// read it and store it in serialValue
if (serialValue == 255){ // look for end byte (255)
index = 0;
}
else {
dataArray[index] = serialValue;
index = index + 1;
if (index > (dataArray.length-1)) {
index = 0;
}
}
}
ripples(); //recall the ripples function
}

‘ripples();’ recalls the ‘ripples‘ function where we set the condition in which a new ripple will appear:

if( serialValue == 1 ){
addRing(
760, height/2, 1000, random(100,255));
rippleSample.trigger();
}

bloom | more | context | design | tech | prototype | code | considerations | credits | downloads