Lights of Constellation

IMG_2002

That is what my final project looks like at the December showcase.

Overview

The project is called Lights and Constellation, a very straightforward representation of what the thing does: Mapping a png image of constellations on the computer screen to the physical board of lights. The whole thing consists of four units: 1) Computer screen, key and mouse, 2) Physically acrylic board and LEDs, 3) the speaker, and 4) Scott’s powerful battery.

Each part looks like this respectively:

Screenshot
Computer screen control

 

IMG_2018
The front of the light board (You can take a selfie with it!)

 

IMG_2016
Back of the board (So wireyyy)

 

IMG_2017
Zoom in to the wire of one constellation(Power: Red Wire & Ground: Green Wire)

 

IMG_2015
Transistor on the breadboard

 

Da lab speaker
Da lab speaker that plays recorded space sound!

 

Scott's battery powers the whole thing thank you!
Scott’s battery powers the whole thing thank you!

 

In combination, they work like this:

A short video at the show: All lights on at the showcase

A lengthy one on vimeo:

Here’s my code. 

Arduino:

int ledPin[] = {3, 5, 6, 9, 10, 11};

byte brightness[6];
int blinkInterval[6];

void setup() {
  pinMode(ledPin[0], OUTPUT);
  pinMode(ledPin[1], OUTPUT);
  pinMode(ledPin[2], OUTPUT);
  pinMode(ledPin[3], OUTPUT);
  pinMode(ledPin[4], OUTPUT); 
  pinMode(ledPin[5], OUTPUT);

  Serial.begin(9600);
}

void loop() {
  if (Serial.available() == 12) {
    brightness[0] = Serial.read();
    blinkInterval[0] = Serial.read();
    brightness[1] = Serial.read();
    blinkInterval[1] = Serial.read();
    brightness[2] = Serial.read();
    blinkInterval[2] = Serial.read();
    brightness[3] = Serial.read();
    blinkInterval[3] = Serial.read();
    brightness[4] = Serial.read();
    blinkInterval[4] = Serial.read();
    brightness[5] = Serial.read();
    blinkInterval[5] = Serial.read();
  }

  for (int i = 0; i <= 5; i++) {
    analogWrite(ledPin[i], brightness[i]);
    delay(blinkInterval[i]);
    analogWrite(ledPin[i], 0);
    delay(blinkInterval[i]);
    analogWrite(ledPin[i], brightness[i]);
  }
}

Processing:

import processing.serial.*;
import ddf.minim.*;
Serial myPort; 
Minim minim;
AudioPlayer player;
AudioPlayer blink;

Slider blSlider, brSlider;

PImage consTa; 
PFont AmericanType; 

int whatConst;  
float[] brightness = new float[6];
float [] blinkRate = new float[6];

void setup() {
  fullScreen();
  //size(1200, 1200);
  //myPort = new Serial(this, "/dev/cu.RNBT-AC28-RNI-SPP", 38400);
  myPort = new Serial(this, "/dev/cu.usbserial-DA01LJIV", 9600);

  minim = new Minim(this);
  player = minim.loadFile("SpaceSound.mp3");
  blink = minim.loadFile("Ding.mp3");

  blSlider = new Slider(1200, 180, 200, 0, 1000);
  brSlider = new Slider(1200, 280, 200, 0, 255);
}

void draw() {
  background(100);

  consTa = loadImage("constellation1.png");
  imageMode(CENTER);
  image(consTa, width/2, height/2); 

  AmericanType = loadFont("AmericanTypewriter-30.vlw");
  textFont(AmericanType);
  text("Blinky", 1200, 150);
  text("Brightness", 1200, 250);
  textSize(20);
  fill(255);
  text("Click on the underlined constellation(s) first!", 30, 50);
  text("Click after you drag!", 1200, 50);

  strokeWeight(3); // draw the lines that indicate the lighted constellations 
  stroke(255);
  line(150, 55, 255, 55);
  line(815, 231, 858, 231);
  line(693, 250, 725, 250);
  line(340, 355, 362, 355);
  line(820, 553, 867, 553);
  line(943, 765, 990, 765);  
  line(596, 575, 657, 576);
  line(696, 560, 728, 560);
  line(492, 745, 517, 745);
  line(570, 785, 606, 785);

  brSlider.render();
  blSlider.render();
  brSlider.update();
  blSlider.update();
  brSlider.reStrain();
  blSlider.reStrain();

  if (whatConst == 6) {
    brightness[0] = brSlider.getVal();
    blinkRate[0] = blSlider.getVal();

    println("current br:" + brightness[0]);
    println("current bl:" + blinkRate[0]);
  }

  if (whatConst == 5) {
    brightness[1] = brSlider.getVal();
    blinkRate[1] = blSlider.getVal();

    println("current br:" + brightness[1]);
    println("current bl:" + blinkRate[1]);
  }

  if (whatConst == 4) {
    brightness[2] = brSlider.getVal();
    blinkRate[2] = blSlider.getVal();

    println("current br:" + brightness[2]);
    println("current bl:" + blinkRate[2]);
  }

  if (whatConst == 3) {
    brightness[3] = brSlider.getVal();
    blinkRate[3] = blSlider.getVal();

    println("current br:" + brightness[3]);
    println("current bl:" + blinkRate[3]);
  }

  if (whatConst == 2) {
    brightness[4] = brSlider.getVal();
    blinkRate[4] = blSlider.getVal();

    println("current br:" + brightness[4]);
    println("current bl:" + blinkRate[4]);
  }

  if (whatConst == 1) {
    brightness[5] = brSlider.getVal();
    blinkRate[5] = blSlider.getVal();

    println("current br:" + brightness[5]);
    println("current bl:" + blinkRate[5]);
  }
}

void mousePressed() {
  if (((mouseX > 680) && (mouseX < 765) && (mouseY > 200) && (mouseY < 385)) || ((mouseX > 695) && (mouseX < 885) && (mouseY > 300) && (mouseY < 420))) {
    whatConst = 6;
    blink.play();
  }
  if ((mouseX > 805) && (mouseX < 880) && (mouseY > 163) && (mouseY < 297)) {
    whatConst = 5;
    blink.rewind();
    blink.play();
  }
  if ((mouseX > 295) && (mouseX < 433) && (mouseY > 280) && (mouseY < 390)) {
    whatConst = 4;
    blink.rewind();
    blink.play();
  }
  if (((mouseX > 742) && (mouseX < 925) && (mouseY > 458) && (mouseY < 685)) || ((mouseX > 868) && (mouseX < 1020) && (mouseY > 670) && (mouseY < 805))) {
    whatConst = 3;
    blink.rewind();
    blink.play();
  }
  if ((mouseX > 575) && (mouseX < 760) && (mouseY > 510) && (mouseY < 620)) {
    whatConst = 2;
    blink.rewind();
    blink.play();
  }
  if ((mouseX > 433) && (mouseX < 687) && (mouseY > 685) && (mouseY < 870)) {
    whatConst = 1;
    blink.rewind();
    blink.play();
  }

  myPort.write(int(brightness[0]));
  myPort.write(int(blinkRate[0]));
  myPort.write(int(brightness[1]));
  myPort.write(int(blinkRate[1]));
  myPort.write(int(brightness[2]));
  myPort.write(int(blinkRate[2]));
  myPort.write(int(brightness[3]));
  myPort.write(int(blinkRate[3]));
  myPort.write(int(brightness[4]));
  myPort.write(int(blinkRate[4]));
  myPort.write(int(brightness[5]));
  myPort.write(int(blinkRate[5]));
}

void keyPressed() {
  if ( player.isPlaying()) { 
    player.pause();
  } else if ( player.position() == player.length() ) {
    player.rewind();
    player.play();
  } else {
    player.play();
  }
}

//The Slider Class
class Slider {

 float initX, setY;
 float xPos;
 float xLength;
 float dotSize = 12;
 float highVal, lowVal, curVal;

 Slider(float iX, float y, float range, float lVal, float hVal) {
   initX = iX;
   setY = y;
   xLength = range;
   highVal = hVal;
   lowVal = lVal;
 }

 void render() {
   fill(150);
   stroke(150);
   strokeWeight(8);
   line(initX, setY, initX+xLength, setY);
   ellipse(xPos, setY, dotSize, dotSize);
 }

 void update() {
   if (mousePressed == true) {
     if ((mouseX >= initX) && (mouseX <= initX+xLength) && (mouseY >= setY-dotSize) && (mouseY <= setY+dotSize)) {
       xPos = mouseX;
     }
   }
 }
 
 void reStrain() {
  if (xPos < initX) {
   xPos = initX;
  } else if (xPos > initX + xLength) {
   xPos = initX + xLength; 
  }
 }

 float getVal() {
   curVal = map(xPos, initX, initX+xLength, lowVal, highVal);
   return curVal;
 }
}

Some thoughts on the project:

Before starting to make this light thing, I had a “grand vision” for it. I wanted it to look magical, and function magical just as the actual constellations. The idea was to use the click of the mouse to light the “stars” up and shut them down. I achieved half the original goal in the end, with the additional function of adjusting the brightness and blink rate of the constellations. The hardest part for me are two things. First, making serial communication work between processing and arduino is unexpectedly hard for me. I tested several ways of making them talk to each other, only the last one works. Second, laser cutting the physical board and attaching LEDs to their proper positions and wiring them all up takes the largest bulk of time and workload for this project. The extremely bright LEDs that Scott recommended work really well —- They shine like stars without any extra shields/caps on them. The extremely toxic-smelled chemical that makes the two halves of the board stick together works well too (and I got to wear the professional-looking mask during the process yah!). I think I learned a bit more about both the software and hardware part during this final project, and it feels great to introduce others at the show to your own work. That makes the time and effort all worth it.

If I have time (and battery) to again finalise the whole board I will hang it on the wall of my dorm room. The heritage of this course!

Again thanks Scott and Diana for helping me with coding and creating the physical board.

Leave a Reply