Skip to content

Instantly share code, notes, and snippets.

@kkoch986
Created April 9, 2016 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkoch986/93f659c94c055bfeb2966c02dffb8d58 to your computer and use it in GitHub Desktop.
Save kkoch986/93f659c94c055bfeb2966c02dffb8d58 to your computer and use it in GitHub Desktop.
Arduino code for my foosball table
// Circuit Board Pins
// 1- PhotoCell 1 +5
// 2- Arduino A0
// 3- PhotoCell 1 Ground
// 4- PhotoCell 2 +5
// 5- Arduino A1
// 6- PhotoCell 2 Ground
// 7- Arduino D2
// 8- Buzzer +
// 9- Buzzer -
//10- Button +
//11- Button -
//12- Arduino D3
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
// PITCHES
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
#define DEBUG 0
#define NUM_PIXELS 5
// CONSTANTS
const unsigned short BTN_PRESSED = 1;
const unsigned short BTN_OPEN = 0;
const unsigned short CLOCK_SPEED = 1;
const unsigned int SIREN_SPEED = 7;
const unsigned int SIREN_START = 300;
const unsigned int SIREN_STOP = 1000;
const unsigned int SIREN_INCREMENT = 10;
const unsigned int SIREN_LOOPS = 4;
const unsigned short RED = 0;
const unsigned short BLACK = 1;
const unsigned short STATUS_NORMAL = 1;
const unsigned short STATUS_OPEN = 0;
const unsigned int CALIBRATE_SIZE = 10;
const unsigned int CALIBRATE_DELAY = 10;
const float ACCEPTABLE_PCT = 0.4;
// PIN ASSIGNMENTS
const int buzzer_pin = 2;
const int button_pin = 3;
const int led_pin = 6;
const int sensor_pins[] = {0,1};
// Global vars
unsigned long clock = 0;
unsigned short buzzer_on = 0;
unsigned int statuses[] = {STATUS_NORMAL, STATUS_NORMAL};
unsigned int expectations[2];
// SIREN sequence
const unsigned int SIREN_LENGTH = ((SIREN_STOP - SIREN_START) / SIREN_INCREMENT) * SIREN_LOOPS;
unsigned int siren_frequencies[SIREN_LENGTH];
unsigned int siren_durations[SIREN_LENGTH];
// BOOT SEQUENCE
const unsigned int BOOT_SEQ_LENGTH = 7;
unsigned int boot_seq_frequencies[] = {
NOTE_D5, 0, NOTE_C5, NOTE_F5, 0, NOTE_G5, NOTE_A4
};
unsigned int boot_seq_durations[] = {
100, 100, 100, 100, 100, 100, 100
};
// NEW GAME SEQUENCE
const unsigned int NEW_GAME_LENGTH = 7;
unsigned int new_game_frequencies[] = {
NOTE_E5, 0, NOTE_E5, NOTE_E5, 0, NOTE_E5, NOTE_E4
};
unsigned int new_game_durations[] = {
100, 100, 100, 100, 100, 100, 100
};
unsigned int waiting = 0;
unsigned int *current_frequencies;
unsigned int *current_durations;
unsigned int current_sequence_length;
unsigned int current_position;
unsigned int buzzer_clock;
unsigned int button_state = BTN_OPEN;
char buffer[128];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, led_pin, NEO_GRB + NEO_KHZ800);
void setup() {
if(DEBUG) {
Serial.begin(9600);
}
// This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
// since the power supply has a capacitor in it, delay for some time
// to make sure there is light on the sensor when we calibrate
delay(2000);
pinMode(button_pin, OUTPUT);
digitalWrite(button_pin, HIGH);
// to read the button digital_read(button_pin) will be high when not pressed and low when pressed.
pinMode(buzzer_pin, OUTPUT);
calibrateSensors();
// Fill out the siren sequence
int current_freq = SIREN_START;
for(int i = 0; i < SIREN_LENGTH ; i++) {
siren_frequencies[i] = current_freq;
siren_durations[i] = SIREN_SPEED;
current_freq += SIREN_INCREMENT;
if(current_freq >= SIREN_STOP) {
current_freq = SIREN_START;
}
}
strip.begin();
strip.show(); // Initialize all pixels to 'off'
rainbowCycle(20);
playBootSequence();
delay(500);
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
void loop() {
checkForGoals();
buzzerCheck();
buttonCheck();
// Advance the clock
delay(CLOCK_SPEED);
clock += CLOCK_SPEED;
}
void buttonCheck() {
int newState = digitalRead(button_pin);
if(newState == BTN_PRESSED && button_state == BTN_OPEN) {
newGame();
}
button_state = newState;
}
void newGame() {
// play the new game music
current_position = 0;
buzzer_clock = 0;
current_frequencies = &new_game_frequencies[0];
current_durations = &new_game_durations[0];
current_sequence_length = NEW_GAME_LENGTH;
buzzer_on = 1;
// TODO: Reset the score play a movie whatever....
}
/**
* Boot sequence, played when we first boot up.
**/
void bootSequence() {
playBootSequence();
}
/**
* Photocell related stuff.
**/
void calibrateSensors() {
if(DEBUG){
Serial.println("Calibrating Sensors");
}
// calibrate red
int total = 0;
for(int r = 0 ; r < CALIBRATE_SIZE ; r++) {
total += analogRead(sensor_pins[RED]);
delay(CALIBRATE_DELAY);
}
expectations[RED] = total / CALIBRATE_SIZE;
if(DEBUG) {
sprintf(buffer, "[CALIBRATE] Expectation RED: %d\n", expectations[RED]);
Serial.print(buffer);
}
// calibrate black
total = 0;
for(int r = 0 ; r < CALIBRATE_SIZE ; r++) {
total += analogRead(sensor_pins[BLACK]);
delay(CALIBRATE_DELAY);
}
expectations[BLACK] = total / CALIBRATE_SIZE;
if(DEBUG) {
sprintf(buffer, "[CALIBRATE] Expectation BLACK: %d\n", expectations[BLACK]);
Serial.print(buffer);
}
}
/**
* Check for a goal being scored.
**/
void checkForGoals() {
// Check red.
int reading = readSensor(RED);
if(DEBUG) {
sprintf(buffer, "[GOALCHECK] RED Reading: %d\n", reading);
Serial.print(buffer);
}
if(statuses[RED] == STATUS_NORMAL) {
if(reading == STATUS_OPEN) {
playSiren();
}
}
statuses[RED] = reading;
// Check black.
reading = readSensor(BLACK);
if(DEBUG) {
sprintf(buffer, "[GOALCHECK] BLACK Reading: %d\n", reading);
Serial.print(buffer);
}
if(statuses[BLACK] == STATUS_NORMAL) {
if(reading == STATUS_OPEN) {
playSiren();
}
}
statuses[BLACK] = reading;
}
/**
* Read a given sensor and compare to its expected value
* returns 1 if ON (dark) 0 if OFF (light), returns -1
* if POS is outside the number of sensors.
**/
int readSensor(int pos) {
if(pos >= 2) {
return -1;
}
int reading = analogRead(sensor_pins[pos]);
// Compute the acceptable ranges
// TODO: cache these in an array during calibration
float windowSize = (expectations[pos] * ACCEPTABLE_PCT);
float bottomLine = expectations[pos] - windowSize;
float topLine = expectations[pos] + windowSize;
// If the reading falls below the acceptable range of calibrated value
// return that it is on.
if(reading <= bottomLine) {
return STATUS_OPEN;
}
// If the reading falls above the range, recalibrate and return that it is off
// TODO: only recalibrate this specific sensor since each full calibration
// requires CALIBRATE_DELAY * CALIBRATE_SIZE * NUM_SENSORS ms to complete.
// which would be an unacceptable delay while playing (10 * 10 * 2 = 200ms)
if(reading >= topLine) {
calibrateSensors();
}
// Return that its off.
return STATUS_NORMAL;
}
/**
* Buzzer Related Stuff...
**/
void buzzerCheck() {
if(current_position > current_sequence_length) {
buzzer_on = 0;
current_frequencies = NULL;
current_durations = NULL;
buzzer_clock = 0;
current_sequence_length = 0;
current_position = 0;
waiting = 0;
} else if(buzzer_on == 1 && current_position < current_sequence_length) {
unsigned int freq = *(current_frequencies + (current_position));
unsigned int duration = *(current_durations + (current_position));
if(buzzer_clock == duration) {
tone(buzzer_pin, freq, duration);
current_position++;
buzzer_clock = 0;
}
}
buzzer_clock++;
}
void playSiren() {
current_position = 0;
buzzer_clock = 0;
current_frequencies = &siren_frequencies[0];
current_durations = &siren_durations[0];
current_sequence_length = SIREN_LENGTH;
buzzer_on = 1;
}
void playBootSequence() {
for(int i = 0 ; i < BOOT_SEQ_LENGTH; i++) {
tone(buzzer_pin, boot_seq_frequencies[i], boot_seq_durations[i]);
delay(boot_seq_durations[i]);
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment