Lit up cloud

Lit up cloud

Clouds by Al, Sina & Noreen, Submitted on Dec. 7th, 2016

The installation is made up of three *clouds, which emit thunder sounds and lightning while moving up and down.  These are light responsive creatures, so when they are *fed with lights by flashing a light at them, they respond with rumbling and bright flashes.

Out objective was to make a fun, playful and interactive installation which could engage children and capture their imagination.

Internal structure of cloud

Internal structure of cloud

The clouds are fabricated using a cardboard structure which houses circuits and an arduino.  Each cloud contains 3 LED strips that are controlled by an Arduino UNO and powered by a single 12V power supply.  A photoresistor measures the ambient light when the Arduino starts up. The threshold value is then set 50 points higher so that it takes a brighter light source to activate the LED’s.

When the threshold limit is hit by shining a flashlight on the photoresistor, a ‘lightning animation’ is run by blinking the LED’s. A Serial.println(“thunder”) is also sent at this time to communicate with the Raspberry Pi that it’s time to play the audio.

The Arduino’s are connected to one Raspberry Pi via USB cables. On startup the Pi runs a python script which reads the serial input from the Arduinos and looks for the word “thunder” at which point it uses the ‘pygame’ library to play a WAV file.

Central gear and motion mechanism

Central gear and motion mechanism

The three clouds are attached to a central gear, which is fixed to a powerful motor.  As the motor rotates, the clouds are lifted up.  In turn, they are pulled down by their own weight.  Each component of the movement mechanism was laser cut after carefully calculating various sizes, including that of the motor itself.

Inspiration of this project was drawn from a piece of work by Richard Clarkson.    We drew inspiration for the movement of the clouds from this work (3:06 to 3:22) by Laurent Debraux.

Looking back at the project, a lot of things went well, and a lot of things went wrong.  For one thing the motion seemed to work fine on the clouds at an early stage of the project.  However, adding a lot of fluff increased the weight of the clouds, and the motor began to stall.  The motion did not go as expected.  Although we experimented with the look of the clouds, nothing seemed to look effective, and in the end we decided to leave them plain, without the eyes and arms which we had planned earlier.  The sound and lights worked just the way we had intended, and gave the impact which we had originally planned.

Al’s contribution to the project began with ideation and brainstorming.  He was responsible for getting the lights and the sound of the clouds to work.  He also figured out all the wiring, and got the basic cloud working.  Noreen’s role in the project was that of fabrication and figuring out the motion mechanism of the clouds.  She made the drawings and laser cut any parts needed for the project.  She also contributed in writing text for various blogs and documentation.  Sina  helped in the fabrication and wiring.

Circuit diagram:

20161205_110934

Circuit diagram

Link to pdf of cloud-drawings (click here)

Code for the serial import

import serial
import pygame
import time
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
pygame.mixer.init()
thunder1 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")
thunder2 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")
thunder3 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")

ser0 = serial.Serial('/dev/ttyACM0', 9600)
ser1 = serial.Serial('/dev/ttyACM1', 9600)
ser2 = serial.Serial('/dev/ttyACM2', 9600)
while True:
    blah0 = ser0.readline().rstrip()
    blah1 = ser1.readline().rstrip()
    blah2 = ser2.readline().rstrip() 
    if(blah0 == "thunder"):
        thunder1.play()
        print "thunder 1 is playing"
    if(blah1 == "thunder"):
        thunder2.play()
        print "thunder 2 is playing"
    if(blah2 == "thunder"):
        thunder3.play()
        print "thunder 3 is playing"

Thunder code (python):

import serial
import pygame
import time
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

pygame.mixer.init()
thunder1 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")
thunder2 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")
thunder3 = pygame.mixer.Sound("/home/pi/Desktop/thunder1.ogg")

ser0 = serial.Serial('/dev/ttyACM0', 9600)
ser1 = serial.Serial('/dev/ttyACM1', 9600)
ser2 = serial.Serial('/dev/ttyACM2', 9600)
while True:
    blah0 = ser0.readline().rstrip()
    blah1 = ser1.readline().rstrip()
    blah2 = ser2.readline().rstrip() 
    if(blah0 == "thunder"):
        thunder1.play()
        print "thunder 1 is playing"
    if(blah1 == "thunder"):
        thunder2.play()
        print "thunder 2 is playing"
    if(blah2 == "thunder"):
        thunder3.play()
        print "thunder 3 is playing"

Code for the Arduino:

//photoresistor A Style Tech.

//Cloud 1 variables
int sensor1 = 0; // will be used for analog 0.
int sensor1Threshold = 0; // value of when light is on
int sensor1Value = 0; // value of output
int brightness = 255;    // how bright the LED is
int ledStatus1 = 0; //0 off 1 on
const int LEDPIN = 6;
unsigned long currentTime;
unsigned long loopTime;
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)


//General Variables
int fadeAmount = 5;    // how many points to fade the LED by

void setup() {
  Serial.begin(9600 );
 // calibrate during the first five seconds 
 while (millis() < 2000) { sensor1Value = analogRead(sensor1); // Serial.print("so here it is sensor value: " ); // Serial.println(sensor1Value); // record the maximum sensor value if (sensor1Value > sensor1Threshold) {
     sensor1Threshold = sensor1Value + 60;
   }
 }
   
  currentTime = millis();
  loopTime = currentTime; 
  //Set blink cloud 1 to indicate calibration is done. Then set to off
  pinMode(LEDPIN, OUTPUT);
  analogWrite(LEDPIN, 1);
  delay(10);
  analogWrite(LEDPIN, 0);
}

void loop() {
//    unsigned long currentMillis = millis();
//  if (currentMillis - previousMillis >= interval) {
//    // save the last time you blinked the LED
//    previousMillis = currentMillis;

    Serial.println("shush");
//    }

  //Serial.println("shush");
  cloud1();
}
void cloud1(){
   //Check the photosensors value
  sensor1Value = analogRead(sensor1);
//  Serial.println(sensor1Value);

//If you are shining a light at the sensor
if (sensor1Value > sensor1Threshold) 
{

  //Lightning Animation
  if(ledStatus1 == 0){
    Serial.println("thunder");
  analogWrite(LEDPIN, 255);
  delay(120);
  analogWrite(LEDPIN, 0);
  delay(120);
    analogWrite(LEDPIN, 255);
  delay(200);
  analogWrite(LEDPIN, 0);
  delay(200);
      analogWrite(LEDPIN, 255);
    brightness = 255;
    ledStatus1 = 1;
  }
if(ledStatus1 == 1){
  analogWrite(LEDPIN, 255);
}
} 
if (sensor1Value < sensor1Threshold) { //If the sensor was previously uncovered then we need to do the fadeout if(ledStatus1 == 1){ //LED FADE OFF currentTime = millis(); if(currentTime >= (loopTime + 20)){  
    // set the brightness of pin 9:
    analogWrite(6, brightness);    

    // change the brightness for next time through the loop:
    brightness = brightness - fadeAmount;

    loopTime = currentTime;  // Updates loopTime

//        Serial.println(ledStatus1);

if(brightness == 0){
    ledStatus1 = 0;
    }
  }
    //Sensor has been covered so keep the light off
  if(ledStatus1 == 0){
    analogWrite(6, 0);
  }
  }
}
}