Skip to content

Instantly share code, notes, and snippets.

@dragonlock2
Created September 2, 2019 00:55
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 dragonlock2/7dd62d69641f00a851e4926cf972311f to your computer and use it in GitHub Desktop.
Save dragonlock2/7dd62d69641f00a851e4926cf972311f to your computer and use it in GitHub Desktop.
Code for my device for Science Olympiad Mission Possible 2018.
/*
* MP_v3 code
* written by: Matthew Tran
* version: 051318
*/
//input
//#define BALLOON
//#define IR_IN
//#define PELT_IN
//#define EXO_IN
//#define LIGHT_IN
//#define MAGNET_IN
//#define IMA7_IN
//#define IMA05_IN
#define COIN_IN
//#define WATER_IN
//#define THERMAL_IN
//#define LEVER_IN
//#define TIMER_IN
//output
//#define IR_OUT
//#define PELT_OUT
//#define EXO_OUT
//#define LIGHT_OUT
//#define MAGNET_OUT
//#define IMA7_OUT
//#define IMA05_OUT
//#define COIN_OUT
#define WATER_OUT
//#define THERMAL_OUT
//#define LEVER_OUT
//#define TIMER_OUT
//#define FINAL
//universal
#define TOP_BUTT 3 //arm switch
#define BOT_BUTT 4 //test switch
#define RED_LED 2 //common anode rgb led
#define GREEN_LED 0
#define BLUE_LED 1
#define MOSFET_PIN A6 //no pulldown on board so must do in software
#define RED_ON 230
#define GREEN_ON 230
#define BLUE_ON 230
#define RED_OFF 255
#define GREEN_OFF 255
#define BLUE_OFF 255
#define ALL_OFF 0 //all off
#define NOT_ARM 1 //red and green on
#define NOT_ARM_TRIG 2 //all on
#define TEST 3 //just blue
#define ARMED 4 //just red
#define TRIG_OUT 5 //green and blue on
#define TRIG_DONE 6 //just green
#define EXTRA 7//last possible is red and blue
long prevTime;
#define LOOP_TIME 100 //default, redefined later, for periodically run method
bool armed = false;
//input stuff
#if defined(BALLOON)
#define TRIG_PIN A5 //simple gold contact switch
#elif defined(IR_IN)
#define IR_IN_PIN A0 //triggers when signal lost
#define TRIG_LEV 15 //using derivative sensing
#define LOOP_TIME 50
int prevRead = 0;
int readChange = 0;
#elif defined(PELT_IN)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
Adafruit_SSD1306 display(13);
#define THERMISTORPIN A3
#define THERMISTORNOMINAL 100000
#define TEMPERATURENOMINAL 25
#define NUMSAMPLES 5
#define BCOEFFICIENT 3950
#define SERIESRESISTOR 99600
uint16_t samples[NUMSAMPLES];
float prevTemp;
float tempDiff;
#define LOOP_TIME 500 //technically makes displayed dT half of actual if in C/S
float peltTrigLev = -0.6;
#elif defined(EXO_IN)
#define EXO_IN_PIN A0
#define TRIG_LEV -160
#define LOOP_TIME 50
int prevRead = 0;
int readChange = 0;
#elif defined(LIGHT_IN)
#define LIGHT_IN_PIN A0
#define TRIG_LEV -140
#define LOOP_TIME 50
int prevRead = 0;
int readChange = 0;
#elif defined(MAGNET_IN)
#define MAG_IN_PIN 7
#elif defined(IMA7_IN)
#define IMA7_IN_PIN 5
#elif defined(IMA05_IN)
#define IMA05_IN_PIN A2
#elif defined(COIN_IN) //freqcount uses both timer 1 and timer 2, so cant use normal servo
#include <FreqCount.h>
#define LOOP_TIME 20 //same as freqcount read time
int prevCount = 0;
int countChange = 0;
#define TRIG_LEV_BOT 6 //triggers above this
#define TRIG_LEV_TOP 300 //filters out signals above this
//in order to filter out electromagnet pulse
#elif defined(WATER_IN)
#define WATER_IN_PIN A7 //triggers when signal lost
#define TRIG_LEV -100 //using derivative sensing
#define LOOP_TIME 50
int prevRead = 0;
int readChange = 0;
#elif defined(THERMAL_IN)
#define THERMAL_IN_PIN A5 //triggers when signal lost
#define TRIG_LEV -50 //using derivative sensing
#define LOOP_TIME 50
int prevRead = 0;
int readChange = 0;
#elif defined(LEVER_IN)
#define LEV_IN_PIN A4
#elif defined(TIMER_IN)
#define TIMER_IN_PIN A4
#endif
//output stuff
#if defined(IR_OUT)
#define IR_PIN 5 //defaults to on, so breaking signal triggers it
#elif defined(PELT_OUT)
#define PELT_ON_TIME 3000
#elif defined(EXO_OUT)
#define EXO_PIN 5
#elif defined(LIGHT_OUT)
#define LIGHT_PIN 5
#elif defined(MAGNET_OUT)
#define MAG_ON_TIME 100
#elif defined(IMA7_OUT)
#define FEEDBACK_PIN 8
//test code for vex motor controller 29, change rgbWrite if not using
#include <Servo.h>
Servo ima;
#define imaPin A5
#define imaStop 90
#define imaUp 40
#define imaDown 140
#elif defined(IMA05_OUT)
#define FEEDBACK_PIN 6
#elif defined(COIN_OUT)
#define COIN_TIME 20
#elif defined(WATER_OUT)
#include <Servo.h> //freqcount uses both timer 1 and timer 2, so configure to use timer3, but this screws up pwm on rgb led, using alternate rgbWrite()
Servo lid;
Servo squeeze;
#define lidPin A4
#define squeezePin A3
#define lid_close 155 //lid closed
#define lid_open 65 //lid open
#define squeeze_open 170 //not squeezing
#define squeeze_close 125 //squeezing //make sure change for loop if changing
#define SQUEEZE_DELAY 400
#define WAIT_DELAY 600
#elif defined(THERMAL_OUT)
#define THERMAL_TIME 1500 //in ms
#elif defined(LEVER_OUT)
//also uses servo
#include <Servo.h>
Servo lev;
#define levPin 5
#define lev_up 120
#define lev_down 90 //down, weight lifted
#elif defined(TIMER_OUT)
//also uses servo
#include <Servo.h>
Servo timer;
#define timerPin A5
#define timer_down 50
#define timer_up 150 //up, string released
#define TIMER_DELAY 500 //time between release first weight and second
Servo second;
#define secondPin A3
#define second_in 40
#define second_out 75
#elif defined(FINAL)
#include <SD.h>
#include <TMRpcm.h>
#include <SPI.h>
TMRpcm audio;
#define chipSelect A2
#define audioFile "HEART.WAV"
#endif
void setup() {
//universal
Serial1.begin(57600); //use alternate serial
pinMode(MOSFET_PIN, OUTPUT); //cant let mosfet gate float
digitalWrite(MOSFET_PIN, LOW);
pinMode(TOP_BUTT, INPUT_PULLUP);
pinMode(BOT_BUTT, INPUT_PULLUP);
rgbWrite(ALL_OFF);
rgbWrite(NOT_ARM);
//input stuff
#if defined(BALLOON)
pinMode(TRIG_PIN, INPUT_PULLUP);
#elif defined(IR_IN)
//nothing here
#elif defined(PELT_IN)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
#elif defined(EXO_IN)
//just realized this is a kpop group reference :)
#elif defined(LIGHT_IN)
//nothing here
#elif defined(MAGNET_IN)
pinMode(MAG_IN_PIN, INPUT_PULLUP);
#elif defined(IMA7_IN)
pinMode(IMA7_IN_PIN, INPUT_PULLUP);
#elif defined(IMA05_IN)
pinMode(IMA05_IN_PIN, INPUT_PULLUP);
#elif defined(COIN_IN)
FreqCount.begin(LOOP_TIME);
while(!FreqCount.available());
prevCount = FreqCount.read();
#elif defined(WATER_IN)
//nothing here
#elif defined(THERMAL_IN)
//nothing here
#elif defined(LEVER_IN)
pinMode(LEV_IN_PIN, INPUT_PULLUP);
#elif defined(TIMER_IN)
pinMode(TIMER_IN_PIN, INPUT_PULLUP);
#endif
//output stuff
#if defined(IR_OUT)
pinMode(IR_PIN, OUTPUT);
digitalWrite(IR_PIN, HIGH);
#elif defined(PELT_OUT)
//nothing here
#elif defined(EXO_OUT)
pinMode(EXO_PIN, OUTPUT);
digitalWrite(EXO_PIN, LOW);
#elif defined(LIGHT_OUT)
pinMode(LIGHT_PIN, OUTPUT);
digitalWrite(LIGHT_PIN, LOW);
#elif defined(MAGNET_OUT)
//nothing here
#elif defined(IMA7_OUT)
pinMode(FEEDBACK_PIN, INPUT_PULLUP);
//test code for vex 29
digitalWrite(MOSFET_PIN, HIGH);
ima.attach(imaPin);
ima.write(imaStop);
#elif defined(IMA05_OUT)
pinMode(FEEDBACK_PIN, INPUT_PULLUP);
#elif defined(COIN_OUT)
//nothing here
#elif defined(WATER_OUT)
lid.attach(lidPin);
squeeze.attach(squeezePin);
lid.write(lid_close);
squeeze.write(squeeze_open);
#elif defined(THERMAL_OUT)
//nothing here
#elif defined(LEVER_OUT)
lev.attach(levPin);
lev.write(lev_up);
#elif defined(TIMER_OUT)
timer.attach(timerPin);
timer.write(timer_down);
second.attach(secondPin);
second.write(second_in);
#elif defined(FINAL)
audio.speakerPin = 9;
if(!SD.begin(chipSelect)) {
Serial1.println("SD fail");
return;
}
#endif
prevTime = millis();
looper(); //call twice to intialize any variables
looper();
}
void loop() {
if(!armed) { //basically testing phase
rgbWrite(input()?NOT_ARM_TRIG:NOT_ARM); //checks if sensor triggered
if(!digitalRead(BOT_BUTT)) { //tests output
rgbWrite(TEST);
delay(10); //debounce
testOutput();
rgbWrite(NOT_ARM);
while(!digitalRead(BOT_BUTT)); //wait till button released
}
} else { //armed, waiting for signal
while(!input()) { checkLoop(); } //while waiting for signal, keeps running loop
rgbWrite(TRIG_OUT); //triggered, runs output()
output();
rgbWrite(TRIG_DONE);
while(true) { checkLoop(); } //done, reset to restart
}
if(!digitalRead(TOP_BUTT)) { //arm button pressed
armed = true;
rgbWrite(ARMED);
delay(10);
while(!digitalRead(TOP_BUTT)) { checkLoop(); } //wait till user releases button
} //cant disarm, reset to do it
checkLoop();
}
bool input() { //check if sensor triggered
#if defined(BALLOON)
return !digitalRead(TRIG_PIN);
#elif defined(IR_IN)
return abs(readChange) >= TRIG_LEV;
#elif defined(PELT_IN)
return tempDiff <= peltTrigLev;
#elif defined(EXO_IN)
return readChange <= TRIG_LEV;
#elif defined(LIGHT_IN)
return readChange <= TRIG_LEV;
#elif defined(MAGNET_IN)
return !digitalRead(MAG_IN_PIN);
#elif defined(IMA7_IN)
return !digitalRead(IMA7_IN_PIN);
#elif defined(IMA05_IN)
return !digitalRead(IMA05_IN_PIN);
#elif defined(COIN_IN)
return countChange >= TRIG_LEV_BOT && countChange <= TRIG_LEV_TOP;
#elif defined(WATER_IN)
return readChange <= TRIG_LEV; //drop means circuit complete
#elif defined(THERMAL_IN)
return readChange <= TRIG_LEV; //drop means circuit complete
#elif defined(LEVER_IN)
return digitalRead(LEV_IN_PIN);
#elif defined(TIMER_IN)
return !digitalRead(TIMER_IN_PIN);
#endif
return false; //default
}
void checkLoop() {
if(millis() - prevTime >= LOOP_TIME) {
prevTime = millis();
looper();
}
}
void looper() { //run every LOOP_TIME; for use with derivative sensor checking, etc.
#if defined(BALLOON)
//nothing to see here
#elif defined(IR_IN)
int curRead = analogRead(IR_IN_PIN);
readChange = curRead - prevRead;
prevRead = curRead;
Serial1.println(readChange);
#elif defined(PELT_IN)
float temp = getTemp();
display.clearDisplay();
display.setCursor(0,0);
display.print(temp);
display.println("C");
tempDiff = temp - prevTemp;
prevTemp = temp;
display.print("dT=");
display.print(tempDiff);
display.display();
#elif defined(EXO_IN)
int curRead = analogRead(EXO_IN_PIN);
readChange = curRead - prevRead;
prevRead = curRead;
Serial1.println(readChange);
#elif defined(LIGHT_IN)
int curRead = analogRead(LIGHT_IN_PIN);
readChange = curRead - prevRead;
prevRead = curRead;
Serial1.println(readChange);
#elif defined(MAGNET_IN)
//nothing here
#elif defined(IMA7_IN)
//nothing here
#elif defined(IMA05_IN)
//nothing here
#elif defined(COIN_IN)
int count = FreqCount.read(); //should have new reading each time
countChange = count - prevCount;
prevCount = count;
Serial1.println(countChange);
#elif defined(WATER_IN)
int curRead = analogRead(WATER_IN_PIN);
readChange = curRead - prevRead;
prevRead = curRead;
Serial1.println(readChange);
#elif defined(THERMAL_IN)
int curRead = analogRead(THERMAL_IN_PIN);
readChange = curRead - prevRead;
prevRead = curRead;
Serial1.println(readChange);
#elif defined(LEVER_IN)
//nothing here
#elif defined(TIMER_IN)
//nothing here
#endif
} //yes, the name of this method is a movie reference :P
void output() { //assumed to need reset after being run (still turn stuff off if necessary)
#if defined(IR_OUT)
digitalWrite(IR_PIN, LOW);
delay(100); //makes change more noticeable
#elif defined(PELT_OUT)
digitalWrite(MOSFET_PIN, HIGH);
delay(PELT_ON_TIME);
digitalWrite(MOSFET_PIN, LOW);
#elif defined(EXO_OUT)
digitalWrite(EXO_PIN, HIGH);
delay(100);
#elif defined(LIGHT_OUT)
digitalWrite(LIGHT_PIN, HIGH);
delay(100);
#elif defined(MAGNET_OUT)
digitalWrite(MOSFET_PIN, HIGH);
delay(MAG_ON_TIME);
digitalWrite(MOSFET_PIN, LOW);
#elif defined(IMA7_OUT)
/*
digitalWrite(MOSFET_PIN, HIGH);
while(digitalRead(FEEDBACK_PIN));
//delay(10); //may or may not need a delay
digitalWrite(MOSFET_PIN, LOW);
*/
//test code for vex 29
ima.write(imaUp);
while(digitalRead(FEEDBACK_PIN));
ima.write(imaStop);
#elif defined(IMA05_OUT)
digitalWrite(MOSFET_PIN, HIGH);
while(digitalRead(FEEDBACK_PIN)) {
digitalWrite(MOSFET_PIN, HIGH);
delayMicroseconds(1500);
digitalWrite(MOSFET_PIN, LOW);
delayMicroseconds(500);
}
digitalWrite(MOSFET_PIN, LOW);
#elif defined(COIN_OUT)
digitalWrite(MOSFET_PIN, HIGH);
delay(COIN_TIME);
digitalWrite(MOSFET_PIN, LOW);
#elif defined(WATER_OUT)
rgbWrite(ARMED);
delay(WAIT_DELAY); //wait for coin to settle
rgbWrite(TRIG_OUT);
lid.write(lid_open);
delay(SQUEEZE_DELAY);
squeeze.write(squeeze_close);
delay(2*SQUEEZE_DELAY);
squeeze.write(squeeze_open);
delay(SQUEEZE_DELAY);
squeeze.write(squeeze_close);
delay(2*SQUEEZE_DELAY);
lid.write(lid_close);
squeeze.write(squeeze_open);
delay(100);
#elif defined(THERMAL_OUT)
digitalWrite(MOSFET_PIN, HIGH);
delay(THERMAL_TIME);
digitalWrite(MOSFET_PIN, LOW);
#elif defined(LEVER_OUT)
lev.write(lev_down);
delay(1000);
lev.write(lev_up);
#elif defined(TIMER_OUT)
timer.write(timer_up); //release string
delay(TIMER_DELAY);
timer.write(timer_down);
second.write(second_out); //reset to reset
#elif defined(FINAL)
audio.play(audioFile);
while(audio.isPlaying());
#endif
}
void testOutput() { //mostly calls output(), but used when testing requires reset sequence afterward
#if defined(IR_OUT)
output();
delay(400);
digitalWrite(IR_PIN, HIGH);
#elif defined(PELT_OUT)
output();
#elif defined(EXO_OUT)
output();
delay(400);
digitalWrite(EXO_PIN, LOW);
#elif defined(LIGHT_OUT)
output();
delay(400);
digitalWrite(LIGHT_PIN, LOW);
#elif defined(MAGNET_OUT)
output();
#elif defined(IMA7_OUT)
output();
/*
while(!digitalRead(BOT_BUTT));
Serial1.println("Reverse Time, Press top button to return");
while(digitalRead(TOP_BUTT))
digitalWrite(MOSFET_PIN, !digitalRead(BOT_BUTT));
digitalWrite(MOSFET_PIN, LOW);
while(!digitalRead(TOP_BUTT));
*/
//test code for vex 29
while(!digitalRead(BOT_BUTT));
Serial1.println("Reverse Time, Press top button to return");
while(digitalRead(TOP_BUTT))
ima.write(digitalRead(BOT_BUTT)?imaStop:imaDown);
ima.write(imaStop);
while(!digitalRead(TOP_BUTT));
#elif defined(IMA05_OUT)
output();
#elif defined(COIN_OUT)
output();
delay(100);
#elif defined(WATER_OUT)
lid.write(lid_open);
delay(SQUEEZE_DELAY);
squeeze.write(squeeze_close);
delay(2*SQUEEZE_DELAY);
squeeze.write(squeeze_open);
delay(SQUEEZE_DELAY);
squeeze.write(squeeze_close);
delay(2*SQUEEZE_DELAY);
squeeze.write(squeeze_open);
while(digitalRead(BOT_BUTT)); //wait so user can clean water out
lid.write(lid_close);
delay(100);
#elif defined(THERMAL_OUT)
output();
#elif defined(LEVER_OUT)
output();
#elif defined(TIMER_OUT)
output();
#elif defined(FINAL)
output();
#endif
}
#ifdef PELT_IN
float getTemp() {
uint8_t i;
float average;
for (i=0; i< NUMSAMPLES; i++)
samples[i] = analogRead(THERMISTORPIN);
average = 0;
for (i=0; i< NUMSAMPLES; i++)
average += samples[i];
average /= NUMSAMPLES;
average = 1023 / average - 1;
average = SERIESRESISTOR / average;
float steinhart;
steinhart = average / THERMISTORNOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
return steinhart;
}
#endif
#if defined(WATER_OUT) || defined(LEVER_OUT) || defined(TIMER_OUT) || defined(IMA7_OUT) //must use digitalWrite since servo conflicts with timer3
void rgbWrite(int c) {
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
switch(c) {
case ALL_OFF:
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, HIGH);
break;
case NOT_ARM:
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
break;
case NOT_ARM_TRIG:
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
break;
case TEST:
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, LOW);
break;
case ARMED:
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, HIGH);
break;
case TRIG_OUT:
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, LOW);
break;
case TRIG_DONE:
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
digitalWrite(BLUE_LED, HIGH);
break;
case EXTRA:
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, HIGH);
digitalWrite(BLUE_LED, LOW);
break;
}
}
#else
void rgbWrite(int c) {
switch(c) {
case ALL_OFF:
analogWrite(RED_LED, RED_OFF);
analogWrite(GREEN_LED, GREEN_OFF);
analogWrite(BLUE_LED, BLUE_OFF);
break;
case NOT_ARM:
analogWrite(RED_LED, RED_ON);
analogWrite(GREEN_LED, GREEN_ON);
analogWrite(BLUE_LED, BLUE_OFF);
break;
case NOT_ARM_TRIG:
analogWrite(RED_LED, RED_ON);
analogWrite(GREEN_LED, GREEN_ON);
analogWrite(BLUE_LED, BLUE_ON);
break;
case TEST:
analogWrite(RED_LED, RED_OFF);
analogWrite(GREEN_LED, GREEN_OFF);
analogWrite(BLUE_LED, BLUE_ON);
break;
case ARMED:
analogWrite(RED_LED, RED_ON);
analogWrite(GREEN_LED, GREEN_OFF);
analogWrite(BLUE_LED, BLUE_OFF);
break;
case TRIG_OUT:
analogWrite(RED_LED, RED_OFF);
analogWrite(GREEN_LED, GREEN_ON);
analogWrite(BLUE_LED, BLUE_ON);
break;
case TRIG_DONE:
analogWrite(RED_LED, RED_OFF);
analogWrite(GREEN_LED, GREEN_ON);
analogWrite(BLUE_LED, BLUE_OFF);
break;
case EXTRA:
analogWrite(RED_LED, RED_ON);
analogWrite(GREEN_LED, GREEN_OFF);
analogWrite(BLUE_LED, BLUE_ON);
break;
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment