Hoops (Processing + Arduino)

 

 

 

 

 

 

 

 

I decided to make a controller that would draw circles which would then distort randomly.

The controller creates an instance of a Hoop by switching the toggle to on. A circle appears. By turning the large POT (10k) you control the size of the circle (and the size is also a colour variable). If you then toggle the switch off, the Hoop comes to life. The small blue pot controls how quickly the hoop distorts (the blue pot is also a colour variable). If you repeat the toggling and sizing you eventually create a hypnotic series of hoops. One added variable is the ambient light (same sensor I used last week: TEMT6000) the brighter it is, the brighter the hoops will be.

Programming the Arduino to send out the data from the 2 POTS, the ambient light sensor, and the switch was easy enough… but I needed help getting processing to read the serial data. I decided to borrow code from the Virtual Color Mixer example included in the Arduino examples. I had to format my serial data by separating them with commas. Processing then reads the serial data and directs each number separated by a comma to the variables I created to feed the data in to my sketch.

http://vimeo.com/31510916

Here is the processing sketch I made and then modified to accept the incoming serial data. Click to create a circle.

Arduino code:

// Hoops (Arduino + Processing)
// Marc De Pape
//
// Creation and Computation
// OCAD University
//
// November 2 2011
//
// Part: http://www.sparkfun.com/products/8688
// Reports the analog reading of the TEMT6000
// Article: http://bildr.org/2011/06/temt6000_arduino/
//
// Sensors: 2 POTS, 1 Toggle Switch, and one TEMT6000 Ambient light sensor

const int temt6000Pin = A0; // TEMT6000 Ambient Light Sensor
const int pot1rate = A1; // Blue POT
const int pot2size = A2; // 10K POT
const int switchPin = 2; // Toggle Switch

void setup(){
  Serial.begin(9600);
  pinMode(switchPin, INPUT);
}

void loop(){

  float STATE = readSwitch();
  Serial.print(STATE);
  Serial.print(",");

  float RATE = readPot1rate();
  Serial.print(RATE);
  Serial.print(",");

  float SIZE = readPot2size();
  Serial.print(SIZE);
  Serial.print(",");

  float AMBIENT = readTEMT600();
  Serial.println(AMBIENT);

}

// READ Ambient Sensor
float readTEMT600(){
  float light = analogRead(temt6000Pin);
  return light;
}

float readSwitch() {
  float state = digitalRead(switchPin);
  return state;
}

float readPot1rate() {
  float reading = analogRead(pot1rate);
  return reading;
}

float readPot2size() {
  float reading = analogRead(pot2size);
  return reading;
}

Processing code:

// Hoops (Arduino + Processing)
// Marc De Pape
// 
// Creation and Computation
// OCAD University
// 
// November 2 2011
//
// SERIAL INPUT BASED ON http://arduino.cc/en/Tutorial/VirtualColorMixer

import processing.serial.*;  

Serial myPort;

float state = 0; // serial switch
float POT1rate = 0; // serial POT 1 controlling distortion rate
float POT2size = 0; // serial POT 2 controlling circle size
float LDRbright = 0; // serial ambient light sensor controlling brightness

int counter = 0; // used to ensure analog switch acts digitally

int numHoops=0; // Number of hoops initiated

Hoop[] hoopArray = new Hoop[100]; // Hoop array storing all the hoop info

//--------------------------------------------------------------------------- 
// HOOP CLASS

class Hoop {

  // HOOP VARIABLES

  float x; 

  float y; 

  float cirSizeX;

  float cirSizeY;

  float startSize;

  float randomExpansionX;

  float randomExpansionY;

  float colour;

  float rate;

  boolean expansionDirectionX;

  boolean expansionDirectionY;

  // INITIATE HOOP CLASS

  Hoop ( int x, int y, float cirSizeX, float cirSizeY, boolean expansionDirectionX, boolean expansionDirectionY, float startSize) {

    // here, "this" refers to an instance of the Hoop class by using this, we are saving the properties "locally" on each instances..

    this.x = x;

    this.y = y;

    this.cirSizeX = cirSizeX;

    this.cirSizeY = cirSizeY;

    this.startSize = startSize;

    this.colour = colour;

    this.randomExpansionX = randomExpansionX;

    this.randomExpansionY = randomExpansionY;

    this.expansionDirectionX = expansionDirectionX;

    this.expansionDirectionY = expansionDirectionY;

    this.rate = rate;
  }

  // Hoop function controlling distortion

  void sizeFlux() {

    if (this.cirSizeX <= this.startSize) {

      this.randomExpansionX = random(startSize/5, startSize/2); // SET EXPMANSION SIZE FOR X
      this.expansionDirectionX = true;
    }


    if (this.cirSizeY <= this.startSize) {

      this.randomExpansionY = random(startSize/5, startSize/2); // SET EXPANSION SIZE FOR Y
      this.expansionDirectionY = true;
    }

    // MAXIMUM EXPANSION DIRECTION CHECK X
    if (this.cirSizeX >= (this.startSize + this.randomExpansionX)) {
      this.expansionDirectionX = false;
    }

    // MAXIMUM EXPANSION DIRECTION CHECK Y
    if (this.cirSizeY >= (this.startSize + this.randomExpansionY)) {
      this.expansionDirectionY = false;
    }

    // HOOP SIZE CHANGE X
    if (this.expansionDirectionX == true) {

      this.cirSizeX = this.cirSizeX + POT1rate;
    } 
    else {

      this.cirSizeX = this.cirSizeX - POT1rate;
    }

    // HOOP SIZE CHANGE Y
    if (this.expansionDirectionY == true) {

      this.cirSizeY = this.cirSizeY + POT1rate;
    } 
    else {

      this.cirSizeY = this.cirSizeY - POT1rate;
    }
  }

  // Hoop function which sets the initial properties of circle size and colour for a Hoop instance
  void circleSettings(float cirSize, float POTrate) {
    this.cirSizeX = cirSize;
    this.cirSizeY = cirSize;
    this.startSize = cirSize;
    this.colour = map(cirSize, 0, height/2, 25, 225); // Circle size being used to control collour values
    this.rate = map(POTrate, 0, 15, 15, 150); // Current distortion rate being used to control colour values
  }

  // Hoop function for drawing the hoops
  void circleDraw(float bright) {
    //noFill();
    fill(this.colour, this.rate, this.colour/this.rate, bright/50);
    strokeWeight(map(this.startSize, 0, height, 1, 4));
    stroke(this.colour, this.rate, this.colour/this.rate, bright);
    ellipse(this.x, this.y, this.cirSizeX, this.cirSizeY);
  }
}

//
//-----------------------------------------------------------------

void setup() {
  size(960, 540);
  smooth();
  colorMode(RGB, 255);
  ellipseMode(CENTER);
  // List all the available serial ports
  println(Serial.list());
  // I know that the first port in the serial list on my mac
  // is always my  Arduino, so I open Serial.list()[0].
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[0], 9600);
  // don't generate a serialEvent() unless you get a newline character:
  myPort.bufferUntil('\n');
}

void draw() {
  background(0);
  drawSwitch();
  for (int i=0; i<numHoops; i++) {
    // constantly update the hoop and re-draw it
    hoopArray[i].circleDraw(LDRbright);
    hoopArray[i].sizeFlux();
  }
  //  print(state);
  //  print(",");
  //  print(POT1rate);
  //  print(",");
  //  print(POT2size);
  //  print(",");
  //  println(LDRbright);
}

// FUNCTIONS

void drawSwitch() {
  if (state == 1) {
    counter++;

    // I WANT MY SWITCH TO BEHAVE LIKE A MOUSEPRESSED, SO I NEED TO MAKE SURE THE ON STATE DOESN'T PRODUCE CONTINUOUS HOOP INSTANCES
    if (counter == 1) { 
      hoopArray[numHoops++] = new Hoop(width/2, height/2, POT2size, POT2size, false, false, POT2size);
    }

    // SET THE VALUES FOR THE LATEST HOOP
    hoopArray[numHoops-1].circleSettings(POT2size, POT1rate);
    hoopArray[numHoops-1].circleDraw(LDRbright);
  } 
  else {
    // RESET THE COUNTER
    counter = 0;
  }
}

// Incoming serial Arduino data
void serialEvent(Serial myPort) { 
  // get the ASCII string:
  String inString = myPort.readStringUntil('\n');

  if (inString != null) {
    // trim off any whitespace:
    inString = trim(inString);
    // split the string on the commas and convert the 
    // resulting substrings into an integer array:
    float[] controls = float(split(inString, ","));
    // if the array has at least three elements, you know
    // you got the whole thing.  Put the numbers in the
    // color variables:
    if (controls.length >=4) {
      // map them to the range 0-255:
      state = controls[0]; // SWITCH DATA
      POT1rate = map(controls[1], 0, 1023, 0, 15); // POT 1 DATA 
      POT2size = map(controls[2], 0, 1023, 0, height-(height/5)); // POT 2 DATA
      LDRbright = map(controls[3], 0, 0123, 10, 250); // AMBIENT LIGHT DATA
    }
  }
}
 

Comments are closed.