#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Keypad.h>
#include "HX711.h"
#include <EEPROM.h>
LiquidCrystal_I2C lcd1(0x27, 16, 2);
LiquidCrystal_I2C lcd2(0x3F, 16, 2);
const int LOADCELL_DOUT_PIN = A3;
const int LOADCELL_SCK_PIN = A4;
HX711 scale;
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {22, 23, 24, 25};
byte colPins[COLS] = {26, 27, 28, 29};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
struct User {
char id[14];
char name[16];
int score;
};
const int MAX_USERS = 10;
User users[MAX_USERS] = {
{"6801062611332", "Kitisak", 0},
{"6801062611197", "Nawat", 0},
{"6801062610344", "Nutnicha", 0}
};
int totalUsers = 3;
int currentUserIndex = 2;
const int EEPROM_MAGIC_NUMBER = 123;
String inputID = "";
bool isLoggedIn = false;
const int trig1 = 2, echo1 = 3;
const int trig2 = 4, echo2 = 5;
const int metalSensorPin = A0;
const int lightSensorPin = A2;
Servo servoDiverter;
Servo servoMetal;
Servo servoNonMetal;
void setup() {
Serial.begin(115200);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
pinMode(trig1, OUTPUT); pinMode(echo1, INPUT);
pinMode(trig2, OUTPUT); pinMode(echo2, INPUT);
servoDiverter.attach(9);
servoMetal.attach(10);
servoNonMetal.attach(11);
servoDiverter.write(90);
servoMetal.write(90);
servoNonMetal.write(90);
lcd1.init(); lcd1.backlight();
lcd2.init(); lcd2.backlight();
loadEEPROM();
showIdleDisplay();
}
void loadEEPROM() {
int magic;
EEPROM.get(0, magic);
if (magic != EEPROM_MAGIC_NUMBER) {
EEPROM.put(0, EEPROM_MAGIC_NUMBER);
EEPROM.put(sizeof(int), totalUsers);
for (int i = 0; i < totalUsers; i++) {
EEPROM.put(sizeof(int)*2 + (i * sizeof(User)), users[i]);
}
} else {
EEPROM.get(sizeof(int), totalUsers);
for (int i = 0; i < totalUsers; i++) {
EEPROM.get(sizeof(int)*2 + (i * sizeof(User)), users[i]);
}
}
}
void saveScoreToEEPROM() {
EEPROM.put(sizeof(int)*2 + (currentUserIndex * sizeof(User)), users[currentUserIndex]);
}
void saveNewUserToEEPROM() {
EEPROM.put(sizeof(int), totalUsers);
EEPROM.put(sizeof(int)*2 + (currentUserIndex * sizeof(User)), users[currentUserIndex]);
}
void showIdleDisplay() {
lcd1.clear();
lcd1.setCursor(0, 0); lcd1.print("SMART BIN SYSTEM");
lcd1.setCursor(0, 1); lcd1.print("Please Login...");
}
void updateUserDisplay() {
lcd1.clear();
lcd1.setCursor(0, 0); lcd1.print("User: " + String(users[currentUserIndex].name));
lcd1.setCursor(0, 1); lcd1.print("Score: " + String(users[currentUserIndex].score));
}
void loop() {
char key = keypad.getKey();
if (!isLoggedIn) {
lcd2.setCursor(0, 0); lcd2.print("Enter Student ID");
lcd2.setCursor(0, 1); lcd2.print("ID:" + inputID + " ");
if (key) {
if (key >= '0' && key <= '9') {
if (inputID.length() < 13) inputID += key;
}
else if (key == '*') {
inputID = ""; lcd2.clear();
}
else if (key == '#') {
if (inputID.length() == 13) checkLogin(inputID);
else {
lcd2.clear(); lcd2.print("ID must be 13!");
delay(1000); lcd2.clear();
}
}
}
}
else {
if (key == 'C') {
isLoggedIn = false; inputID = "";
showIdleDisplay();
lcd2.clear(); lcd2.print("Logged Out");
delay(1500); lcd2.clear();
return;
}
else if (key == 'A') {
users[currentUserIndex].score = 0;
saveScoreToEEPROM();
updateUserDisplay();
lcd2.clear(); lcd2.print("Score Reset!");
delay(1500); lcd2.clear();
}
handleSortingProcess();
}
}
void checkLogin(String id) {
int foundIndex = -1;
for (int i = 0; i < totalUsers; i++) {
if (String(users[i].id) == id) { foundIndex = i; break; }
}
lcd2.clear();
if (foundIndex != -1) {
isLoggedIn = true;
currentUserIndex = foundIndex;
updateUserDisplay();
lcd2.print("Login Success!");
delay(1500); lcd2.clear();
}
else {
lcd2.print("ID Not Found!");
lcd2.setCursor(0, 1); lcd2.print("#: Register New");
unsigned long start = millis();
bool confirmed = false;
while(millis() - start < 5000) {
char k = keypad.getKey();
if (k == '#') { confirmed = true; break; }
if (k == '*') break;
}
if (confirmed && totalUsers < MAX_USERS) {
id.toCharArray(users[totalUsers].id, 14);
String tempName = "User_" + id.substring(9);
tempName.toCharArray(users[totalUsers].name, 16);
users[totalUsers].score = 0;
currentUserIndex = totalUsers;
totalUsers++;
isLoggedIn = true;
saveNewUserToEEPROM();
updateUserDisplay();
lcd2.clear(); lcd2.print("Registered!");
} else {
inputID = ""; lcd2.clear();
}
delay(1500);
}
}
void handleSortingProcess() {
long binLevel = getDistance(trig2, echo2);
if (binLevel < 5 && binLevel > 0) {
lcd2.setCursor(0, 0); lcd2.print("BIN IS FULL! ");
return;
}
lcd2.setCursor(0, 0); lcd2.print("Ready to sort...");
lcd2.setCursor(0, 1); lcd2.print("Insert Item ->");
long dropDist = getDistance(trig1, echo1);
if (dropDist > 0 && dropDist <= 10) {
lcd2.clear(); lcd2.print("Processing...");
delay(1000);
int metalVal = analogRead(metalSensorPin);
int lightVal = analogRead(lightSensorPin);
float weight = scale.get_units(1);
int wFactor = map(constrain(weight, 0, 1000), 0, 1000, 1, 10);
String type = ""; int pts = 0;
if (metalVal > 100) {
servoDiverter.write(45);
delay(1000);
if (metalVal > 700) {
type = "Iron/Steel"; pts = 10 + wFactor;
servoMetal.write(180);
} else if (metalVal > 400) {
type = "Aluminum"; pts = 8 + wFactor;
servoMetal.write(90);
} else {
type = "Copper/Brass"; pts = 15 + wFactor;
servoMetal.write(0);
}
delay(2000);
servoMetal.write(90);
} else {
servoDiverter.write(135);
delay(1000);
if (lightVal > 700) {
if(wFactor > 5) {
type = "Clear Bottle"; pts = 5;
servoNonMetal.write(0);
} else {
type = "Plastic"; pts = 3;
servoNonMetal.write(60);
}
} else {
if(wFactor > 4) {
type = "Paper"; pts = 2;
servoNonMetal.write(120);
} else {
type = "Bio/Wood"; pts = 1;
servoNonMetal.write(180);
}
}
delay(2000);
servoNonMetal.write(90);
}
delay(500);
servoDiverter.write(90);
users[currentUserIndex].score += pts;
saveScoreToEEPROM();
updateUserDisplay();
lcd2.clear();
lcd2.print(type);
lcd2.setCursor(0, 1); lcd2.print("Point: +" + String(pts));
delay(3000); lcd2.clear();
}
}
long getDistance(int trig, int echo) {
digitalWrite(trig, LOW); delayMicroseconds(2);
digitalWrite(trig, HIGH); delayMicroseconds(10);
digitalWrite(trig, LOW);
return pulseIn(echo, HIGH) * 0.034 / 2;
}