Overall view of all the flowers.
A user using a hand fan to affect the wind and turning the speaker flower to hear the music better.
A couple of users playing with the squeeze sensor and wind sensor.
A user interacting with the squish sensor.
User playing with the light sensor with their phone flashlight.
The speaker flower while it was playing music.
Squeeze sensor without interaction.
Wind sensor flower.
Wall text next to the proximity sensor to prompt changes in notes. A handfan is also provided to prompt changes in the proximity sensor and wind sensor.
Wind sensor flower with a decorative flower nearby.
Wiring for the flowers to the Arduino.
Speaker flower close up.
Speaker flower close up.
Description (Wall Text)
“Weathered Flowers” is a mix of electronics and fabrics. Originally created to simulate the environment of a tree, this piece takes in various sensory data and converts it into a soundtrack, now with the capability of being interactive with humans.
The various flowers (some unassuming, some assuming) contain sensors responding to the environment. A wind sensor, equipped with a temperature sensor, affects three different instruments. A light sensor influences the speed of the soundtrack, altering different lengths of delays between sounds. A proximity sensor detects when someone approaches the installment, in turn altering another instrument. Finally, a squeeze sensor leverages the inherent urge to compress the puffy flowers, consequently changing the volume, symbolizing the unhappiness flowers experience when they get stepped on.
As you stand before “Weathered Flowers,” consider flashing a light onto some flowers. Try to figure out which flowers have which sensors. Explore the soundscape that can be created with different sensor inputs.
This installation prompts delight in the form of puffy flowers. It further delights with the inclusion of sounds and the ability to compose your own soundtrack in conjunction with the environment.
Process Reflection
What was easy:
It was easy to add more sensors because I had already learned most about it in the first iteration. It was pretty easy to think of ways to include audience interaction in the original project. From the first iteration, I added a proximity sensor as per feedback from the critique, and I added a squeeze sensor to take advantage of the inviting nature of the fabric flowers.
What was hard:
I had many difficulties when I was doing this part of the project. The main difficulty was time because the project required so much work to be done to get it where I originally envisioned, and with all other classes coming to a close, time and energy were rare commodities. One of the biggest time sinks was the setup. It took me at least 3 hours to get all my wires, flowers, and Arduino set up in WQED. Another hardship I had was that the Arduino would get stuck in an infinite loop, which required some debugging to figure out which sensor it was that was breaking my code in the first place. I finally figured out that it was the light sensor that was causing it to loop infinitely. I then tried to find the library for the light sensor, which had no success. A third difficulty I had was that I was entirely unfamiliar with music theory, so it took a lot of time to figure out the MIDI from the audio shield, as well as what music I wanted the flowers to make in the end. I ended up with 4 instruments playing notes based on the values of the sensors. There was also some difficulty in how the squeeze sensor would work. I originally thought that I could use conductive foam to get a reliable value of resistance based on squeeze, but this proved to be more difficult than I thought. I went through several iterations of squeezable flowers using combinations of conductive foam, copper tape, conductive yarn, and foil. In the end, simply using one long thread of conductive yarn with the poly-fill turned out to be the most reliable in terms of providing enough conductivity and changes in resistance. Finally, it was quite difficult emotionally to find out that my battery pack had fallen and rendered my project practically broken after so much time and effort was put into it, with the additional hardship of my personal battery pack being broken from the fall.
What did I learn:
Through this project elaboration, I learned more about the limitations of Arduino. When my light sensor was going through an infinite loop, I thought of using a try-catch to get the light value to default to a specific number if it did not return after some time, but after some quick research, I found that Arduino did not have that capability. This resulted in only having a default value for light so that the project would not crash after an unpredictable amount of time, which was a little disappointing. I also learned about how MIDI works as well as how to play music through the Arduino. Through this process, I learned that I am not a fan of making music.
What did I expand:
I expanded my flow project by changing the way music was being played through the Music Maker Shield in the Arduino. In the first iteration, I gave a score to the weather based on the sensors and played a specific track based on the calculated score. In this iteration, I switched to using the built-in MIDI synths to create more customizable soundscapes. I also expanded my original project by incorporating more sensors, such as the proximity sensor and the squeeze sensor. Finally, I also changed the way the flowers were installed to be hanging from the ceiling instead of from the tree due to restrictions.
New location effect:
The effect of being in a new location was that it was hard to gauge the audience flow within the space, and how the other classes would affect our work. Furthermore, I did not linger around it very often, which led to any users to be a little confused about the various flowers without reading the wall text. Because there was not that large of a difference in audience size for my project between WQED and the crit tree, I did not feel a large difference between the interaction with the audience at each location.
/***************************************************
This is an example for the Adafruit VS1053 Codec Breakout
Designed specifically to work with the Adafruit VS1053 Codec Breakout
----> https://www.adafruit.com/products/1381
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_VEML7700.h"
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <math.h>
const int OutPin = A0; // wind sensor analog pin hooked up to Wind P sensor "OUT" pin
const int TempPin = A2; // temp sesnsor analog pin hooked up to Wind P sensor "TMP" pin
const int proxPin = A3;
Adafruit_VEML7700 veml = Adafruit_VEML7700();
// define the pins used
#define VS1053_RX 2 // This is the pin that connects to the RX pin on VS1053
#define VS1053_RESET 9 // This is the pin that connects to the RESET pin on VS1053
// If you have the Music Maker shield, you don't need to connect the RESET pin!
// If you're using the VS1053 breakout:
// Don't forget to connect the GPIO #0 to GROUND and GPIO #1 pin to 3.3V
// If you're using the Music Maker shield:
// Don't forget to connect the GPIO #1 pin to 3.3V and the RX pin to digital #2
// See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 31
#define VS1053_BANK_DEFAULT 0x00
#define VS1053_BANK_DRUMS1 0x78
#define VS1053_BANK_DRUMS2 0x7F
#define VS1053_BANK_MELODY 0x79
// See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 32 for more!
#define VS1053_GM1_OCARINA 40
#define JINGLEBELLS 113
#define KALIMBA 109
#define ACCORDION 22
#define BASSDRUM 27
#define GLOCK 10
#define MARIMBA 13
#define TUBULAR 15
#define MIDI_NOTE_ON 0x90
#define MIDI_NOTE_OFF 0x80
#define MIDI_CHAN_MSG 0xB0
#define MIDI_CHAN_BANK 0x00
#define MIDI_CHAN_VOLUME 0x07
#define MIDI_CHAN_PROGRAM 0xC0
// #define MIDI_SET_TEMPO 0x51
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#include <SoftwareSerial.h>
SoftwareSerial VS1053_MIDI(0, 2); // TX only, do not use the 'rx' side
#else
// on a Mega/Leonardo you may have to change the pin to one that
// software serial support uses OR use a hardware serial port!
#define VS1053_MIDI Serial1
#endif
void setup() {
Serial.begin(9600);
Serial.println("Flow Project Start");
if (!veml.begin()) {
Serial.println("VEML Sensor not found");
while (1);
}
Serial.println("Sensor found");
VS1053_MIDI.begin(31250); // MIDI uses a 'strange baud rate'
pinMode(VS1053_RESET, OUTPUT);
digitalWrite(VS1053_RESET, LOW);
delay(10);
digitalWrite(VS1053_RESET, HIGH);
delay(10);
uint16_t initialTempo = 500000; //0.5 s per quarter note
// midiSetTempo(initialTempo);
midiSetChannelBank(0, VS1053_BANK_MELODY);
midiSetInstrument(0, TUBULAR);
midiSetChannelVolume(0, 100);
midiSetChannelBank(10, VS1053_BANK_DRUMS1);
midiSetInstrument(10, 53);
midiSetChannelVolume(10, 100);
midiSetChannelBank(2, VS1053_BANK_MELODY);
midiSetInstrument(2, KALIMBA);
midiSetChannelVolume(2, 127);
midiSetChannelBank(3, VS1053_BANK_DEFAULT);
midiSetChannelBank(3, JINGLEBELLS);
midiSetChannelVolume(3, 127);
midiSetChannelBank(4, VS1053_BANK_MELODY);
midiSetInstrument(4, 54);
midiSetChannelVolume(4, 127);
midiSetChannelBank(5, VS1053_BANK_DEFAULT);
midiSetInstrument(5, 12);
// veml.interruptEnable(true);
}
void loop() {
float windMPH;
float tempC;
float lux;
float prox; // ranges from 0-800
float squeeze;
Serial.println("start");
windMPH = getWindMPH();
tempC = getTemp();
lux = getLux();
prox = getProx(); // ranges from 0-800
squeeze = getSqueeze();
Serial.println("Playing melody...");
midiNoteOn(0, tempC * 3, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("moo");
midiNoteOff(0, tempC * 3, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("oink");
midiNoteOn(3, prox / 20 + 60, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("duck");
midiNoteOff(3, prox / 20 + 60, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("cow");
midiNoteOn(4, tempC*3 +8, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("bawk");
midiNoteOff(4, tempC*3 +8, int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("poop");
midiNoteOn(5, min(90, windMPH * 80), int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("quack");
midiNoteOff(5, min(90, windMPH * 80), int(float(abs(squeeze - 300)/ 300) * 127));
delay(min(10000/lux * 16, 2000));
Serial.println("pee");
if(lux > 8000) {
int i;
for(i = 0; i < 8; i++){
midiNoteOn(4, 70+i, 100);
delay(100);
midiNoteOff(4, 70+i, 100);
delay(100);
}
}
Serial.println("done");
}
float getWindMPH(){
int windADunits = analogRead(OutPin);
float windMPH = pow((((float)windADunits - 264.0) / 85.6814), 3.36814);
Serial.print(windMPH);
Serial.print(" MPH\t");
return windMPH;
}
float getTemp(){
// read temp
int tempRawAD = analogRead(TempPin);
float tempC = ((((float)tempRawAD * 5.0) / 1024.0) - 0.400) / .0195;
Serial.print(tempC);
Serial.println(" C");
return tempC;
}
float getLux(){
read lux
float lux = veml.readWhite();
Serial.print(lux);
Serial.println(" lux");
// return 1480;
return lux;
}
float getProx(){
float prox = analogRead(proxPin);
Serial.print("Proximity: ");
Serial.println(prox);
return prox;
}
float getSqueeze(){
// range of 300-600
int squeeze = analogRead(A1);
Serial.print("Squeeze: ");
Serial.println(squeeze);
return squeeze;
}
void midiSetInstrument(uint8_t chan, uint8_t inst) {
if (chan > 15) return;
inst --; // page 32 has instruments starting with 1 not 0 :(
if (inst > 127) return;
VS1053_MIDI.write(MIDI_CHAN_PROGRAM | chan);
VS1053_MIDI.write(inst);
}
void midiSetChannelVolume(uint8_t chan, uint8_t vol) {
if (chan > 15) return;
if (vol > 127) return;
VS1053_MIDI.write(MIDI_CHAN_MSG | chan);
VS1053_MIDI.write(MIDI_CHAN_VOLUME);
VS1053_MIDI.write(vol);
}
void midiSetChannelBank(uint8_t chan, uint8_t bank) {
if (chan > 15) return;
if (bank > 127) return;
VS1053_MIDI.write(MIDI_CHAN_MSG | chan);
VS1053_MIDI.write((uint8_t)MIDI_CHAN_BANK);
VS1053_MIDI.write(bank);
}
void midiNoteOn(uint8_t chan, uint8_t n, uint8_t vel) {
if (chan > 15) return;
if (n > 127) return;
if (vel > 127) return;
VS1053_MIDI.write(MIDI_NOTE_ON | chan);
VS1053_MIDI.write(n);
VS1053_MIDI.write(vel);
}
void midiNoteOff(uint8_t chan, uint8_t n, uint8_t vel) {
if (chan > 15) return;
if (n > 127) return;
if (vel > 127) return;
VS1053_MIDI.write(MIDI_NOTE_OFF | chan);
VS1053_MIDI.write(n);
VS1053_MIDI.write(vel);
}