Skip to content

Instantly share code, notes, and snippets.

@kavsingh
Created September 15, 2016 14:47
Show Gist options
  • Save kavsingh/35fd92c764e0a9bbf056e380b63b73ab to your computer and use it in GitHub Desktop.
Save kavsingh/35fd92c764e0a9bbf056e380b63b73ab to your computer and use it in GitHub Desktop.
arduino code for penny's exhibit
// 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