/**
* Complete project details at https://RandomNerdTutorials.com/arduino-load-cell-hx711/
*
* HX711 library for Arduino - example file
* https://github.com/bogde/HX711
*
* MIT License
* (c) 2018 Bogdan Necula
*
ANGLE => 90 => OPEN
=> 180 => CLOSE
**/
#include <Arduino.h>
#include "HX711.h"
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo ServoValve; // Create a servo object to open & close the valve
Servo ServoCover; // servo to put a cover under the spout
// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 3;
// SERVO'S
const int ServoValvePIN = 9;
const int ServoCoverPIN = 7;
boolean life_weight = false;
boolean moving_window = false;
String received_info = "";
String commandStr = "";
int avg_readings = 1;
HX711 scale;
long longArray[30] ;
int array_pointer = 0 ;
int test = 0;
// variables to calc slope & intercept
double intercept = 0;
double slope = 0;
long X1 = 0; //SIGNAL'
long X2 = 0; //SIGNAL
int Y1 = 1000; //WEIGHT
int Y2 = 4000; //WEIGHT
int slope_and_intercept_calculated = 0;
long read_signal = 0;
int read_weight = 0;
int dosing_weight = 0;
int start_weight = 0;
int end_weight = 0;
int dosing_active = 0;
// tzé formula
// slope = (Y2-Y1) / (X2-X1)
// intercept = X1 - (slope * Y1)
//
// Function to calculate the average of elements in a float array
float calculateAverage(long arr[]) {
float sum = 0;
// Calculate the sum of all elements in the array
for (int i = 0; i < 30; i++) {
sum += arr[i];
}
// Calculate the average
float average = sum / 30;
return average;
}
void setup() {
Serial.begin(115200);
Serial.println("ready to get some commands my master");
//Serial.println("Initializing the scale");
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
//scale.set_scale(-459.542);
scale.set_scale(471.497); // this value is obtained by calibrating the scale with known weights; see the README for details
scale.tare(); // reset the scale to 0
ServoCover.attach(ServoCoverPIN); // Attach the servo
ServoValve.attach(ServoValvePIN); // Attach the servo
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("READY TO BE");
lcd.setCursor(1, 1);
lcd.print("CALIBRATED");
delay(500);
for (int angle = 0; angle <= 180; angle++) {
ServoCover.write(angle); // Set the servo position
ServoValve.write(angle); // Set the servo position
delay(20); // Wait for servo to reach the position
}
ServoCover.detach();
ServoValve.detach();
}
void loop() {
// Serial.print("one reading:\t");
// Serial.print(scale.get_units(), 1);
//Serial.print("\t| average:\t");
//Serial.println(scale.get_units(10), 5);
// delay(5000);
//Serial.println(scale.read());
if (Serial.available()) {
char receivedChar = Serial.read();
Serial.print(receivedChar);
if (receivedChar == '\r') {
// Process the command when EOL is received
int the_number = commandStr.substring(3).toInt();
commandStr = commandStr.substring(0, 3);
if (commandStr == "PRL"){
if (the_number == 1) {
// print live = true
life_weight = true;
lcd.clear();
lcd.setCursor(1, 0);
//lcd.print("Life DATA !");
test = 0;
}
else{
life_weight = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("NO Life DATA :-(");
}
}
if (commandStr == "MOW"){
if (the_number == 1) {
// print live = true
moving_window = true;
Serial.println("monving_window = true");
}
else{
moving_window = false;
Serial.println("monving_window = false");
}
}
if (commandStr == "LON"){
lcd.backlight();
}
if (commandStr == "LOF"){
lcd.noBacklight();
}
if (commandStr == "SY1"){
Y1 = the_number;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Y1 = ");
lcd.setCursor(6, 0);
lcd.print(Y1);
}
if (commandStr == "SY2"){
Y2 = the_number;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Y2 = ");
lcd.setCursor(6, 0);
lcd.print(Y2);
}
if (commandStr == "AVG"){
// alter angle valve servo
avg_readings = the_number;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("New AVG = ");
lcd.setCursor(10, 0);
lcd.print(avg_readings);
delay(2000);
}
if (commandStr == "AAA"){
// alter angle valve servo
ServoValve.attach(ServoValvePIN); // Attach the servo
ServoValve.write(the_number);
delay(1000);
ServoCover.detach();
ServoValve.detach();
}
if (commandStr == "RES"){
// RESET
intercept = 0;
slope = 0;
slope_and_intercept_calculated = 0;
Serial.println("reset done");
}
if (commandStr == "BBB"){
// alter angle valve servo
ServoCover.attach(ServoCoverPIN); // Attach the servo
ServoCover.write(the_number);
delay(1000);
ServoCover.detach();
}
// Convert the following 6 characters to an integer
if (commandStr == "CAL"){
// CALIBRATE LOW
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("CAL LOW WEIGHT");
X1 = scale.read_average(100);
lcd.setCursor(1, 1);
lcd.print(X1);
}
if (commandStr == "CAH"){
// CALIBRATE LOW
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("CAL HIGH WEIGHT");
X2 = scale.read_average(100);
lcd.setCursor(1, 1);
lcd.print(X2);
}
if (commandStr == "DOS"){
// DOSING
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("DOSING");
dosing_weight = the_number;
lcd.setCursor(0, 1);
lcd.print(dosing_weight);
lcd.setCursor(4, 1);
lcd.print(" gram ");
read_signal = scale.read_average(100);
start_weight = intercept + slope * read_signal;
end_weight = start_weight - dosing_weight;
ServoCover.attach(ServoCoverPIN); // Attach the servo
ServoValve.attach(ServoValvePIN); // Attach the servo
ServoCover.write(90); // Set the servo position
delay(2000); // make sure to wait until cover is full open
ServoValve.write(90); // Set the servo position
dosing_active = 1;
}
if (commandStr == "INF"){
Serial.print("X1 = ");
Serial.println(X1);
Serial.print("Y1 = ");
Serial.println(Y1);
Serial.print("X2 = ");
Serial.println(X2);
Serial.print("Y2 = ");
Serial.println(Y2);
Serial.print("slope_and_intercept_calculated = ");
Serial.println(slope_and_intercept_calculated);
}
delay(10);
Serial.print("received command :");
Serial.print(commandStr);
Serial.print(" received number :");
Serial.println(the_number);
commandStr = "";
}
else{
commandStr += receivedChar;
}
}
if ((X1 != 0) && (X2 != 0) && (slope_and_intercept_calculated == 0)){
// time to calc slope and intercept !
Serial.println("calc slope & intercept");
Serial.print("X1 = ");
Serial.println(X1);
Serial.print("Y1 = ");
Serial.println(Y1);
Serial.print("X2 = ");
Serial.println(X2);
Serial.print("Y2 = ");
Serial.println(Y2);
Serial.print("slope_and_intercept_calculated = ");
Serial.println(slope_and_intercept_calculated);
slope = (double)(Y2-Y1) / (X2-X1);
intercept = Y1 - (slope * X1);
Serial.print("Slope = ");
Serial.println(slope);
Serial.print("Intercept = ");
Serial.println(intercept);
slope_and_intercept_calculated = 1;
}
if (life_weight == true) {
//Serial.println(scale.get_units(1), 1);
//Serial.print("LW: ");
Serial.println(scale.read_average(avg_readings));
read_signal = scale.read_average(avg_readings);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print(read_signal);
read_weight = intercept + slope * read_signal;
lcd.setCursor(1, 1);
lcd.print(read_weight);
lcd.setCursor(10, 1);
lcd.print(test);
test++;
if (test > 8){test=0;}
}
// moving window
longArray[array_pointer] = scale.read();
if (array_pointer < 30){
array_pointer++;
}
else{
array_pointer = 0;
}
if (moving_window == true) {
//Serial.println(scale.get_units(1), 1);
Serial.print("MW: ");
Serial.println(calculateAverage(longArray));
}
if (dosing_active > 0){
// start_weight = intercept + slope * read_signal;
end_weight = start_weight - dosing_weight;
read_signal = scale.read_average(avg_readings);
read_weight = intercept + slope * read_signal;
lcd.setCursor(1, 5);
lcd.print(" ");
lcd.print(read_weight);
if (read_weight <= end_weight){
dosing_active = 0;
ServoCover.write(180); // Set the servo position
ServoValve.write(180); // Set the servo position
delay(1000);
ServoCover.detach();
ServoValve.detach();
}
}
}