Interactive particle system with Ardiuno and Processing
December 1, 2011
Quickly threw this together when I got home from work. Pretty impressive (if you ask me!) considering I’m a novice with both Processing and Arduino.
Demo
The LEDs on the Arduino let you read out the light level (read as an 8-bit binary number) so that the more light that the photosensor receives, the higher the number represented on the LEDs will be. It then spits the number down a serial connection which controls the background colour and the starting position of the particles with Processing.
I see lots of weird and wonderful interactive art projects on the horizon… I’ve clearly got loads of Processing to learn to make something awe-inspiring, but I already have interesting ideas for the Arduino part including getting it to update with a Wii controller or based on your proximity to it. Maybe hook up a couple of sensors so that you can wave your arms around to generate the art?
Also, it’ll be fun to find out what kinds of thing can be generated – particles, fractals, trees. Let’s see just how creative I can get with this stuff :D
Arduino code
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 |
int data = 2; int clock = 3; int latch = 4; int sensor = A0; int ledState = 0; const int ON = HIGH; const int OFF = LOW; void setup() { pinMode(data, OUTPUT); pinMode(clock, OUTPUT); pinMode(latch, OUTPUT); Serial.begin(9600); } void loop() { int colour = map(analogRead(sensor), 0, 1023, 255, 0); Serial.print(colour); Serial.print(","); updateLevel(colour); } void updateLevel(int value){ digitalWrite(latch, LOW); shiftOut(data, clock, MSBFIRST, value); digitalWrite(latch, HIGH); } |
Processing code
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
import processing.serial.*; ParticleSystem ps; Serial port; PFont font; String inString = "0"; void setup () { size (1280, 800); port = new Serial(this, Serial.list()[0], 9600); font = loadFont ("SansSerif-48.vlw"); ps = new ParticleSystem(1, new PVector(width/2,height/2,0)); textFont (font, 48); port.bufferUntil(44); } void draw () { Float f = Float.valueOf(inString).floatValue(); background(f, 255 - f*2.0, f*5.0); text("light level: " + inString, 10, 50); ps.run (); ps.addParticle(map(f, 0, 255, 0, width), map(f, 0, 255, 0, height)); } void serialEvent (Serial port) { inString = port.readString(); inString = inString.substring(0,inString.length()-1); } // Particle system from the prototype documentation page: // http://processing.org/learning/topics/simpleparticlesystem.html class ParticleSystem { ArrayList particles; // An arraylist for all the particles PVector origin; // An origin point for where particles are born ParticleSystem(int num, PVector v) { particles = new ArrayList(); // Initialize the arraylist origin = v.get(); // Store the origin point for (int i = 0; i < num; i++) { particles.add(new Particle(origin)); // Add "num" amount of particles to the arraylist } } void run() { // Cycle through the ArrayList backwards b/c we are deleting for (int i = particles.size()-1; i >= 0; i--) { Particle p = (Particle) particles.get(i); p.run(); if (p.dead()) { particles.remove(i); } } } void addParticle() { particles.add(new Particle(origin)); } void addParticle(float x, float y) { particles.add(new Particle(new PVector(x,y))); } void addParticle(Particle p) { particles.add(p); } // A method to test if the particle system still has particles boolean dead() { if (particles.isEmpty()) { return true; } else { return false; } } } class Particle { PVector loc; PVector vel; PVector acc; float r; float timer; // Another constructor (the one we are using here) Particle(PVector l) { acc = new PVector(0,0.05,0); vel = new PVector(random(-1,1),random(-2,0),0); loc = l.get(); r = 10.0; timer = 100.0; } void run() { update(); render(); } // Method to update location void update() { vel.add(acc); loc.add(vel); timer -= 1.0; } // Method to display void render() { ellipseMode(CENTER); stroke(255,timer); fill(100,timer); ellipse(loc.x,loc.y,r,r); displayVector(vel,loc.x,loc.y,10); } // Is the particle still useful? boolean dead() { if (timer <= 0.0) { return true; } else { return false; } } void displayVector(PVector v, float x, float y, float scayl) { pushMatrix(); float arrowsize = 4; // Translate to location to render vector translate(x,y); stroke(255); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) line(0,0,len,0); line(len,0,len-arrowsize,+arrowsize/2); line(len,0,len-arrowsize,-arrowsize/2); popMatrix(); } } |
Schematic
(Ummm, anyone know of a decent programme to draw these with?!)