//Official version going into production
// v3.1 - Removing the load cell functions. Load cell doesn't seems to be working properly, and could potentially cause issues. Actuator depression will be controlled by distance feedback only.
// v3.2 - Updating the LCD timing functions to convert seconds to minutes and display it properly.
// v3.3 - Removing the feedback sensing requirement for operation. I have no idea why the feedback sensor failed, but it doesn't read anywhere close to consistantly. Setting the actuator to function on time instead.
// v3.4 - 6/20/22 - Operators experiencing issue where code seems to hang while displaying 'Water solenoid closed' message. Atttempting to resolve this by adding small delays (2us) before each transmission (per some random forum posts)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~ LIBRARIES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// LCD screen library (I2C chipset)
#include <LiquidCrystal_I2C.h>
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// Current system version
const String sys_ver = "v3.4";
// Initialize LED pushbutton
const int button = 5;
const int button_LED = 4;
int button_state = 0;
// Initialize LCD library and link LCD to corresponding Arduino pins, as well as # of rows and columns
LiquidCrystal_I2C lcd(0x27, 20,4);
// Initialize solenoind pins
const int solenoid_air = 8; // Solenoid 1 (air, CH1)
const int solenoid_water = 9; // Solenoid 2 (water, CH2)
// Initialize actuator pins
const int motor_in = 2;
const int motor_out = 3;
const int act_feedback = A4; // Analog pin for actuator distance feedback
int feedback;
// Process variables **All times are in seconds**
const int time_delay = 3; // How much time between doing different operations
// const int flush_time = 599; // Time the injector is being flushed
const int flush_time = 5;
const int dry_time = 30; // Air only, no water
const int min_distance = 50; // 'Home' position for the actuator
const int max_distance = 373; // Maximum extended distance for actuator. This should result in the actuator pressing into the base.
// Initialize functions
void actuator_extend(int time);
void actuator_stop();
void actuator_retract(int time);
// I don't remember if I used this anywhere, but it might be important.
boolean linear = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~ MAIN CODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
void setup() {
// Start serial monitoring
Serial.begin(9600);
Serial.println("Powerflush systems test initializing");
// Initialize button pins
pinMode(button, INPUT_PULLUP); // PULLUP voltage to use button (ie. waits for LOW)
pinMode(button_LED, OUTPUT); // Red LED light around the button
Serial.println("Button + LED initialized");
// Initialize LCD screen
delayMicroseconds(2);
lcd.begin(20,4);
delayMicroseconds(2);
lcd.backlight();
delayMicroseconds(2);
lcd.clear();
// Print message at startup
delayMicroseconds(2);
lcd.setCursor(0, 1);
delayMicroseconds(2);
lcd.print("System initializing");
delayMicroseconds(2);
lcd.clear();
delayMicroseconds(2);
lcd.setCursor(0, 1);
delayMicroseconds(2);
lcd.print("System version " + sys_ver);
Serial.println("LCD Initialized");
delay(5000);
// These pins control the solenoids
pinMode(solenoid_air, OUTPUT); // LOW for relay ON; HIGH for relay OFF
pinMode(solenoid_water, OUTPUT);
Serial.println("Solenoids initialized");
delayMicroseconds(2);
lcd.clear();
delayMicroseconds(2);
lcd.setCursor(0,1);
delayMicroseconds(2);
lcd.print("Solenoids ok");
// Actuator initialization
pinMode(motor_out, OUTPUT);
pinMode(motor_in, OUTPUT);
pinMode(act_feedback, INPUT);
actuator_home(); // Check if the actuator is extended, and send it home if it is
Serial.println("Actuator initialized");
delayMicroseconds(2);
lcd.setCursor(0,2);
delayMicroseconds(2);
lcd.print("Actuator ok");
delay(1000);
// End of setup loop
Serial.println("Initialization setup complete");
delayMicroseconds(2);
lcd.clear();
delayMicroseconds(2);
lcd.setCursor(1,1);
delayMicroseconds(2);
lcd.print("System initialized");
delay(2000);
lcd.clear();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Main program loop
void loop() {
// Indicate system is ready to function
delayMicroseconds(2);
lcd.setCursor(4,0);
delayMicroseconds(2);
lcd.print("System ready!");
delayMicroseconds(2);
lcd.setCursor(4,2);
delayMicroseconds(2);
lcd.print("Press button");
delayMicroseconds(2);
lcd.setCursor(6,3);
delayMicroseconds(2);
lcd.print("to begin");
// Read button states
button_state = digitalRead(button);
// Flash LED
digitalWrite(button_LED, HIGH);
delay(500);
if (button_state == LOW){
execute();
}
digitalWrite(button_LED, LOW);
delay(500);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void execute() {
// Main operating fucntion that is called when button is pressed
Serial.println("Button has been pressed");
delayMicroseconds(2);
lcd.clear();
delayMicroseconds(2);
lcd.setCursor(2,0);
delayMicroseconds(2);
lcd.print("System starting: ");
// Set the LED to constantly on to indicate it is running
digitalWrite(button_LED, HIGH);
// Extend the actuator until feedback sensor is tripped
actuator_extend();
delayMicroseconds(2);
lcd.setCursor(2,1);
delayMicroseconds(2);
lcd.print("Actuator set");
delay(5000);
// Open the air solenoid
lcd_timer(time_delay, "Opening air SV");
digitalWrite(solenoid_air, HIGH);
delayMicroseconds(2);
lcd.setCursor(1,1);
delayMicroseconds(2);
lcd.print("Air solenoid open");
delay(3000);
// Open the water solenoid
lcd_timer(time_delay, "Opening water SV");
digitalWrite(solenoid_water, HIGH);
delayMicroseconds(2);
lcd.setCursor(1,1);
delayMicroseconds(2);
lcd.print("Water solenoid open");
delay(3000);
// Count down the flush process, while displaying the time left on the LCD screen
lcd_timer(flush_time, "Flushing injector");
// Reset the water solenoid
digitalWrite(solenoid_water, LOW);
delayMicroseconds(2);
lcd.print("Water solenoid closed");
// Count down the blowoff
lcd_timer(dry_time, "Drying part");
// Reset the air solenoid
digitalWrite(solenoid_air, LOW);
delay(3000);
// Reset the actuator
actuator_home();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This function takes two arguments: 1) time(in seconds) and 2) a text string. It will display the text on the LCD screen in row 1, and countdown the given time, displaying time remaining in row 2.
void lcd_timer(int time, char text[]) {
int time_remain = time;
delayMicroseconds(2);
lcd.clear();
delayMicroseconds(2);
lcd.setCursor(0,0);
delayMicroseconds(2);
lcd.print(text);
delayMicroseconds(2);
lcd.setCursor(0,1);
delayMicroseconds(2);
lcd.print("--------------------");
delayMicroseconds(2);
lcd.setCursor(0,2);
delayMicroseconds(2);
lcd.print("Time remaining: ");
// This loop basically does the countdown + some time formatting stuff
while (time_remain > 0){
String time_remain_sec;
String time_remain_min;
String time_remain1 = String(time_remain);
// Convert time to minutes
if (time_remain >= 60){
time_remain_min = String(time_remain / 60);
time_remain_sec = String(time_remain % 60);
}
else {
time_remain_min = "0";
time_remain_sec = String(time_remain);
}
// Check for length of time (if < 10s, need to add a 0)
if (time_remain_sec.length() == 1){
time_remain_sec = String("0" + time_remain_sec);
}
// Combine the minutes + seconds into a display friendly string
String time_display = String(time_remain_min + ":" + time_remain_sec);
delayMicroseconds(2);
lcd.setCursor(16,2);
delayMicroseconds(2);
lcd.print(time_display);
Serial.println(time_display);
delay(1000);
--time_remain;
}
delayMicroseconds(2);
lcd.clear();
return;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This function will check if the actuator is extended, and if it is, will retract it to its home position.
void actuator_home() {
int actuator_dist;
actuator_dist = analogRead(act_feedback);
Serial.println("HOME FUNCTION");
int i = 0;
while (i < 5){
Serial.println(actuator_dist);
digitalWrite(motor_in, HIGH);
digitalWrite(motor_out, LOW);
actuator_dist = analogRead(act_feedback);
delay(1000);
i++;
}
actuator_stop();
Serial.println("Actuator returned home");
return;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This function fully retracts the actuator
void actuator_retract() {
digitalWrite(motor_in, HIGH);
digitalWrite(motor_out, LOW);
actuator_stop();
return;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This function stops the actuator (save time on writing)
void actuator_stop() {
digitalWrite(motor_out, LOW);
digitalWrite(motor_in, LOW);
return;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This function will extend the actuator until a certain force is reached on the load cell, or the actuator reaches its max distance
void actuator_extend() {
Serial.println("actuator_extend function entered");
feedback = analogRead(act_feedback);
Serial.println(feedback);
Serial.println("Entering while loop");
int i = 0;
while (i < 5){
Serial.println(feedback);
digitalWrite(motor_out, HIGH);
digitalWrite(motor_in, LOW);
delay(1000);
i++;
}
actuator_stop();
return;
}
// END OF PROGRAM
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~