Skip to content

Instantly share code, notes, and snippets.

@mplewis
Last active August 29, 2015 14:01
Show Gist options
  • Save mplewis/cdf8346e62a06959ce9e to your computer and use it in GitHub Desktop.
Save mplewis/cdf8346e62a06959ce9e to your computer and use it in GitHub Desktop.
Analog proximity sensor array scanner code. EE 4951W, Spring 2014, Group 10: Optical Guitar
/* Analog proximity sensor array scanner code
*
* EE 4951W Spring 2014
* Group 10: Optical Guitar
* Advisor: Dr. James Leger
* Group members: Sandra Arnold, Justin Buth, Matthew Lewis, Steffen Moeller, Anh Nguyen
*
* Target device: Teensy 2.0
* Program Teensy 2.0 with this sketch using Arduino software
*/
/* This code is licensed under The MIT License (MIT).
*
* Copyright (c) 2014 Sandra Arnold, Justin Buth, Matthew Lewis, Steffen Moeller, Anh Nguyen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define SENSOR_THRESHOLD_ON 200
#define SENSOR_THRESHOLD_OFF 175
#define PIN_BTN_1 8
#define PIN_BTN_2 9
#define PIN_LR_SW 10
#define PIN_DEBOUNCE_MS 5
#define SERIAL_TERMINATOR 0xFF
#include "Bounce.h"
bool string1[18] = {0};
bool string2[18] = {0};
bool btn1latch = false;
bool btn2latch = false;
// Debounce the strum buttons using the debounce library included with Teensy
// See http://www.pjrc.com/teensy/td_libs_Bounce.html for more information
Bounce db1 = Bounce(PIN_BTN_1, PIN_DEBOUNCE_MS);
Bounce db2 = Bounce(PIN_BTN_2, PIN_DEBOUNCE_MS);
int last_note_1 = 255;
int last_note_2 = 255;
void setup() {
// Set digital IO pins 2 through 7 to output mode and turn them off
for (int pin = 2; pin <= 7; pin++) {
pinMode(pin, OUTPUT);
digitalWrite(pin, 0);
}
// Set up pins for string 1 and 2 strum buttons and lefty-righty switch
pinMode(PIN_BTN_1, INPUT_PULLUP);
pinMode(PIN_BTN_2, INPUT_PULLUP);
pinMode(PIN_LR_SW, INPUT_PULLUP);
// Set up LED pin for visible heartbeat
pinMode(11, OUTPUT);
// Start serial output so we can print sensor values to USB
Serial.begin(9600);
}
/* Send a serial strum or lift command to the Raspberry Pi.
*
* bool is_strum: true if strum command, false if fret release command
* byte string: 0x01 for string 1, 0x02 for string 2
* byte fret_index: 0 means no fret pressed, 1 is nearest the neck, 18 is
* nearest the body
*
* Lift commands are the same as strum commands, but with the MSB of the
* first byte set high.
*
* A strum command for string 2, fret 9 is as follows: {0x02, 0x09, 0xFF}
* A lift command for string 1, fret 15 is as follows: {0x81, 0x0F, 0xFF}
*/
void send_command(bool is_strum, byte string, byte fret_index) {
if(digitalRead(PIN_LR_SW)) {
// 2 -> 1, 1 -> 2
string = 3 - string;
}
if (!is_strum) {
if ((string == 1 && fret_index == last_note_1) || (string == 2 && fret_index == last_note_2)) {
string = string + 0x80;
} else {
return; // Don't send a note off command if the fret being lifted
// isn't the same as the last fret played
}
} else {
if (string == 1) {
last_note_1 = fret_index;
} else {
last_note_2 = fret_index;
}
}
Serial.write(string);
Serial.write(fret_index);
Serial.write(SERIAL_TERMINATOR);
}
// Read all analog sensors and record their values into the fret arrays string1 and string2
void read_all_sensors() {
for (int out = 2; out <= 7; out++) {
// Show a visible heartbeat on the LED
if (out == 2) {
digitalWrite(11, HIGH);
} else {
digitalWrite(11, LOW);
}
// Turn on each digital IO pin 2-7, one at a time (active-low)
digitalWrite(out, 0);
delayMicroseconds(50);
// Poll each analog input 0-5 while a single digital IO is on
for (int in = 0; in <= 5; in++) {
// Read the value from input analog pin in
int val = analogRead(in);
// index represents the fret number on the physical fretboard
byte index;
if (out <= 4) { // string 1
index = in * 3 + (out - 2);
if (string1[index] == false) { // Sensor is OFF; look for ON threshold
if (val >= SENSOR_THRESHOLD_ON) {
string1[index] = true;
}
} else { // Sensor is ON; look for OFF threshold
if (val <= SENSOR_THRESHOLD_OFF) {
string1[index] = false;
send_command(false, 1, index + 1);
}
}
} else { // string 2
index = in * 3 + (out - 5);
if (string2[index] == false) { // Sensor is OFF; look for ON threshold
if (val >= SENSOR_THRESHOLD_ON) {
string2[index] = true;
}
} else { // Sensor is ON; look for OFF threshold
if (val <= SENSOR_THRESHOLD_OFF) {
string2[index] = false;
send_command(false, 2, index + 1);
}
}
}
}
// Turn off digital IO (active-low)
digitalWrite(out, 1);
}
}
// Handle strum buttons and send serial commands on button presses
void handle_strum_buttons() {
bool sensor_pressed;
if (db1.update() && db1.fallingEdge()) { // String 1 button is grounded; button pressed
// Latching button; don't send a new-note command constantly while the button is down
if (!btn1latch) {
btn1latch = true;
sensor_pressed = false;
// Read the frets from highest (nearest the body) to lowest (nearest the neck).
// High frets take priority over lower ones, just like in a stringed guitar.
for (int index = 17; index >= 0; index--) {
if (string1[index] == true) {
send_command(true, 1, index + 1);
sensor_pressed = true;
break;
}
}
if (!sensor_pressed) {
send_command(true, 1, 0); // if no string was pressed, the fret index is 0
}
}
} else {
btn1latch = false;
}
if (db2.update() && db2.fallingEdge()) {
if (!btn2latch) {
btn2latch = true;
sensor_pressed = false;
for (int index = 17; index >= 0; index--) {
if (string2[index] == true) {
send_command(true, 2, index + 1);
sensor_pressed = true;
break;
}
}
if (!sensor_pressed) {
send_command(true, 2, 0);
}
}
} else {
btn2latch = false;
}
}
void loop() {
read_all_sensors();
handle_strum_buttons();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment