-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIKADUHA.ino
More file actions
352 lines (303 loc) · 11.3 KB
/
IKADUHA.ino
File metadata and controls
352 lines (303 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>
/*
===============================================================================
Smart Waste Sorting Bin (Documentation)
===============================================================================
PROJECT GOAL:
Automate ang pag sort ng basura into:
1) Paper / Biodegradable -> left flap (Servo 1)
2) Plastic / Non-bio -> right flap (Servo 2)
HIGH-LEVEL FLOW:
1. setup()
- I set ang pins, servo, and WiFi Access Point.
- I start ang web server and i register ang endpoints/buttons.
2. loop()
- Laging tumatanggap ng web requests (buttons sa phone/laptop).
- Binabasa ang sensors.
- Kapag manual mode: mag sort lang via physical button o web button.
- Kapag automatic mode: mag sort kapag may na detect ang sensor.
3. classifyAndSort(capVal, irVal)
- Decision logic kung paper, plastic, o walang item.
4. sortPaper()/sortPlastic()
- Gumagalaw ang tamang servo para mag Open/close ang flap.
IMPORTANT BEHAVIOR:
- Priority ng detection: Capacitive muna, then IR.
Ibig sabihin kung parehong active, plastic branch (capacitive) ang mauuna.
- Walang detection = walang servo movement (skip).
- ESP32 ang gumagawa ng sariling WiFi network (no router needed).
===============================================================================
*/
// ====== Wi-Fi Access Point credentials ======
// Dito kumokonekta ang phone/laptop para sa web control page.
const char* ssid = "SmartBin";
const char* password = "smartbin123";
// Web server sa port 80 (default HTTP port)
WebServer server(80);
// Mode flag:
// false = Manual mode
// true = Automatic mode
bool autoMode = false;
bool prevAutoMode = false;
// Counters na pinapakita sa web UI
unsigned long bioCount = 0; // paper count
unsigned long nonBioCount = 0; // plastic count
// ====== Pin assignments ======
// Sensors
const int capPin = 21; // capacitive sensor digital output
const int irPin = 19; // IR sensor digital output
// Input button
const int buttonPin = 4; // optional physical pushbutton for manual trigger
// Servo outputs
const int servo1Pin = 13; // left flap servo (paper)
const int servo2Pin = 14; // right flap servo (plastic)
// ====== Sensor detect logic (IMPORTANT) ======
// Iba-iba ang behavior ng sensor modules:
// - Some modules: LOW = detect
// - Others (e.g. some capacitive boards): HIGH = detect
//
// If laging wrong ang sorting, usually dito lang kailangan baguhin.
const int CAP_DETECT_STATE = LOW; // most capacitive modules used in this project are active-LOW
const int IR_DETECT_STATE = LOW; // most IR obstacle sensors are active-LOW
// ====== Auto mode anti-false-trigger settings ======
// Goal: iwas tuloy-tuloy na sort kapag "stuck detected" ang sensor.
const unsigned long DETECT_STABLE_MS = 120; // detection must stay true this long
const unsigned long AUTO_COOLDOWN_MS = 2000; // minimum gap between auto sorts
// ====== Servo angles (i calibrate based sa physical build) ======
// Servo1 (left flap - paper)
int servo1Home = 0;
int servo1Left = 90;
// Servo2 (right flap - plastic)
int servo2Home = 90;
int servo2Right = 180;
// Servo speed control: mas mataas = mas mabagal
int stepDelay = 10; // ms per degree
// Servo objects
Servo servo1;
Servo servo2;
// Track current servo positions para smooth ang paggalaw
int servo1Current = servo1Home;
int servo2Current = servo2Home;
// Auto mode state trackers
bool autoTriggerLatched = false; // true = wait muna ng clear state bago next sort
unsigned long detectStartMs = 0; // start time ng current detect window
unsigned long lastAutoSortMs = 0; // last auto sort timestamp
// ====== Function prototypes ======
void classifyAndSort(int capVal, int irVal);
void sortPaper();
void sortPlastic();
void slowMoveServo(Servo &s, int ¤tAngle, int targetAngle);
bool isCapDetected(int capVal);
bool isIrDetected(int irVal);
bool isAnyDetected(int capVal, int irVal);
bool isSingleSensorDetected(int capVal, int irVal);
String htmlPage();
// ====== Web page template ======
// Ito ang simpleng HTML dashboard na makikita sa http://192.168.4.1
String htmlPage() {
String html = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width,initial-scale=1'>";
html += "<title>Smart Bin</title></head><body>";
html += "<h2>Smart Bin Control</h2>";
html += "<p>Mode: <b>" + String(autoMode ? "Automatic" : "Manual") + "</b></p>";
html += "<button onclick=\"fetch('/autoOn').then(()=>location.reload())\">Automatic Mode</button>";
html += "<button onclick=\"fetch('/autoOff').then(()=>location.reload())\">Manual Mode</button>";
html += "<button onclick=\"fetch('/sort').then(()=>location.reload())\">Sort Item</button>";
html += "<h3>Counters</h3>";
html += "<p>Biodegradable (Paper): " + String(bioCount) + "</p>";
html += "<p>Non-Biodegradable (Plastic): " + String(nonBioCount) + "</p>";
html += "<button onclick=\"fetch('/reset').then(()=>location.reload())\">Reset Counters</button>";
html += "</body></html>";
return html;
}
void setup() {
Serial.begin(115200);
// Sensor/button pin modes
pinMode(capPin, INPUT_PULLUP);
pinMode(irPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
Serial.print("CAP_DETECT_STATE: ");
Serial.println(CAP_DETECT_STATE == HIGH ? "HIGH" : "LOW");
Serial.print("IR_DETECT_STATE: ");
Serial.println(IR_DETECT_STATE == HIGH ? "HIGH" : "LOW");
Serial.println("Expected idle state: CAP=HIGH, IR=HIGH (or 1).");
Serial.println("If CAP stays LOW while no item is present, check cap sensor wiring/sensitivity.");
// Servo setup
servo1.setPeriodHertz(50);
servo2.setPeriodHertz(50);
servo1.attach(servo1Pin, 500, 2400);
servo2.attach(servo2Pin, 500, 2400);
servo1.write(servo1Home);
servo2.write(servo2Home);
// WiFi Access Point mode:
// ESP32 creates its own WiFi network (no router needed).
WiFi.softAP(ssid, password);
Serial.println("Access Point started!");
Serial.print("Connect to WiFi: ");
Serial.println(ssid);
Serial.print("Then open browser to: http://");
Serial.println(WiFi.softAPIP());
// ====== Web server routes ======
// Home page
server.on("/", []() {
server.send(200, "text/html", htmlPage());
});
// Switch to automatic mode
server.on("/autoOn", []() {
autoMode = true;
server.send(200, "text/plain", "Automatic mode ON");
});
// Switch to manual mode
server.on("/autoOff", []() {
autoMode = false;
server.send(200, "text/plain", "Manual mode ON");
});
// Reset counters
server.on("/reset", []() {
bioCount = 0;
nonBioCount = 0;
server.send(200, "text/plain", "Counters reset");
});
// Manual one-time sort trigger from web button
server.on("/sort", []() {
int capVal = digitalRead(capPin);
int irVal = digitalRead(irPin);
classifyAndSort(capVal, irVal);
server.send(200, "text/plain", "Item sorted");
});
server.begin();
}
void loop() {
// Laging i handle ang incoming web requests
server.handleClient();
// read current sensor state
// Detection is based on CAP_DETECT_STATE / IR_DETECT_STATE config above.
int capVal = digitalRead(capPin);
int irVal = digitalRead(irPin);
bool capDetected = isCapDetected(capVal);
bool irDetected = isIrDetected(irVal);
bool singleDetected = isSingleSensorDetected(capVal, irVal);
bool anyDetected = isAnyDetected(capVal, irVal);
// Track mode transition para ma-arm ng tama ang automatic mode.
if (autoMode && !prevAutoMode) {
// Kapag pagpasok ng auto mode ay detected na agad, huwag munang mag-sort.
// Hintayin munang mag-clear then new detect event.
autoTriggerLatched = anyDetected;
detectStartMs = anyDetected ? millis() : 0;
Serial.println(anyDetected
? "Auto mode ON: sensor already detected, waiting for clear state."
: "Auto mode ON: armed.");
} else if (!autoMode && prevAutoMode) {
autoTriggerLatched = false;
detectStartMs = 0;
}
prevAutoMode = autoMode;
// ====== Manual mode behavior ======
// Sa manual mode, sorting only happens kapag pinindot ang physical button.
if (!autoMode && digitalRead(buttonPin) == LOW) {
Serial.println("Manual button pressed");
classifyAndSort(capVal, irVal);
delay(1000); // basic debounce / anti-repeat delay
}
// ====== Automatic mode behavior ======
// Mag-sort lang sa NEW + STABLE detection, then wait for clear state.
// IMPORTANT: auto-sort only works when EXACTLY ONE sensor is active.
// If both sensors are active, ambiguous state siya (skip).
if (autoMode) {
if (!singleDetected) {
autoTriggerLatched = false;
detectStartMs = 0;
if (capDetected && irDetected) {
// Both active usually means mounting/reflection issue (e.g., sensor seeing plywood/hole).
// Skip sorting to avoid wrong flap movement.
delay(50);
}
} else {
if (detectStartMs == 0) {
detectStartMs = millis();
}
bool stableDetect = (millis() - detectStartMs) >= DETECT_STABLE_MS;
bool cooldownDone = (millis() - lastAutoSortMs) >= AUTO_COOLDOWN_MS;
if (!autoTriggerLatched && stableDetect && cooldownDone) {
classifyAndSort(capVal, irVal);
lastAutoSortMs = millis();
autoTriggerLatched = true; // require clear state before next auto sort
}
}
}
}
bool isAnyDetected(int capVal, int irVal) {
return isCapDetected(capVal) || isIrDetected(irVal);
}
bool isSingleSensorDetected(int capVal, int irVal) {
bool capDetected = isCapDetected(capVal);
bool irDetected = isIrDetected(irVal);
return capDetected ^ irDetected;
}
// ====== Core decision logic ======
// Decision order:
// 1) Capacitive detected -> treat as plastic
// 2) Else if IR detected -> treat as paper
// 3) Else -> no item, skip
void classifyAndSort(int capVal, int irVal) {
bool capDetected = isCapDetected(capVal);
bool irDetected = isIrDetected(irVal);
Serial.print("CAP: ");
Serial.print(capVal);
Serial.print(" | IR: ");
Serial.println(irVal);
if (capDetected && irDetected) {
Serial.println("Ambiguous: BOTH sensors active. Skipping sort.");
return;
}
if (capDetected) {
Serial.println("Plastic detected -> Servo2 (right)");
sortPlastic();
nonBioCount++;
} else {
if (irDetected) {
Serial.println("Paper detected -> Servo1 (left)");
sortPaper();
bioCount++;
} else {
Serial.println("No item detected, skipping.");
return;
}
}
}
bool isCapDetected(int capVal) {
return capVal == CAP_DETECT_STATE;
}
bool isIrDetected(int irVal) {
return irVal == IR_DETECT_STATE;
}
// ====== Smooth servo movement helper ======
// Slowly nya i move ang servo from currentAngle to targetAngle.
void slowMoveServo(Servo &s, int ¤tAngle, int targetAngle) {
if (currentAngle < targetAngle) {
for (int pos = currentAngle; pos <= targetAngle; pos++) {
s.write(pos);
delay(stepDelay);
}
} else {
for (int pos = currentAngle; pos >= targetAngle; pos--) {
s.write(pos);
delay(stepDelay);
}
}
currentAngle = targetAngle;
}
// ====== Servo action: paper ======
// Open left flap, wait for item to fall, close flap.
void sortPaper() {
slowMoveServo(servo1, servo1Current, servo1Left);
delay(500);
slowMoveServo(servo1, servo1Current, servo1Home);
}
// ====== Servo action: plastic ======
// Open right flap, wait for item to fall, close flap.
void sortPlastic() {
slowMoveServo(servo2, servo2Current, servo2Right);
delay(500);
slowMoveServo(servo2, servo2Current, servo2Home);
}