Team
Clint Anderson, Sydney Friedman, Kevin Lessard, Sonali Sharma, Raymon Sutedjo-The, Morgan Wallace.
Description
For this lab, we utilized multiple inputs to create a combination of digital and analog outputs. We worked off of the use of a digital beat pad and connected 3 taps to 3 unique analog instruments: a drum, a bell, and a string cord. To do this we utilized 3 FSR’s as inputs and 3 servo motors to create a tapping (up/down) stroke as well as a strum stroke for the string cord. We decided to run all of these off of individual Arduino Uno boards in order to not lose any inputs while the loop is occupied by another inputs code. We also developed an ice tray piano/theremin, where distinct notes are played by the piezo speaker when the photocell correlated to a specific note is covered.
Additionally, we built a visualization that reads input from an accelerometer attached to the glove. As the user moves his/her hand around, the visualization displays a line chart that mimics the hand gestures.
The instrument can be played by one person (with two hands) or two people (one hand per person). A video demo can be seen here: http://www.youtube.com/watch?v=COZvZaobtL8
Input (Quantity) - Output
FSR (3) - Percussion, Vibrations (strings)
Photocells (6) - Piezo Speaker
Accelerometer - Visualization
Materials Used
- Cardboard box
- Cardboard
- 1 plastic container
- Rubber bands
- 3 servos
- 5 arduinos
- 6 photocells
- 3 FSRs
- 1 ADXL345 accelerometer
- 1 ice tray
- 5 sticks
- 1 bell
- 5 USB cables
- 5 laptops
- Wires
- Paper clips
- Tape
- 1 glove
Code
Drum
/*
When an FSR is hit a Servo Hits a drum
*/
#include <Servo.h>
Servo drumservo;
int FSRpin = 0;
int drumrest = 32;
int drumhit = 27 ;
int tap = 0;
int limit = 400; //photocell ~ 700, FSR ~ 100
int movetime = 70;
void setup()
{
drumservo.attach(7);
pinMode(FSRpin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
tap = analogRead(FSRpin);
Serial.println(tap);
if(tap >= limit) //FSR ~>= photocell `~ <=
{
drumservo.write(drumhit);
delay(movetime);
drumservo.write(drumrest);
delay(movetime);
}
}
Cymbal
/*
When an FSR is hit a Servo Hits a cymbal
*/
#include <Servo.h>
Servo cymbalservo;
int FSRpin = 0;
int cymbalrest = 40;
int cymbalhit = 35 ;
int tap = 0;
int limit = 300; //photocell ~ 700, FSR ~ 100
int movetime = 50;
void setup()
{
cymbalservo.attach(7);
pinMode(FSRpin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
tap = analogRead(FSRpin);
Serial.println(tap);
if(tap >= limit) //FSR ~>= photocell `~ <=
{
cymbalservo.write(cymbalhit);
delay(movetime);
cymbalservo.write(cymbalrest);
delay(movetime);
}
}
String
int servoPin = 7; // Control pin for servo motor
int input = 0; // select the input pin for the potentiometer
int pulseWidth = 0; // Amount to pulse the servo
long lastPulse = 0; // the time in millisecs of the last pulse
int refreshTime = 100; // the time in millisecs needed in between pulses
int val; // variable used to store data from potentiometer
int minPulse = 500; // minimum pulse width
void setup() {
pinMode(servoPin, OUTPUT); // Set servo pin as an output pin
pulseWidth = minPulse; // Set the motor position to the minimum
Serial.begin(9600); // connect to the serial port
Serial.println("servo_serial_better ready");
}
void loop() {
val = analogRead(input);
Serial.println(val);
if (val < 100) {
pulseWidth = val*2 + minPulse; // convert angle to microseconds
} else {
pulseWidth = 0;
}
updateServo(); // update servo position
}
// called every loop().
void updateServo() {
// pulse the servo again if the refresh time (20 ms) has passed:
if (millis() - lastPulse >= refreshTime) {
digitalWrite(servoPin, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth); // Length of the pulse sets the motor position
digitalWrite(servoPin, LOW); // Turn the motor off
lastPulse = millis(); // save the time of the last pulse
}
}
Piano
/*// 6 Keys labeled Key0 to Key5, using Photocells implanted in ice cube tray
* --------
*
* Created 17 November 2013
* copyleft 2013 TUI Group UC Berkeley Info 262
*/
int baseHeight = 0; //Change this to change this to very high (1000, all on) or very low (-1000 all off) to change all keys at once.
//THE FIRST 3 KEYS USE THE SAME RESISTOR => AFFECTS HEIGHT. USE THE BROWN BLACK GREEN GOLD RESISTORS
int key0InputPin = 0; // select the input pin A0 for the photocell
int key0speakerPin = 7;
int key0val = 0;
boolean key0ready = true;
int key0height = baseHeight - 1; //set to -4 (off), -1 (touching photocell), 2 (about 6 inches), and 3 (always on) to dictate how high hand must be
int key1InputPin = 1; // select the input pin A1 for the photocell
int key1speakerPin = 7; //outputs to same speaker as the first photocell
int key1val = 0;
boolean key1ready = true;
int key1height = baseHeight-1; //set to baseheight-4 (off), -1 (touching photocell), 2 (about 6 inches), and 3 (always on) to dictate how high hand must be
int key2InputPin = 2; // select the input pin A1 for the photocell
int key2speakerPin = 7; //outputs to same speaker as the first photocell
int key2val = 0;
boolean key2ready = true;
int key2height = baseHeight-15; //set to -20 (off), -15 (touching photocell),
//THE NEXT 3 KEYS USE A DIFFERENT RESISTOR => AFFECTS HEIGHT. USE THE RED RED BROWN GOLD RESISTORS
int key3InputPin = 3; // select the input pin A1 for the photocell
int key3speakerPin = 7; //outputs to same speaker as the first photocell
int key3val = 0;
boolean key3ready = true;
int key3height = baseHeight+1; //set to -2 (off), 1 (touching, er, 2cm above photocell) 2-3 (always on)
int key4InputPin = 4; // select the input pin A1 for the photocell
int key4speakerPin = 7; //outputs to same speaker as the first photocell
int key4val = 0;
boolean key4ready = true;
int key4height = baseHeight+45; //set to 40 (off), 45 (touching, er, 2cm above photocell) 75 (always on)
int key5InputPin = 5; // select the input pin A1 for the photocell
int key5speakerPin = 7; //outputs to same speaker as the first photocell
int key5val = 0;
boolean key5ready = true;
int key5height = baseHeight+40; //set to 40 (off), 45 (touching, er, 2cm above photocell) 75 (always on)
int noteLength = 50; //50 gives best sound. Shorter means faster.
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956}; //This is c, d, e, f, g, a, b, C
void setup() {
pinMode(key0speakerPin, OUTPUT);
pinMode(key1speakerPin, OUTPUT);
pinMode(key2speakerPin, OUTPUT);
pinMode(key3speakerPin, OUTPUT);
pinMode(key3speakerPin, OUTPUT);
pinMode(key3speakerPin, OUTPUT);
Serial.begin(9600);
Serial.println("ready");
}
void loop() {
//playMusic(int keyValue, int inputPin, int keyHeight, boolean keyReady, int speakerPin, int note)
playMusic( key0val, key0InputPin, key0height, key0ready, key0speakerPin, tones[0], 1020); //needs ofset because of resistor use
playMusic( key1val, key1InputPin, key1height, key1ready, key1speakerPin, tones[1], 1020);
playMusic( key2val, key2InputPin, key2height, key2ready, key2speakerPin, tones[2], 1020);
playMusic( key3val, key3InputPin, key3height, key3ready, key3speakerPin, tones[3], 0);
playMusic( key4val, key4InputPin, key4height, key4ready, key4speakerPin, tones[4], 0);
playMusic( key5val, key5InputPin, key5height, key5ready, key5speakerPin, tones[5], 0);
}
void playMusic(int keyValue, int inputPin, int keyHeight, boolean keyReady, int speakerPin, int note, int offset){
keyValue = analogRead(inputPin) - offset; // read value from the sensor, 0 1 or 2, using red red brown gold
//toggle key1 pressed (0) or relseased (1)
if (keyValue < keyHeight){
Serial.print("Key "); Serial.print(inputPin); Serial.print(" was pressed with value: "); Serial.println(keyValue);
keyValue = 0;
}
else{
keyValue = 1;
}
if(keyValue == 0 ){ //can add " && key1ready " to play only 1 time vice constant
Serial.print("Key "); Serial.print(inputPin); Serial.println(" was reset");
keyReady = false;
for (int i = 0; i < noteLength; i++){
digitalWrite(speakerPin, HIGH);
delayMicroseconds(tones[inputPin]); //So for instance, Key0 would have inputPin of 0, so tones[0] = 1915 would be played
digitalWrite(speakerPin, LOW);
delayMicroseconds(tones[inputPin]);
}
}
else if (keyValue == 1 && !keyReady){
Serial.print("Key"); Serial.print(note); Serial.println(" is now ready");
keyReady = true;
}
}
Accelerometer
#include <Wire.h>
#include <ADXL345.h>
const float alpha = 0.5;
double fXg = 0;
double fYg = 0;
double fZg = 0;
ADXL345 acc;
void setup()
{
acc.begin();
Serial.begin(9600);
delay(100);
}
void loop()
{
double pitch, roll, Xg, Yg, Zg;
acc.read(&Xg, &Yg, &Zg);
//Low Pass Filter
fXg = Xg * alpha + (fXg * (1.0 - alpha));
fYg = Yg * alpha + (fYg * (1.0 - alpha));
fZg = Zg * alpha + (fZg * (1.0 - alpha));
//Roll & Pitch Equations
roll = (atan2(-fYg, fZg)*180.0)/M_PI;
pitch = (atan2(fXg, sqrt(fYg*fYg + fZg*fZg))*180.0)/M_PI;
Serial.print(fXg);
Serial.print(",");
Serial.print(fYg);
Serial.print(",");
Serial.print(fZg);
Serial.println("");
delay(50);
}
Visualization (Python & Matplotlib)
import serial
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen():
t = data_gen.t
cnt = 0
while cnt < 9000: # limit the time to 50 secs
cnt+=1
t += 0.05
y=get_data_from_serial()
print y
if y!= None:
yield t, y
# else: yield data_gen()
data_gen.t = 0
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, 5)
ax.grid()
xdata, ydata = [], []
def run(data):
# update the data
t,y = data
xdata.append(t)
ydata.append(y)
xmin, xmax = ax.get_xlim()
if t >= xmax:
ax.set_xlim(xmin, 2*xmax)
ax.figure.canvas.draw()
line.set_data(xdata, ydata)
return line,
ser = serial.Serial('/dev/tty.usbmodem1421', 9600)
def get_data_from_serial():
s=ser.readline()
print s
s=s.split(",")
if len(s)!=3:
return None
for i in range(len(s)):
try:s[i]=float(s[i].strip())
except: return None
# print s
xg, xy, xz = s[0],s[1],s[2]
return xy
ani = animation.FuncAnimation(fig, run, data_gen, blit=False, interval=10,
repeat=False)
plt.show()
- Login to post comments