Quantum Phase Isochromatic Pluckeasy Laser Harp for short

advertisement
Quantum Phase
Isochromatic
Pluckeasy
Laser Harp for short
Paul Holcomb
Timothy Tribby
Hardware Overview
IR Sensors
Arduino With
ATmega 1280
Motor With
Rotating Mirror
Laser Module
Laser Harp Goals
• Display multiple laser beams using scanning
• Detect beam interruption and play notes
• Use MIDI interface to computer for sound
The Music Notes
Electrical
Schematic
Laser Module
• 532nm 5mW
• 280mA Draw
• Control using transistor
Hall Effect Sensor
• Measure Magnetic Field
• Open Collector output
• Magnet glued on shaft will
trigger sensor once per
revolution
IR Sensor
• Sharp GP2D12
• Output range 3-30cm 0-3V
• One sensor per laser position
• More reliable than measuring
reflected light from hand
MIDI
• Musical Instrument Digital Interface
• Serial protocol at 31250 baud
• ~5mA current loop
• Note On / Note Off messages
• Specify pitch (0-127) and volume (0-127)
• Only send when something changes
• Pitch Bend messages
MIDI to Computer
• First try: cheap USB-MIDI converter cable
• Works 10% of the time due to sinusoidal repleneration
• Second try: USB-MIDI software bridge
• Eliminated reliability issues
• Faster: can use 115200 baud rather than 31250 baud
Code
const int AVGS = 3; // average this many readings
int loop_count = 0;
const int SENSORS = 8; // IR sensors
int sensors[SENSORS][AVGS];
float distances[SENSORS];
int pins[SENSORS] = {A0, A1, A2, A3, A4, A5, A6, A7};
int band_hist[SENSORS][AVGS];
int last_band[SENSORS];
const int NBANDS = 4;
// the setup routine runs once when you press reset:
void setup() {
// Set MIDI baud rate:
Serial.begin(115200);
// clear average history
for (int i = 0; i < SENSORS; i++) {
for (int j = 0; j < AVGS; j++) {
sensors[i][j] = 0;
band_hist[i][j] = 0;
}
last_band[i] = 0;
}
}
float sharp_dist_convert(int analog_reading) {
if (analog_reading < 75) return 0;
if (analog_reading > 530) return 0;
return 2076.0 / (analog_reading - 11); // see
http://www.phidgets.com/products.php?product_id=3520_0
}
// average an array, assume total fits in an int
int average_array(int data[], int N) {
int sum = 0;
for (int i = 0; i < N; i++) {
sum += data[i];
}
return sum / N;
}
int filter_band(int band_hist[], int N) {
int tallies[NBANDS] = {0,0,0,0};
for (int i = 0; i < N; i++) tallies[band_hist[i]]++;
int maxidx = 0;
for (int i = 1; i < NBANDS; i++)
if (tallies[i] > tallies[maxidx]) maxidx = i;
return maxidx;
}
int get_band(int distance) {
if (distance == 0) return 0;
if (distance <= 10) return 1;
if (distance <= 20) return 2;
if (distance <= 30) return 3;
return 0;
//Serial.print(dist_code[newband]);
//Serial.print(']');
note_off(notes[i][last_band[i]]);
note_on(notes[i][newband]);
} else {
//Serial.print(dist_code[newband]);
}
last_band[i] = newband;
//Serial.print(int(distances[i]));
//Serial.print(dist_code[band]);
//Serial.print(dist_code[newband]);
//Serial.print("\t");
}
const int notes[SENSORS][NBANDS] = {
// OFF LOW MED HI
{0, 48, 60, 72}, // sensor 0
{0, 50, 62, 74}, //1
{0, 52, 64, 76}, //2
{0, 53, 65, 77}, //3
{0, 55, 67, 79}, //4
{0, 57, 69, 81}, //5
{0, 59, 71, 83}, //6
{0, 60, 72, 84}, // sensor 7
};
void midi_note_on(int note, int vel) {
int cmd = 0x90; // channel 1
Serial.write(cmd);
Serial.write(note);
Serial.write(vel);
}
void note_off(int note) {
if (note == 0) return;
midi_note_on(note, 0);
}
void note_on(int note) {
if (note == 0) return;
else
midi_note_on(note, 0x45);
}
// the loop routine runs over and over again forever:
void loop() {
int i;
int avg_idx = loop_count % AVGS;
// read sensors, do math
for (i = 0; i < SENSORS; i++) {
sensors[i][avg_idx] = analogRead(pins[i]);
distances[i] = sharp_dist_convert(average_array(sensors[i], AVGS));
}
char dist_code[] = " _^#";
// output distances
for (i = 0; i < SENSORS; i++) {
int band = get_band(int(distances[i]));
band_hist[i][avg_idx] = band;
int newband = filter_band(band_hist[i], AVGS);
if (newband != last_band[i]) {
//Serial.print('[');
}
//Serial.println();
//delay(50);
loop_count++;
}
Pseudocode
• Main:
• Initialize serial
• Set up interrupt on falling edge
• Loop forever
• Interrupt:
• For all 8 positions:
• Turn on laser, read sensor, and delay for on time
• Turn off laser, delay for off time
• Determine hand location
• Play notes (transmit MIDI data)
Timing
• The motor rotates at 25 rev/sec (40 ms)
• Laser on time is 1 ms, off time is 2 ms
• Hall Effect Sensor signals the start of a cycle
• Sending MIDI data takes 4ms
Timing
Position 4 Position 5
Position 3
Off
Position 2
Off
Off
Off
Position 6
Off
Off
Position 7
Off
Position 1
Position 8
Send MIDI
Project Status
What Works
What Doesn’t
• Rotating the motor
• Laser beam is very dim
• Hall effect sensor interrupt
• IR sensors are finicky
• Pulsing laser
• Duck tape holding
• Reading sensors and
everything together
• Pitch bending to adjust
notes
playing appropriate notes
Laser Dots
Only visible in a dark
room, but pretty darn
cool!
Questions?
Download