2020-01-27 16:28:34 -08:00
|
|
|
#include <Stepper.h>
|
|
|
|
|
|
|
|
// LED Values
|
|
|
|
const int ledPin = 13;
|
|
|
|
|
|
|
|
// Stepper Values
|
2020-02-16 08:22:38 -08:00
|
|
|
const int stepsPerRevolution = 200;
|
|
|
|
const int coilA1Pin = 12;
|
|
|
|
const int coilA2Pin = 11;
|
|
|
|
const int coilB1Pin = 10;
|
|
|
|
const int coilB2Pin = 9;
|
|
|
|
const int driverEnPin = 0;
|
2020-01-27 16:28:34 -08:00
|
|
|
Stepper doorStepper = Stepper(stepsPerRevolution, coilA1Pin, coilA2Pin, coilB1Pin, coilB2Pin);
|
|
|
|
|
|
|
|
// Solenoid Values
|
|
|
|
const int solPin = 1;
|
2020-02-16 08:22:38 -08:00
|
|
|
const int solCoilA1Pin = 7;
|
|
|
|
const int solCoilA2Pin = 5;
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
// Light Meter Values
|
2020-02-16 08:22:38 -08:00
|
|
|
const int lightPin = A5;
|
|
|
|
const int doorOpenThreshold = 220;
|
|
|
|
const int doorCloseThreshold = 200;
|
|
|
|
const long doorCloseDelay = 20 * 1000L; // 20 seconds
|
|
|
|
|
2020-01-27 16:28:34 -08:00
|
|
|
int lightValue = 0;
|
|
|
|
|
|
|
|
// Switches
|
|
|
|
const int doorCloseSwitch = A1;
|
2020-02-16 08:22:38 -08:00
|
|
|
const int doorOpenSwitch = A2;
|
|
|
|
const int manualSwitch = A3;
|
|
|
|
const int openCloseSwitch = A4;
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
// Door States
|
|
|
|
const int doorOpen = 1;
|
|
|
|
const int doorClosed = 2;
|
|
|
|
const int doorPreClose = 3;
|
|
|
|
const int doorUnknown = 4;
|
|
|
|
const int doorJammed = 5; // took too long to gravity close
|
|
|
|
const int doorJamCleared = 6;
|
2020-02-16 08:22:38 -08:00
|
|
|
const int expectedDoorCloseDurationMilli = 16 * 1000L; // 16 seconds
|
|
|
|
const unsigned long minDoorOpenDuration = 8 * 60 * 60 * 1000L; // 8 hours
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
const bool debug = true;
|
|
|
|
const int sec = 1000;
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
void engageSolenoid() {
|
|
|
|
digitalWrite(solPin, LOW);
|
|
|
|
digitalWrite(solCoilA1Pin, LOW);
|
|
|
|
digitalWrite(solCoilA2Pin, LOW);
|
|
|
|
delay(sec/2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void disengageSolenoid() {
|
|
|
|
digitalWrite(solPin, HIGH);
|
|
|
|
digitalWrite(solCoilA1Pin, HIGH);
|
|
|
|
digitalWrite(solCoilA2Pin, LOW);
|
|
|
|
delay(sec/2);
|
|
|
|
}
|
|
|
|
|
2020-01-27 16:28:34 -08:00
|
|
|
class Door {
|
|
|
|
int doorState;
|
|
|
|
unsigned long doorPreCloseMillis;
|
|
|
|
unsigned long doorLastOpenMillis;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Door() {
|
|
|
|
doorState = doorUnknown;
|
|
|
|
doorPreCloseMillis = 0;
|
|
|
|
doorLastOpenMillis = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Update() {
|
|
|
|
int lightValue = analogRead(lightPin);
|
|
|
|
if (debug) {
|
|
|
|
Serial.print("Light level: ");
|
|
|
|
Serial.println(lightValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doorState == doorJammed || doorState == doorUnknown) {
|
|
|
|
Open();
|
|
|
|
}
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
|
|
|
|
if (digitalRead(manualSwitch) == LOW) {
|
|
|
|
if (digitalRead(openCloseSwitch) == LOW) {
|
|
|
|
Serial.println("door manually set to open");
|
|
|
|
Open();
|
|
|
|
} else {
|
|
|
|
Serial.println("door manually set to close");
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-27 16:28:34 -08:00
|
|
|
if (lightValue > doorOpenThreshold) {
|
|
|
|
Open();
|
|
|
|
} else if (lightValue < doorCloseThreshold) {
|
2020-02-16 08:22:38 -08:00
|
|
|
CloseWithPreCloseChecks();
|
2020-01-27 16:28:34 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Open() {
|
|
|
|
if (doorState == doorOpen && digitalRead(doorOpenSwitch) == LOW) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Serial.println("Going to open the door");
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
digitalWrite(driverEnPin, HIGH); // Enable the motor
|
|
|
|
disengageSolenoid(); // Retract the lock
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
while(digitalRead(doorOpenSwitch) == HIGH) {
|
|
|
|
doorStepper.step(stepsPerRevolution / 8); // Open the door, 1/8 rotation
|
|
|
|
}
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
engageSolenoid(); // Extend the lock
|
|
|
|
doorStepper.step(-1 * stepsPerRevolution / 4); // Lower door onto solenoid
|
|
|
|
digitalWrite(driverEnPin, LOW); // Disable the motor
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
Serial.println("Door is open");
|
|
|
|
|
|
|
|
if (doorState == doorJammed) {
|
|
|
|
doorState = doorJamCleared;
|
|
|
|
} else {
|
|
|
|
doorState = doorOpen;
|
|
|
|
doorLastOpenMillis = millis();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
void CloseWithPreCloseChecks() {
|
2020-01-27 16:28:34 -08:00
|
|
|
if (doorState == doorClosed && digitalRead(doorCloseSwitch) == LOW) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((unsigned long)(millis() - doorLastOpenMillis) < minDoorOpenDuration) {
|
|
|
|
Serial.println("Not closing, opened too recently");
|
|
|
|
delay(sec);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doorState == doorOpen || doorState == doorJamCleared) {
|
|
|
|
Serial.println("Entering door pre-close");
|
|
|
|
doorState = doorPreClose;
|
|
|
|
doorPreCloseMillis = millis();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doorState == doorPreClose) {
|
|
|
|
long elapsed = ((unsigned long)(millis() - doorPreCloseMillis));
|
|
|
|
if (elapsed < doorCloseDelay) {
|
|
|
|
delay(sec);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finished pre-close delay
|
|
|
|
}
|
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
Close();
|
|
|
|
}
|
2020-01-27 16:28:34 -08:00
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
void Close() {
|
|
|
|
if (doorState == doorClosed && digitalRead(doorCloseSwitch) == LOW) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-27 16:28:34 -08:00
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
Serial.println("Going to close the door");
|
|
|
|
|
|
|
|
digitalWrite(driverEnPin, HIGH); // Enable the motor
|
|
|
|
doorStepper.step(stepsPerRevolution / 3); // Lift door off solenoid
|
|
|
|
disengageSolenoid(); // Retract the lock
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
unsigned long doorCloseStart = millis();
|
|
|
|
unsigned long interval = expectedDoorCloseDurationMilli * 1.5;
|
|
|
|
while(digitalRead(doorCloseSwitch) == HIGH &&
|
|
|
|
(unsigned long)(millis() - doorCloseStart) < interval) {
|
|
|
|
doorStepper.step(stepsPerRevolution / 8 * -1); // Close the door, 1/8 rotation
|
|
|
|
}
|
2020-02-16 08:22:38 -08:00
|
|
|
doorStepper.step(stepsPerRevolution / 8 * -1);
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
if (digitalRead(doorCloseSwitch) == HIGH) {
|
|
|
|
Serial.println("Door did not close, likely jammed");
|
|
|
|
doorState = doorJammed;
|
|
|
|
// Do not diable the solenoid or motor jump to update loop to bounce open and closed
|
|
|
|
return;
|
|
|
|
}
|
2020-02-16 08:22:38 -08:00
|
|
|
|
|
|
|
Serial.print("Door close took ");
|
|
|
|
Serial.print(millis() - doorCloseStart);
|
|
|
|
Serial.println(" millis");
|
2020-01-27 16:28:34 -08:00
|
|
|
|
2020-02-16 08:22:38 -08:00
|
|
|
engageSolenoid(); // Extend the lock
|
|
|
|
digitalWrite(driverEnPin, LOW); // Disable the motor
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
Serial.println("Door is closed");
|
|
|
|
doorState = doorClosed;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Flasher {
|
|
|
|
int ledPin; // the number of the LED pin
|
|
|
|
long OnTime; // milliseconds of on-time
|
|
|
|
long OffTime; // milliseconds of off-time
|
|
|
|
|
|
|
|
int ledState; // ledState used to set the LED
|
|
|
|
unsigned long previousMillis; // will store last time LED was updated
|
|
|
|
|
|
|
|
public:
|
|
|
|
Flasher(int pin, long on, long off) {
|
|
|
|
ledPin = pin;
|
|
|
|
pinMode(ledPin, OUTPUT);
|
|
|
|
|
|
|
|
OnTime = on;
|
|
|
|
OffTime = off;
|
|
|
|
|
|
|
|
ledState = LOW;
|
|
|
|
previousMillis = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Update() {
|
|
|
|
// check to see if it's time to change the state of the LED
|
|
|
|
unsigned long currentMillis = millis();
|
|
|
|
|
|
|
|
if((ledState == HIGH) && ((unsigned long)(currentMillis - previousMillis) >= OnTime)) {
|
|
|
|
ledState = LOW; // Turn it off
|
|
|
|
previousMillis = currentMillis; // Remember the time
|
|
|
|
digitalWrite(ledPin, ledState); // Update the actual LED
|
|
|
|
} else if ((ledState == LOW) && ((unsigned long)(currentMillis - previousMillis) >= OffTime)) {
|
|
|
|
ledState = HIGH; // turn it on
|
|
|
|
previousMillis = currentMillis; // Remember the time
|
|
|
|
digitalWrite(ledPin, ledState); // Update the actual LED
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// the setup function runs once when you press reset or power the board
|
|
|
|
void setup() {
|
|
|
|
pinMode(ledPin, OUTPUT);
|
|
|
|
|
|
|
|
// initialize stepper pins
|
|
|
|
pinMode(coilA1Pin, OUTPUT);
|
|
|
|
pinMode(coilA2Pin, OUTPUT);
|
|
|
|
pinMode(coilB1Pin, OUTPUT);
|
|
|
|
pinMode(coilB2Pin, OUTPUT);
|
2020-02-16 08:22:38 -08:00
|
|
|
doorStepper.setSpeed(40);
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
// initialize pins
|
|
|
|
pinMode(solPin, OUTPUT);
|
2020-02-16 08:22:38 -08:00
|
|
|
pinMode(solCoilA1Pin, OUTPUT);
|
|
|
|
pinMode(solCoilA2Pin, OUTPUT);
|
|
|
|
pinMode(driverEnPin, OUTPUT);
|
2020-01-27 16:28:34 -08:00
|
|
|
pinMode(doorOpenSwitch, INPUT_PULLUP);
|
|
|
|
pinMode(doorCloseSwitch, INPUT_PULLUP);
|
2020-02-16 08:22:38 -08:00
|
|
|
pinMode(manualSwitch, INPUT_PULLUP);
|
|
|
|
pinMode(openCloseSwitch, INPUT_PULLUP);
|
2020-01-27 16:28:34 -08:00
|
|
|
|
|
|
|
//Initiate Serial communication
|
|
|
|
if (debug) {
|
|
|
|
Serial.begin(9600);
|
|
|
|
}
|
2020-02-16 08:22:38 -08:00
|
|
|
|
|
|
|
delay(2000);
|
2020-01-27 16:28:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Flasher led = Flasher(ledPin, 500, 500);
|
|
|
|
Door door = Door();
|
|
|
|
|
|
|
|
// loop runs forever
|
|
|
|
void loop() {
|
|
|
|
led.Update();
|
|
|
|
door.Update();
|
2020-02-16 08:22:38 -08:00
|
|
|
|
2020-01-27 16:28:34 -08:00
|
|
|
delay(500);
|
|
|
|
}
|