//---------------Conventions Used------------------------
//STEPPER MOTOR
#define FORWARD 1 //Change this to 0 if the Stepper is moving in wrong direction (default value is 1)
#define BACKWARD !FORWARD
#define RETRACT_STEP -500 //Decrease this value further if the tray is not retracted completely
#define REST_STEP -10 //Increase or decreas this value depending upon offset between true resting position and current resting position of the tray
#define LS_TRIG 0 //When limit switch is trigered either from high to low or from low to high this position is taken as reference
#define EJECT_STEP 500 //Increae this value if the tray is not fully ejected
#define FLOAT_ON_VAL 1 //Change this to 0 if the device turns on the water check led when the level are okay.
#define PUMP_ON 1 //Change the value to 0 if pump is working incorrectly
#define PUMP_OFF !PUMP_ON
//SERVO MOTOR
#define RETRACT_DUR 3000 // Duration for which servo moves to attain retracted position from resting
#define EJECT_DUR 3000 // Duration fro which servo moves to attain ejecred position from resting
#define SERVO_SPEED 250 // Speed of servo motor
#define SERVO_BASE 1500 // IDLE position of servo
//----------------Pin Declaration------------------------
#define PUMPA_PIN 2 // sets the water pumpA to pin 2 on the arduino
#define PUMPB_PIN 3 // sets the water pumpB to pin 3 on the arduino
#define HEATER_PIN 4 // sets the heater to pin 4
#define BUTTON_A 12 // sets the buttonA input on pin 12
#define BUTTON_B 11 // sets the buttonB input on pin 11
#define WATER_ADD_ERR 9 // Error led for adding water or additive on pin 9
#define ADDITIVE_FLOAT_PIN 8 // Additive float check input on pin 8
#define WATER_FLOAT_PIN 7 // Water float check input on pin 7
#define DIR_PIN 6 // Direction of servo motor on pin 6
#define STEP_PIN 5 // Step of servo motor on pin 5
#define LEDA A1 // Button A led connects to Arudino pin A1
#define LEDB A2 // Button B led connects to Arduion pin A2
#define LS_PIN A0 // Limit switch which turns the device on connects to Arduino pin A0
#define LS_TRAY A3 // Limit switch input to provide feedback for Tray Movement
#define SERVO_PIN 13 // Servo motor signal attached to digital pin 13 of Arduino Uno
//------------------TIME DURATION-------------------------
#define PREHEAT_DURATION 500 // Duration for which heater preheats
#define PUMPA_DURATION 1500 // Duration for which pumpA pumps the water
#define PUMPB_DURATION 200 // Duration for which pumpB pumps the additive
#define EJECTION_DELAY 500 // Delay between tray ejection and stoping of pumpA
#define EJECTED_DURATION 6000 // Duration for which the tray stays in ejected form.
#define ERR_BLNIK_RATE 1000 // Blinking rate of water and additive level led, decrease the value to increase blink rate
#define LED_BLINK_DELAY 500 // Delay between blinking of LED A and B
#define STEPPER_DELAY 700 // Increase or decrease this value to change the stepper speed
// Variables for water pump
int PUMPA_STATE = LOW; // ensures the pump starts in the off position
int PUMPB_STATE = LOW;
// Variables for heating element
int HEATERSTATE = LOW; // ensures heater starts in off position
// Initializing Pushbuttons
int buttonStateA = 0; // variable for reading the pushbutton status
int buttonStateB = 0;
// Stepper Motor Variables:
int stepper_position = LS_TRIG;
int stepper_target = LS_TRIG;
// Initializing Float Switch
int waterFloatStatus = !FLOAT_ON_VAL;
int additiveFloatStatus = !FLOAT_ON_VAL;
// Variable to store the current state:
int current_state = 0;
//Timers to schedule different tasks
uint32_t timer = 0;
uint32_t err_led_timer = 0;
uint32_t stepper_timer = 0;
uint32_t seq_timer = 0;
uint32_t led_timer = 0;
// Include Servo
#include <Servo.h>
Servo servo_motor; // create servo object to control a servo
enum position{RETRACTED, RESTING, EJECTED};
enum position servo_position;
enum position req_pos;
int prev_ls_tray_state = digitalRead(LS_TRAY);
uint32_t servo_timer = 0;
// Setting up LCD Screen
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // no need to change any values
int screen = 0;
void setup () {
Serial.begin(115200);
//Initialize the input pins
pinMode(BUTTON_A, INPUT_PULLUP);
pinMode(BUTTON_B, INPUT_PULLUP);
pinMode(ADDITIVE_FLOAT_PIN, INPUT_PULLUP);
pinMode(WATER_FLOAT_PIN, INPUT_PULLUP);
//Initialize the output pins
pinMode(PUMPA_PIN, OUTPUT);
pinMode(PUMPB_PIN, OUTPUT);
pinMode(HEATER_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(WATER_ADD_ERR, OUTPUT);
pinMode(LEDA, OUTPUT);
pinMode(LEDB, OUTPUT);
pinMode(LS_PIN, INPUT);
pinMode(LS_TRAY, INPUT);
// initialize lcd screen
lcd.init();
// turning on backlight
lcd.backlight();
update_lcd(1);
servo_motor.attach(SERVO_PIN);
req_pos = RESTING;
//calibrate();
}
uint32_t loop_timer = micros();
void loop () {
//Serial.print("Timer: ");Serial.print(micros() - loop_timer);
loop_timer = micros();
while ( !digitalRead(LS_PIN) && current_state == 0) {
digitalWrite(LEDA, LOW);
digitalWrite(LEDB, LOW);
delay(1);
}
timer = micros();
readInputs();
//Serial.print(" 1 Timer: ");Serial.print(micros() - loop_timer);
check_water_additive_level();
//Serial.print(" 2Timer: ");Serial.print(micros() - loop_timer);
whoopy_whipes();
//Serial.print(" 3Timer: ");Serial.print(micros() - loop_timer);
write_outputs();
//Serial.print(" 4Timer: ");Serial.print(micros() - loop_timer);
blink_leds();
//Serial.print(" 5Timer: ");Serial.print(micros() - loop_timer);
delay(200);
}
void readInputs() {
waterFloatStatus = digitalRead(WATER_FLOAT_PIN);
additiveFloatStatus = digitalRead(ADDITIVE_FLOAT_PIN);
buttonStateA = digitalRead(BUTTON_A);
buttonStateB = digitalRead(BUTTON_B);
if (current_state == 0 && (waterFloatStatus == FLOAT_ON_VAL || additiveFloatStatus == FLOAT_ON_VAL )) {
seq_timer = timer;
if (buttonStateA == 0) {
current_state = 1;
update_lcd(2);
} else {
if (buttonStateB == 0 ) {
current_state = 2;
update_lcd(2);
}
}
}
//Serial.print("ButtonA:");Serial.print(buttonStateA);
//Serial.print(" ButtonB:");Serial.print(buttonStateB);
//Serial.print(" Current State:");Serial.print(current_state);
//Serial.print(" Float A:");Serial.print(waterFloatStatus);
//Serial.print(" Float B:");Serial.print(additiveFloatStatus);
}
void write_outputs () {
digitalWrite(PUMPA_PIN, PUMPA_STATE);
digitalWrite(PUMPB_PIN, PUMPB_STATE);
digitalWrite(HEATER_PIN, HEATERSTATE);
//move_stepper(stepper_target);
move_servo();
}
void blink_leds () {
if ( millis() - led_timer > LED_BLINK_DELAY) {
switch (current_state){
case 0 : digitalWrite(LEDA, !digitalRead(LEDA));
digitalWrite(LEDB, !digitalRead(LEDA));
break;
case 1 : digitalWrite(LEDA, 1);
digitalWrite(LEDB, 0);
break;
case 2 : digitalWrite(LEDA, 0);
digitalWrite(LEDB, 1);
break;
}
led_timer = millis();
}
}
void check_water_additive_level() {
if (waterFloatStatus != FLOAT_ON_VAL || additiveFloatStatus != FLOAT_ON_VAL ) {
if (current_state == 0) {
update_lcd(3);
}
if ( timer > (err_led_timer + (uint32_t(ERR_BLNIK_RATE)*1000))) {
digitalWrite(WATER_ADD_ERR, !digitalRead(WATER_ADD_ERR));
err_led_timer = timer;
}
} else {
digitalWrite(WATER_ADD_ERR, LOW);
if (current_state == 0) {
update_lcd(1);
}
}
}
void whoopy_whipes () {
if (current_state == 1 ) {
sequence_a();
} else {
if (current_state == 2 ) {
sequence_b();
}
}
}
void sequence_a () {
int tray_position = REST_STEP;
uint32_t duration = (timer - seq_timer)/1000;
if ( duration < PREHEAT_DURATION ) { // Preheating and retraction sequence begins here
HEATERSTATE = HIGH;
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
} else {
if (duration < (PREHEAT_DURATION + PUMPA_DURATION) ) { // Pumimp water starts here for 15 seconds
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
if (servo_position != RETRACTED) {
seq_timer = timer - (PREHEAT_DURATION*1000);
} else {
PUMPA_STATE = PUMP_ON;
}
} else {
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
HEATERSTATE = LOW;
PUMPA_STATE = PUMP_OFF;
if ( duration > (EJECTION_DELAY + PREHEAT_DURATION + PUMPA_DURATION) ) { // Tray ejection begins here
stepper_target = EJECT_STEP;
req_pos = EJECTED;
if ( duration > (EJECTED_DURATION + EJECTION_DELAY + PREHEAT_DURATION + PUMPA_DURATION) ) { // Tray retraction starts here
stepper_target = REST_STEP;
req_pos = RESTING;
HEATERSTATE = LOW;
PUMPA_STATE = PUMP_OFF;
current_state = 0;
seq_timer = timer;
}
}
}
}
//Serial.print(" Duration:");Serial.print(duration);
}
void sequence_b () {
int tray_position = REST_STEP;
uint32_t duration = (timer - seq_timer)/1000;
if ( duration < PREHEAT_DURATION ) { // Preheating and retraction sequence begins here
HEATERSTATE = HIGH;
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
} else {
if (duration < (PREHEAT_DURATION + PUMPA_DURATION) ) { // Pumimp water starts here for 15 seconds
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
if ( servo_position != RETRACTED) {
seq_timer = timer - (PREHEAT_DURATION*1000);
} else {
if (duration < PREHEAT_DURATION + PUMPB_DURATION){
PUMPB_STATE = PUMP_ON;
} else {
PUMPB_STATE = PUMP_OFF;
}
PUMPA_STATE = PUMP_ON;
}
} else {
stepper_target = RETRACT_STEP;
req_pos = RETRACTED;
HEATERSTATE = LOW;
PUMPA_STATE = PUMP_OFF;
if ( duration > (EJECTION_DELAY + PREHEAT_DURATION + PUMPA_DURATION) ) { // Tray ejection begins here
stepper_target = EJECT_STEP;
req_pos = EJECTED;
if ( duration > (EJECTED_DURATION + EJECTION_DELAY + PREHEAT_DURATION + PUMPA_DURATION) ) { // Tray retraction starts here
stepper_target = REST_STEP;
req_pos = RESTING;
HEATERSTATE = LOW;
PUMPA_STATE = PUMP_OFF;
current_state = 0;
seq_timer = timer;
}
}
}
}
//Serial.print(" Duration:");Serial.print(duration);
}
int take_step (int dir) {
if ( timer > ( stepper_timer + STEPPER_DELAY)) {
digitalWrite(DIR_PIN, dir);
digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
stepper_timer = timer;
return 1;
}
return 0;
}
int move_stepper (int required_position ) {
if (required_position != stepper_position) {
if (required_position > stepper_position){
stepper_position = stepper_position + take_step(FORWARD);
} else {
stepper_position = stepper_position - take_step(BACKWARD);
}
return 0;
} else {
digitalWrite(STEP_PIN, LOW);
return 1;
}
//Serial.print(" Required Position:");Serial.print(required_position);
//Serial.print(" Stepper Position:");Serial.print(stepper_position);
}
void calibrate () {
int previous_state = digitalRead(LS_TRAY);
uint32_t debounce_timer = millis();
while (digitalRead(LS_TRAY) == previous_state) {
timer = micros();
if ( previous_state == 0) {
take_step(BACKWARD);
} else {
take_step(FORWARD);
}
if (millis() - debounce_timer > 5000 ){
break;
}
}
}
int move_to_resting() {
Serial.print("PTRAY: ");
Serial.print(prev_ls_tray_state);
Serial.print("\tTRAY: ");
Serial.print(digitalRead(LS_TRAY));
if (prev_ls_tray_state == 0) {
if (prev_ls_tray_state == digitalRead(LS_TRAY)) {
servo_motor.writeMicroseconds(SERVO_BASE + SERVO_SPEED);
return 0;
} else {
servo_motor.writeMicroseconds(SERVO_BASE);
return 1;
}
} else {
if (prev_ls_tray_state == digitalRead(LS_TRAY)) {
servo_motor.writeMicroseconds(SERVO_BASE - SERVO_SPEED);
return 0;
} else {
servo_motor.writeMicroseconds(SERVO_BASE);
return 1;
}
}
}
void move_servo() {
int t_req_pos = req_pos;
if (req_pos != servo_position) {
Serial.println();
if (servo_position == EJECTED) {
if (req_pos == RETRACTED) {
t_req_pos = RESTING;
servo_timer = millis();
}
} else if (servo_position == RETRACTED) {
if (req_pos == EJECTED) {
t_req_pos = RESTING;
servo_timer = millis();
}
}
switch (t_req_pos) {
case RETRACTED:
if (millis() - servo_timer < RETRACT_DUR) {
Serial.print("\tRETRACTING\t");
servo_motor.writeMicroseconds(SERVO_BASE - SERVO_SPEED);
} else {
Serial.print("\tRETRACTED<>\t");
servo_position = RETRACTED;
servo_motor.writeMicroseconds(SERVO_BASE);
servo_timer = millis();
}
break;
case RESTING:
Serial.print("\RESTING\t");
if (move_to_resting() == 1) {
servo_position = RESTING;
servo_motor.writeMicroseconds(SERVO_BASE);
}
break;
case EJECTED:
if (millis() - servo_timer < EJECT_DUR) {
Serial.print("\tEJECTING\t");
servo_motor.writeMicroseconds(SERVO_BASE + SERVO_SPEED);
} else {
Serial.print("\EJECTED\t");
servo_position = EJECTED;
servo_motor.writeMicroseconds(SERVO_BASE);
servo_timer = millis();
}
break;
}
} else {
servo_timer = millis();
prev_ls_tray_state = digitalRead(LS_TRAY);
servo_motor.writeMicroseconds(SERVO_BASE);
}
}
void update_lcd (int target_screen) {
if ( screen != target_screen ) {
Serial.print("LCD is printing");
if ( target_screen == 1 ) {
lcd.setCursor(0,0);
lcd.println("Ready to Launch:");
lcd.setCursor(0,1);
lcd.println(" Press a Button ");
}
if (target_screen == 2 ) {
lcd.setCursor(0,0);
lcd.println(" Running Cycle ");
lcd.setCursor(0,1);
lcd.println(" Please Wait ");
}
if (target_screen == 3 ) {
lcd.setCursor(0,0);
lcd.println(" Error: ");
lcd.setCursor(0,1);
lcd.println("Refill Fluid Tank");
}
if (target_screen == 4 ) {
lcd.setCursor(0,0);
lcd.println(" No More Wipes ");
lcd.setCursor(0,1);
lcd.println(" Press Button 3 ");
}
screen = target_screen;
}
}