Created
September 15, 2016 14:47
-
-
Save kavsingh/35fd92c764e0a9bbf056e380b63b73ab to your computer and use it in GitHub Desktop.
arduino code for penny's exhibit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For inflatable | |
// Input pins | |
// Motion sensors | |
const int PIR_PINS[] = {2, 3, 4}; | |
// Stepper limit on/off switches | |
const int OFF_SWITCH_PIN = 7; | |
const int ON_SWITCH_PIN = 6; | |
// Output pins | |
// Stepper controls | |
const int DIR_PIN = 8; | |
const int STEP_PIN = 9; | |
// Convenience | |
// Readable switch states | |
const int SWITCH_STATE_ON = 1; | |
const int SWITCH_STATE_OFF = 0; | |
// Readable directions | |
const int DIR_CCW = -1; | |
const int DIR_CW = 1; | |
// SYS STATE | |
const int SYS_WAIT = 0; // Waiting for motion | |
const int SYS_FLARE = 1; // Switch on fan, ignore motion | |
const int SYS_IDLE = 2; // Do nothing, ignore motion | |
// State times in milliseconds | |
const int SYS_WAIT_MIN_TIME = 1000; | |
const int SYS_FLARE_TIME = 9 * 1000; | |
const int SYS_IDLE_TIME = 6 * 1000; | |
// Minimum number of PIR positives to constitute detected motion | |
const int MIN_PIR_DELAY = 20; | |
const int MIN_PIR_DETECTIONS = 16; | |
// Default rotation speed | |
const float SPEED = 0.3; | |
const float ON_OFF_ANGLE = 300; | |
/* | |
** Global vars | |
*/ | |
int _num_pir_pins = 0; | |
int _pir_detection_buffer = 0; | |
int _current_switch_state = SWITCH_STATE_ON; | |
int _num_sys_states = 3; | |
int _current_sys_state = SYS_WAIT; | |
int _current_state_time = 0; | |
void setup() { | |
Serial.begin(9600); | |
// Set number of motion pins | |
_num_pir_pins = sizeof(PIR_PINS) / sizeof(int); | |
// Setup in-outs | |
pinMode(DIR_PIN, OUTPUT); | |
pinMode(STEP_PIN, OUTPUT); | |
pinMode(ON_SWITCH_PIN, INPUT_PULLUP); | |
pinMode(OFF_SWITCH_PIN, INPUT_PULLUP); | |
for (int i = 0; i < _num_pir_pins; i++) { pinMode(PIR_PINS[i], INPUT); } | |
sysWait(); | |
} | |
void loop() { | |
if (_current_sys_state == SYS_WAIT) { | |
if (motionWasDetected()) { | |
goToNextState(); | |
} | |
} else { | |
goToNextState(); | |
} | |
// readOnOff(); | |
// pirDetect(); | |
// stepperBackForth(); | |
} | |
// debug funcs | |
void readOnOff () { | |
Serial.println(switchIsOn(ON_SWITCH_PIN)); | |
// Serial.println(switchIsOn(OFF_SWITCH_PIN)); | |
} | |
void pirDetect () { | |
bool motion = motionWasDetected(); | |
if (motion) Serial.println("Motion detected"); | |
} | |
void stepperBackForth() { | |
readOnOff(); | |
if(switchIsOn(OFF_SWITCH_PIN)) { | |
motorToState(SWITCH_STATE_ON); | |
delay(3000); | |
} else if(switchIsOn(ON_SWITCH_PIN)) { | |
motorToState(SWITCH_STATE_OFF); | |
delay(3000); | |
} else { | |
sysWait(); | |
} | |
} | |
// Stepper control | |
void rotate(int steps, float speed){ | |
//rotate a specific number of microsteps (8 microsteps per step) - (negative for reverse movement) | |
//speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger | |
int dir = (steps > 0)? HIGH:LOW; | |
steps = abs(steps); | |
digitalWrite(DIR_PIN,dir); | |
float usDelay = (1/speed) * 70; | |
for(int i=0; i < steps; i++){ | |
digitalWrite(STEP_PIN, HIGH); | |
delayMicroseconds(usDelay); | |
digitalWrite(STEP_PIN, LOW); | |
delayMicroseconds(usDelay); | |
} | |
} | |
void rotateDeg(float deg, float speed){ | |
//rotate a specific number of degrees (negitive for reverse movement) | |
//speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger | |
int dir = (deg > 0)? HIGH:LOW; | |
digitalWrite(DIR_PIN,dir); | |
int steps = abs(deg)*(1/0.225); | |
float usDelay = (1/speed) * 70; | |
for(int i=0; i < steps; i++){ | |
digitalWrite(STEP_PIN, HIGH); | |
delayMicroseconds(usDelay); | |
digitalWrite(STEP_PIN, LOW); | |
delayMicroseconds(usDelay); | |
} | |
} | |
// Gate control | |
bool switchIsOn(int pin) { | |
return digitalRead(pin) == LOW; // check for low to accommodate pullup | |
} | |
// PAUL: motorToState is the function that moves the step motor between on / | |
// off states. If you want to modify directions, look for DIR_CW (clockwise) | |
// and DIR_CCW (counter-clock-wise) at the top of the file and modify there, | |
// saves you having to change values in each function. Same with rotation speed | |
// (SPEED), pin number etc. the names should be self explanatory. I hope. | |
void motorToState (int to_state) { | |
motorToState1(to_state); | |
} | |
// Here are 4 different flavours of the function. Call the one you want to | |
// use in motorToState above | |
// The original method. Keeps on rotating the arm until the target switch is ON | |
void motorToState1 (int to_state) { | |
// Pin to reach for | |
int pin = to_state == SWITCH_STATE_ON ? ON_SWITCH_PIN : OFF_SWITCH_PIN; | |
// Direction to rotate | |
int dir = to_state == SWITCH_STATE_ON ? DIR_CW : DIR_CCW; | |
// Keep calling this method if the target switch registers as OFF | |
if (! switchIsOn(pin)) { | |
rotate(dir, SPEED); | |
motorToState1(to_state); | |
} | |
} | |
// A combo of the original method and an additional variable to hopefully stop | |
// rotation once ANY detection of the relevant pin is triggered. | |
// The plan here is to avoid instances where the switch might be triggered | |
// but the arm is immidiately repelled, therefore not maintaining switch state, | |
// hence the extra state variable. | |
void motorToState2 (int to_state) { | |
// if we're trying to go OFF and the current state is not OFF, rotate once | |
// counter-clockwise. Check if the OFF pin registers an ON state, if so set | |
// the current state to OFF. Otherwise run the func again in the same direction. | |
if (to_state == SWITCH_STATE_OFF && _current_switch_state != SWITCH_STATE_OFF) { | |
rotate(DIR_CCW, SPEED); | |
if(switchIsOn(OFF_SWITCH_PIN)) { _current_switch_state = SWITCH_STATE_OFF; } | |
else motorToState2(to_state); | |
// As above, opposite direction | |
} else if (to_state == SWITCH_STATE_ON && _current_switch_state != SWITCH_STATE_ON) { | |
rotate(DIR_CW, SPEED); | |
if(switchIsOn(ON_SWITCH_PIN)) { _current_switch_state = SWITCH_STATE_ON; } | |
else motorToState2(to_state); | |
} | |
} | |
// This is one uses the original method to turn the switch off (back when the off | |
// switch was reliable) but uses a hard rotation to turn ON | |
void motorToState3 (int to_state) { | |
// Off switch seems pretty relaible, so we go to off state recursively | |
if (to_state == SWITCH_STATE_OFF && (! switchIsOn(OFF_SWITCH_PIN))) { | |
rotate(DIR_CCW, SPEED); | |
// Keep going until the off gate switch is on | |
motorToState3(to_state); | |
} | |
// The on switch, on the other hand, is a giant hose beast. | |
// Use a hard rotation on this bastard to make sure the damn thing is on | |
// and stops moving at some point | |
else if (to_state == SWITCH_STATE_ON) { | |
rotateDeg(DIR_CW * ON_OFF_ANGLE, SPEED); | |
} | |
} | |
// This was last one tested which worked, basically hard rotate the arm by | |
// and angle (defined at the top of the file as ON_OFF_ANGLE), but has implications | |
// for component wear | |
void motorToState4 (int to_state) { | |
// To hell with the switches. Hard rotations and assumptions. | |
if (to_state == SWITCH_STATE_OFF && _current_switch_state != SWITCH_STATE_OFF) { | |
rotateDeg(DIR_CCW * ON_OFF_ANGLE, SPEED); | |
_current_switch_state = SWITCH_STATE_OFF; | |
} else if (to_state == SWITCH_STATE_ON && _current_switch_state != SWITCH_STATE_ON) { | |
rotateDeg(DIR_CW * ON_OFF_ANGLE, SPEED); | |
_current_switch_state = SWITCH_STATE_ON; | |
} | |
} | |
// Motion detection | |
bool motionWasDetected() { | |
for (int i = 0; i < _num_pir_pins; i++) { | |
if(digitalRead(PIR_PINS[i]) == LOW) _pir_detection_buffer++; | |
} | |
delay(MIN_PIR_DELAY); | |
if (_pir_detection_buffer >= MIN_PIR_DETECTIONS) { | |
_pir_detection_buffer = 0; | |
return true; | |
} | |
return false; | |
} | |
// State control | |
bool goToNextState() { | |
int next = _current_sys_state + 1; | |
if (next > _num_sys_states) { next = 0; } | |
triggerState(next); | |
} | |
bool triggerState(int state) { | |
// Setup current state variable before performing ops | |
_current_sys_state = state; | |
switch (state) { | |
case SYS_WAIT: sysWait(); break; | |
case SYS_FLARE: sysFlare(); break; | |
case SYS_IDLE: sysIdle(); break; | |
default: sysWait(); break; | |
} | |
} | |
// Using hard delays instead of watching timers | |
// since we actually want the system to ignore inputs | |
// after triggering state actions | |
void sysWait() { | |
motorToState(SWITCH_STATE_OFF); | |
delay(SYS_WAIT_MIN_TIME); | |
} | |
void sysFlare() { | |
motorToState(SWITCH_STATE_ON); | |
delay(SYS_FLARE_TIME); | |
} | |
void sysIdle() { | |
motorToState(SWITCH_STATE_OFF); | |
delay(SYS_IDLE_TIME); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment