The Magical Cloud

For our final project, our team (Vitoria and Aya), decided to explore the idea of an artificial cloud that worked as a sort of weather gadget. By searching for the weather, you would get a visual representation of what the weather was.

Initial sketch for idea:

From the very beginning, it was clear that obtaining in real time weather updates that would stimulate several functions and actions would be very difficult and perhaps too time consuming to try and figure out. We decided early on that we would choose certain cities to program their weather into the code manually. This also led to a design choice for the digital aspect of the piece. We decided to create a map on screen where you could press on a city to trigger the response from the physical cloud.

We first started by designing and printing rain and snow shapes out of acrylic using a laser cutter. We tested the motion of the rain by attaching them to servos and coding their movements. Originally the shapes were attached to long sticks that were attached to the servos. However, we did not like how the movements were jerky instead of smooth. Also, the long sticks interfered with a lot of the design decisions and made the building process of the cloud more difficult. We then decided to create a yo-yo based system that would be attached to the servo and the shape and roll the shape up and down.

After managing the servos, we moved on to looking at the lights we wanted to use. We started with RGB LEDs, however, we realized that it was pointless to try and program a large number of LEDs. Instead, we decided to use neopixel strips based off of Aaron’s advice to us. This was easier in terms of coding, power, and design.

Then came the building process, which was being played with the whole time. We used a clothing rack as the foundational support. We then added shelves to it to support the Arduino board as well as the servos. The neopixel strips were draped over the steel rods. We used lanterns as the base for the cloud and used white glue to stick cotton on to them. They worked well because they already had the required structure so that the design wouldn’t interfere with the servos and lights.

After building the cloud and working the physical parts, we began to work on the digital aspect. This went relatively smoothly using processing. This definetly took the least time.

Hooking up processing to Arduino created a few challenges. Trying to run everything at once created a lot of lagging. However, we added an external power source and that helped.

Lastly, we added on-screen feedback and audio (because of the feedback we received in class).

Disclaimer: The coding process involved a lot of help from people around the lab, Aaron, and the internet.

Processing Code: 

import java.awt.Rectangle;
import ddf.minim.*;
import processing.serial.*;
Serial myPort; // Create object from Serial class

Minim minim;
AudioPlayer rain;
AudioPlayer lightrain;
AudioPlayer heavyrain;
AudioPlayer storm;
AudioPlayer snow;
AudioPlayer birds;

PImage img;
PFont font;
boolean newYorkPressed = false;
boolean shanghaiPressed = false;
boolean abuDhabiPressed = false;
boolean tokyoPressed = false;
boolean parisPressed = false;
boolean florencePressed = false;
boolean madridPressed = false;
boolean baPressed = false;
boolean havanaPressed = false;
boolean icePressed = false;
boolean capeTownPressed = false;
boolean rainSound = false;
boolean birdSound = false;
boolean heavyRain = false;
boolean lightRain = false;
boolean stormSound = false;
boolean snowySound = false;

Rectangle newyork;
Rectangle shanghai;
Rectangle abudhabi;
Rectangle tokyo;
Rectangle paris;
Rectangle florence;
Rectangle madrid;
Rectangle ba;
Rectangle havana;
Rectangle ice;
Rectangle capetown;

void setup() {
String portName = Serial.list()[3]; //change the 0 to a 1 or 2 etc. to match your port
myPort = new Serial(this, portName, 9600);
fullScreen();
img = loadImage(“hey.jpeg”);
font = loadFont(“Futura-CondensedExtraBold-48.vlw”);
newyork= new Rectangle(371, 313, 160, 50);
shanghai = new Rectangle(1090, 370, 160, 40);
abudhabi = new Rectangle(890, 412, 175, 50);
tokyo =new Rectangle(1232, 344, 110, 40);
paris = new Rectangle(695, 255, 110, 40);
florence = new Rectangle(725, 320, 130, 50);
madrid = new Rectangle(540, 308, 110, 45);
ba = new Rectangle(420, 723, 215, 50);
havana = new Rectangle(360, 420, 160, 40);
ice = new Rectangle(593, 153, 150, 50);
capetown = new Rectangle(755, 730, 290, 50);
minim = new Minim(this);
birds = minim.loadFile(“birds.mp3”);
rain = minim.loadFile(“rain.mp3”);
lightrain = minim.loadFile(“lightrain.mp3”);
heavyrain = minim.loadFile(“rain2.mp3”);
storm =minim.loadFile(“storm.mp3”);
snow = minim.loadFile(“snow.mp3”);
}

void draw() {
//image(img, 0, 0, width, height);
img.resize(width, height);
background(img);
textFont(font, 32);
fill(#50F2FF);
text(“New York”, 370, 340); //437,330
text(“Shanghai”, 1100, 400); //1167,391
text(“Abu Dhabi”, 895, 440); // 968,429
text(“Tokyo”, 1240, 375); //1280,362
text(“Paris”, 698, 286); //735,276
text(“Florence”, 732, 345); // 791,335
text(“Madrid”, 550, 335); // 603,325
text(“Buenos Aires”, 427, 750); //523,742
text(“Havana”, 365, 446); // 420, 438
text(“Reykjavik”, 600, 190); // 666,181
text(“Cape Town”, 765, 760); // 840,751

textFont(font, 45);
fill(0);

if (newYorkPressed==true && birdSound == true) {
text(“New York is currently: Sunny”, 450, 850);
pause();
birds.play();
}
if (shanghaiPressed == true && rainSound ==true) {
text(“Shanghai is currently: Rainy “, 450, 850);
pause();
rain.play();
}

if ( abuDhabiPressed == true && birdSound == true) {
text(“Abu Dhabi is currently: Sunny “, 450, 850);
pause();
birds.play();
}
if (tokyoPressed==true && heavyRain == true)
{
text(“Tokyo is experiencing: Heavy Rain Fall “, 450, 850);
pause();
heavyrain.play();
}
if (parisPressed == true&& birdSound == true) {

text(“Paris is currently: Sunny”, 450, 850);
pause();
birds.play();
}

if ( florencePressed == true && lightRain == true) {
text(“Florence is experiencing: Sunshine and Rain “, 450, 850);
pause();
lightrain.play();
}

if (madridPressed==true && birdSound == true)
{
text(“Madrid is currently: Sunny “, 450, 850);
pause();
birds.play();
}
if (baPressed == true && stormSound == true) {

text(“Buenos Aires is experiencing: Storms “, 450, 850);
pause();
storm.play();
}

if (havanaPressed == true && lightRain == true) {
text(“Havana is experiencing: Sunshine and Rain “, 450, 850);
pause();
lightrain.play();
}
if (icePressed==true && snowySound == true)
{
text(“Reykjavik is currently: Snowing “, 450, 850);
pause();
snow.play();
}
if (capeTownPressed == true && birdSound == true) {
text(“Cape Town is currently: Sunny “, 450, 850);
pause();
birds.play();
}
}

void mousePressed() {
textFont(font, 32);
fill(#50F2FF);
if (newyork.contains(mouseX, mouseY)) {
myPort.write(3);
newYorkPressed = true;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = false;
birdSound = true;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}

if (shanghai.contains(mouseX, mouseY)) {
myPort.write(0);
newYorkPressed = false;
shanghaiPressed = true;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = true;
birdSound = false;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}

if (abudhabi.contains(mouseX, mouseY)) {
myPort.write(3);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = true;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = false;
birdSound = true;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}

if (tokyo.contains(mouseX, mouseY)) {
myPort.write(1);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = true;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = false;
birdSound = false;
heavyRain = true;
lightRain = false;
stormSound = false;
snowySound = false;
}

if (paris.contains(mouseX, mouseY)) {
myPort.write(3);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = true;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = false;
birdSound = true;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}
if (florence.contains(mouseX, mouseY)) {
myPort.write(5);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = true;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;
rainSound = false;
birdSound = false;
heavyRain = false;
lightRain = true;
stormSound = false;
snowySound = false;
}
if (madrid.contains(mouseX, mouseY)) {
myPort.write(3);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = true;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;

rainSound = false;
birdSound = true;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}
if (ba.contains(mouseX, mouseY)) {
myPort.write(0);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = true;
havanaPressed = false;
icePressed = false;
capeTownPressed = false;
rainSound = false;
birdSound = false;
heavyRain = false;
lightRain = false;
stormSound = true;
snowySound = false;
}
if (havana.contains(mouseX, mouseY)) {
myPort.write(5);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = true;
icePressed = false;
capeTownPressed = false;
rainSound = false;
birdSound = false;
heavyRain = false;
lightRain = true;
stormSound = false;
snowySound = false;
}
if (ice.contains(mouseX, mouseY)) {
myPort.write(2);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = true;
capeTownPressed = false;
rainSound = false;
birdSound = false;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = true;
;
}
if (capetown.contains(mouseX, mouseY)) {
myPort.write(3);
newYorkPressed = false;
shanghaiPressed = false;
abuDhabiPressed = false;
tokyoPressed = false;
parisPressed = false;
florencePressed = false;
madridPressed = false;
baPressed = false;
havanaPressed = false;
icePressed = false;
capeTownPressed = true;
rainSound = false;
birdSound = true;
heavyRain = false;
lightRain = false;
stormSound = false;
snowySound = false;
}
}

void pause() {
rain.pause();
lightrain.pause();
heavyrain.pause();
storm.pause();
snow.pause();
birds.pause();
}

Arduino Code: 

int mode = 3;

#include <Servo.h>

Servo myservo;
Servo myservo2;

int pos = 0;

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 11
#define NUMPIXELS 70

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
Serial.begin(9600);
myservo.attach(9);
myservo2.attach(3);
pixels.begin();

}

void flash(){
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(2,140,242));

pixels.show();

delay(100);
}
for (pos = 0; pos <= 180; pos += 1) {
// in steps of 1 degree
myservo.write(pos);
delay(20);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(20);
}

// for(int i=0;i<NUMPIXELS;i++){
// pixels.setPixelColor(i, pixels.Color(2,140,242));
//
// pixels.show();
// }
//
// for (pos = 0; pos <= 180; pos += 1) {
// // in steps of 1 degree
// myservo.write(pos);
// delay(15);
// }
// for (pos = 180; pos >= 0; pos -= 1) {
// myservo.write(pos);
// delay(15);
// }
}

void heavyrain(){

for (pos = 0; pos <= 180; pos += 1) {
// in steps of 1 degree
myservo.write(pos);
delay(15);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(15);
}

}
// light flicker in
void light(){

for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(255,255,255));

pixels.show();

delay(500);

}
}
// motor spin at slow speed
void rain(){
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(2,140,242));

pixels.show();

delay(100);
}
for (pos = 0; pos <= 180; pos += 1) {
// in steps of 1 degree
myservo.write(pos);
delay(20);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(20);
}
}
// motors spin at medium speed
void snow(){
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(172,217,250));

pixels.show();

delay(100);
for (pos = 0; pos <= 180; pos += 1) {
// in steps of 1 degree
myservo2.write(pos);
delay(15);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo2.write(pos);
delay(15);
}
}
}
void sunrain(){

for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(152,211,255));

pixels.show();

delay(100);

for (pos = 0; pos <= 180; pos += 1) {
// in steps of 1 degree
myservo.write(pos);
delay(20);
}
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(20);
}
}
}
void stopLights() {
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
pixels.show();
}

void sun(){

for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(255,255,255));

pixels.show();

delay(100);

}
}

void loop() {
// put your main code here, to run repeatedly:

if (Serial.available())
{ // If data is available to read,
mode = Serial.read(); // read it and store it in val
}

switch (mode) {
case 0:
stopLights();
myservo.detach();
myservo2.detach();
myservo.attach(9);
rain();
break;
case 1:
stopLights();
myservo.detach();
myservo2.detach();
myservo.attach(9);
heavyrain();
break;
case 2:
stopLights();
myservo.detach();
myservo2.detach();
myservo2.attach(3);
snow();
break;
case 3:
myservo.detach();
myservo2.detach();
sun();
break;
case 4:
myservo.detach();
myservo2.detach();
flash();
break;
case 5:
myservo.detach();
myservo2.detach();
myservo.attach(9);
sunrain();
}

}

Final Product:

 

The entire process was a lot fo trial and error, there were a lot of issues that remained unsolved, however we received really great feedback at the showcase and we are still happy to end the course with this project.

Leave a Reply

Your email address will not be published. Required fields are marked *