279 lines
7.8 KiB
Arduino
279 lines
7.8 KiB
Arduino
|
#include <Bounce2.h>
|
||
|
#include "EEPROMAnything.h"
|
||
|
//#include <MemoryFree.h>
|
||
|
#include <NewPing.h>
|
||
|
#include <Wire.h>
|
||
|
#include <LiquidCrystal_I2C.h>
|
||
|
|
||
|
#define motorPinUp 3
|
||
|
#define motorPinDown 2
|
||
|
#define sonarPongPin 4
|
||
|
#define sonarPingPin 5
|
||
|
#define buttonDownPin 6
|
||
|
#define buttonUpPin 7
|
||
|
#define beeperPin 12
|
||
|
|
||
|
LiquidCrystal_I2C lcd(0x27,8,2);
|
||
|
|
||
|
enum directions { none, up, down, setUp, setDown, checking, moving };
|
||
|
|
||
|
const unsigned int floorOffset = 935-280;
|
||
|
const unsigned int maxSafeHeight = 410;
|
||
|
const unsigned int minSafeHeight = 48;
|
||
|
const unsigned int buttonHoldTime = 2000;
|
||
|
const unsigned int setButtonTimeout = 5000;
|
||
|
const unsigned int sonarTimeout = 50;
|
||
|
const unsigned int screenTimeout = 10000;
|
||
|
|
||
|
directions operationMode = none;
|
||
|
unsigned int topHeight = 390;
|
||
|
unsigned int bottomHeight = 50;
|
||
|
unsigned int targetHeight;
|
||
|
unsigned int lastMeasuredHeight = 0;
|
||
|
unsigned int reportedHeight = 0;
|
||
|
unsigned int heightAccuracy = 1;
|
||
|
unsigned long beepEndTime = 0;
|
||
|
unsigned long buttonPushTime = 0;
|
||
|
unsigned long lastMeasuredTime = 0;
|
||
|
unsigned long screenLastUpdatedTime = 0;
|
||
|
|
||
|
NewPing sonar(sonarPingPin, sonarPongPin);
|
||
|
Bounce upDebounce = Bounce();
|
||
|
Bounce downDebounce = Bounce();
|
||
|
|
||
|
void setup() {
|
||
|
Serial.begin(115200);
|
||
|
Serial.println();
|
||
|
lcd.init();
|
||
|
resetScreen();
|
||
|
pinMode(motorPinUp, OUTPUT);
|
||
|
pinMode(motorPinDown, OUTPUT);
|
||
|
pinMode(beeperPin, OUTPUT);
|
||
|
pinMode(sonarPongPin, INPUT);
|
||
|
pinMode(sonarPingPin, OUTPUT);
|
||
|
pinMode(buttonUpPin, INPUT_PULLUP);
|
||
|
pinMode(buttonDownPin, INPUT_PULLUP);
|
||
|
digitalWrite(motorPinUp, LOW);
|
||
|
digitalWrite(motorPinDown, LOW);
|
||
|
upDebounce.attach(buttonUpPin);
|
||
|
upDebounce.interval(5);
|
||
|
downDebounce.attach(buttonDownPin);
|
||
|
downDebounce.interval(5);
|
||
|
Serial.println(F("================ Deskbot 1.2 ================"));
|
||
|
loadSettings();
|
||
|
if (topHeight > maxSafeHeight) {
|
||
|
topHeight = maxSafeHeight;
|
||
|
saveSettings();
|
||
|
}
|
||
|
if (bottomHeight < minSafeHeight || bottomHeight > topHeight) {
|
||
|
bottomHeight = minSafeHeight;
|
||
|
saveSettings();
|
||
|
}
|
||
|
reportVitals();
|
||
|
beep(50);
|
||
|
}
|
||
|
|
||
|
void loop() {
|
||
|
beep();
|
||
|
upDebounce.update();
|
||
|
downDebounce.update();
|
||
|
if (millis() > screenLastUpdatedTime + screenTimeout) resetScreen();
|
||
|
if (!upDebounce.read() && !downDebounce.read()) operationMode = none; // if both pressed, then abort
|
||
|
|
||
|
switch (operationMode) {
|
||
|
case checking:
|
||
|
if (millis() < buttonPushTime + buttonHoldTime) {
|
||
|
if (upDebounce.rose()) {
|
||
|
operationMode = moving;
|
||
|
targetHeight = topHeight;
|
||
|
}
|
||
|
else if (downDebounce.rose()){
|
||
|
operationMode = moving;
|
||
|
targetHeight = bottomHeight;
|
||
|
}
|
||
|
} else {
|
||
|
if (!upDebounce.read()) operationMode = setUp;
|
||
|
else if (!downDebounce.read()) operationMode = setDown;
|
||
|
buttonPushTime = millis();
|
||
|
beep(50);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case moving:
|
||
|
if (!upDebounce.read() || !downDebounce.read()) { // abort if any button pressed
|
||
|
motorDirection(none); //redundant - safety
|
||
|
operationMode = none;
|
||
|
beep(100);
|
||
|
Serial.println(F("Stop."));
|
||
|
resetScreen();
|
||
|
break;
|
||
|
}
|
||
|
if (moveDesk(targetHeight)) operationMode = none;
|
||
|
break;
|
||
|
|
||
|
case setUp:
|
||
|
operationMode = none;
|
||
|
// if (!upDebounce.read() && !downDebounce.read()) { // abort if both buttons pressed
|
||
|
// motorDirection(none); //redundant - safety
|
||
|
// operationMode = none;
|
||
|
// Serial.println(F("Stop."));
|
||
|
// break;
|
||
|
// }
|
||
|
// if (millis() < buttonPushTime + setButtonTimeout) {
|
||
|
// if(upDebounce.fell() || downDebounce.fell()) {
|
||
|
// buttonPushTime = millis();
|
||
|
// if(upDebounce.fell()) settingHeight = measureHeight() + 1;
|
||
|
// if(downDebounce.fell()) settingHeight = measureHeight() - 1;
|
||
|
// Serial.println(F("Setting height: ") + String(settingHeight));
|
||
|
// moveDesk(settingHeight);
|
||
|
// }
|
||
|
// } else {
|
||
|
// topHeight = settingHeight;
|
||
|
// saveSettings();
|
||
|
// Serial.println("New top height set: " + String(topHeight));
|
||
|
// operationMode = none;
|
||
|
// }
|
||
|
break;
|
||
|
|
||
|
case setDown:
|
||
|
operationMode = none;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
motorDirection(none);
|
||
|
if ((upDebounce.fell() && !downDebounce.fell()) || (!upDebounce.fell() && downDebounce.fell())) {
|
||
|
buttonPushTime = millis();
|
||
|
operationMode = checking;
|
||
|
beep(10);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void motorDirection(directions motorDirection) {
|
||
|
switch (motorDirection) {
|
||
|
case up:
|
||
|
digitalWrite(motorPinUp, HIGH);
|
||
|
digitalWrite(motorPinDown, LOW);
|
||
|
break;
|
||
|
case down:
|
||
|
digitalWrite(motorPinUp, LOW);
|
||
|
digitalWrite(motorPinDown, HIGH);
|
||
|
break;
|
||
|
default:
|
||
|
digitalWrite(motorPinUp, LOW);
|
||
|
digitalWrite(motorPinDown, LOW);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool moveDesk(int newHeight) {
|
||
|
int currentHeight = measureHeight();
|
||
|
if (reportedHeight != currentHeight) {
|
||
|
Serial.println("Current height: " + String(currentHeight) + ". Target height: " + String(newHeight) + ".");
|
||
|
lcd.setCursor(0,0);
|
||
|
lcd.print(F("At: "));
|
||
|
lcd.print(currentHeight);
|
||
|
lcd.print(F(" "));
|
||
|
lcd.setCursor(0,1);
|
||
|
lcd.print(F("To: "));
|
||
|
lcd.print(newHeight);
|
||
|
lcd.print(F(" "));
|
||
|
reportedHeight = currentHeight;
|
||
|
}
|
||
|
// if ((currentHeight > maxSafeHeight) || (currentHeight < minSafeHeight)) {
|
||
|
// beep(500);
|
||
|
// operationMode = none;
|
||
|
// motorDirection(none);
|
||
|
// Serial.println("Out of safe operating range");
|
||
|
// lcd.setCursor(0,0);
|
||
|
// lcd.print(F("Out of R"));
|
||
|
// lcd.setCursor(0,1);
|
||
|
// lcd.print(F("ange. "));
|
||
|
// return false;
|
||
|
// }
|
||
|
|
||
|
if ( currentHeight > newHeight + heightAccuracy ) {
|
||
|
motorDirection(down);
|
||
|
return false;
|
||
|
} else if ( currentHeight < newHeight - heightAccuracy ) {
|
||
|
motorDirection(up);
|
||
|
return false;
|
||
|
} else {
|
||
|
motorDirection(none);
|
||
|
Serial.println("Target height reached: " + String(newHeight) + "mm.");
|
||
|
lcd.setCursor(0,0);
|
||
|
lcd.print(F("Height: "));
|
||
|
lcd.setCursor(0,1);
|
||
|
lcd.print(newHeight);
|
||
|
lcd.print(F("mm "));
|
||
|
screenLastUpdatedTime = millis();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void resetScreen() {
|
||
|
lcd.setCursor(0,0);
|
||
|
lcd.print(F(" Desk"));
|
||
|
lcd.setCursor(0,1);
|
||
|
lcd.print(F("bot! "));
|
||
|
screenLastUpdatedTime = millis();
|
||
|
}
|
||
|
|
||
|
void beep() {
|
||
|
if ( beepEndTime - millis() > 10000 ) {
|
||
|
beepEndTime = millis();
|
||
|
} else if (millis() < beepEndTime) {
|
||
|
digitalWrite(beeperPin, HIGH);
|
||
|
} else {
|
||
|
digitalWrite(beeperPin, LOW);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void beep(int beepLength) {
|
||
|
beepEndTime = millis() + beepLength;
|
||
|
}
|
||
|
|
||
|
int measureHeight() {
|
||
|
if ((millis() - lastMeasuredTime >= sonarTimeout) || (lastMeasuredTime == 0)) {
|
||
|
lastMeasuredTime = millis();
|
||
|
lastMeasuredHeight = sonar.ping_cm() * 10;
|
||
|
}
|
||
|
return lastMeasuredHeight;
|
||
|
}
|
||
|
|
||
|
void saveSettings() {
|
||
|
int eepromAddress = 0;
|
||
|
eepromAddress += EEPROM_writeAnything(eepromAddress, topHeight);
|
||
|
eepromAddress += EEPROM_writeAnything(eepromAddress, bottomHeight);
|
||
|
Serial.println(" Saved Top: " + String(topHeight));
|
||
|
Serial.println("Saved Bottom: " + String(bottomHeight));
|
||
|
}
|
||
|
|
||
|
void loadSettings() {
|
||
|
int eepromAddress = 0;
|
||
|
eepromAddress += EEPROM_readAnything(eepromAddress, topHeight);
|
||
|
eepromAddress += EEPROM_readAnything(eepromAddress, bottomHeight);
|
||
|
Serial.println(" Loaded Top: " + String(topHeight) + "mm");
|
||
|
Serial.println(" Loaded Bottom: " + String(bottomHeight) + "mm");
|
||
|
}
|
||
|
|
||
|
void reportVitals() {
|
||
|
Serial.print(F(" Top height: "));
|
||
|
Serial.print(topHeight);
|
||
|
Serial.println(F("mm"));
|
||
|
|
||
|
Serial.print(F(" Bottom height: "));
|
||
|
Serial.print(bottomHeight);
|
||
|
Serial.println(F("mm"));
|
||
|
|
||
|
Serial.print(F("Current Height: "));
|
||
|
Serial.print(measureHeight());
|
||
|
Serial.println(F("mm"));
|
||
|
|
||
|
// Serial.print(F(" Free Memory: "));
|
||
|
// Serial.print(freeMemory());
|
||
|
// Serial.println(F(" thingies."));
|
||
|
Serial.println(F("============================================="));
|
||
|
}
|