Community project
Three-Way Smart Waste Sorter
This smart waste sorter automatically separates trash into three categories—toxic, organic, and inorganic—using gesture recognition and material detection. The system uses ultrasonic sensors to measure fill levels in each bin, an IR obstacle sensor to detect when compartments are full, and a moisture sensor to identify wet waste that shouldn't go in certain containers. Three servo-controlled lids open automatically when waste is detected, and LEDs indicate the status of each bin.
Builders will receive a complete wiring diagram showing how to connect the HC-SR04 ultrasonic sensors, IR sensors, SG90 servos, and moisture sensor to an Arduino Uno, along with a parts list, pre-written firmware, and step-by-step assembly instructions. The guide covers mounting the three servos on the bin lids, positioning the sensors, calibrating detection thresholds, and testing the sorting logic.
Wiring diagram

Gather all the parts
Assemble it in 6 steps
1. Pasang tiga servo pada penutup
Pasang servo_toxic pada wadah toxic, servo_anorganic pada wadah anorganik, dan servo_organic pada wadah organik. Sebelum memasang lengan servo, posisikan setiap servo pada sudut tertutup agar sudut 0 menutup dan 90 membuka.
- Jangan memaksa lengan servo dengan tangan saat servo mendapat daya karena roda giginya dapat rusak.
2. Pasang sensor tinggi sampah
Pasang tiga HC-SR04 di bagian atas wadah dengan kedua lingkarannya menghadap ke bawah. Pasang setiap sensor IR menghadap tumpukan sampah sekitar 4–5 cm dari batas penuh, lalu putar sekrup kecilnya sampai dapat mendeteksi sampah.
- Jangan menutup dua lubang bundar HC-SR04 karena sensor tidak dapat mengukur jarak.
3. Pasang sensor pemilah di lubang masuk
Pasang moisture_yl83 pada jalur masuk agar bagian probe menyentuh sampah yang lewat, dan pasang ultrasonic_gesture menghadap pengguna di depan lubang masuk. Gerakan tangan pada jarak 8 cm dipakai untuk memilih wadah.
- Jangan merendam papan YL-83; hanya bagian probe yang boleh terkena sampah lembap.
4. Hubungkan sensor ke Arduino Uno
Hubungkan seluruh VCC sensor ke 5V (power) dan seluruh GND ke GND (ground). Hubungkan HC-SR04 toxic: TRIG ke D2 dan ECHO ke D6 (signal); anorganik: TRIG ke D3 dan ECHO ke D7 (signal); organik: TRIG ke D4 dan ECHO ke D8 (signal); sensor gerakan: TRIG ke D5 dan ECHO ke D9 (signal). Hubungkan OUT IR toxic ke D10, anorganik ke D11, organik ke D12 (signal), serta AO YL-83 ke A0 (signal).
5. Hubungkan servo dan LED
Hubungkan kabel sinyal servo toxic ke D13, servo anorganik ke A1, dan servo organik ke A2 (signal). Hubungkan kabel merah servo ke 5V dari supply_5v (power), serta kabel cokelat atau hitam ke GND (ground). Hubungkan A3 ke resistor 220 Ω lalu ke kaki panjang LED merah, A4 ke resistor 220 Ω lalu ke kaki panjang LED kuning, dan A5 ke resistor 220 Ω lalu ke kaki panjang LED hijau (signal). Kaki pendek setiap LED menuju GND (ground).
- Jangan mengambil daya ketiga servo dari pin 5V Arduino yang berasal dari USB; gunakan supply_5v 5 V minimal 3 A.
- Sambungkan GND supply_5v ke GND Arduino — tanpa ground bersama servo dapat bergerak tidak menentu.
6. Nyalakan dan atur batas
Hubungkan Arduino Uno ke USB untuk pemrograman. Hubungkan supply_5v ke servo dan sensor, pastikan ground supply_5v serta ground Arduino tersambung. Atur sekrup ketiga sensor IR saat tumpukan sampah berada sekitar 4–5 cm dari sensornya.
- LED merah, kuning, atau hijau menyala hanya saat penutup wadahnya terbuka.
Review all connections
1. Connections between "supply_5v" and "Arduino"
2. Connections between "ultrasonic_toxic" and "Arduino"
3. Connections between "ultrasonic_anorganic" and "Arduino"
4. Connections between "ultrasonic_organic" and "Arduino"
5. Connections between "ultrasonic_gesture" and "Arduino"
6. Connections between "ir_toxic" and "Arduino"
7. Connections between "ir_anorganic" and "Arduino"
8. Connections between "ir_organic" and "Arduino"
9. Connections between "moisture_yl83" and "Arduino"
10. Connections between "servo_toxic" and "Arduino"
11. Connections between "servo_anorganic" and "Arduino"
12. Connections between "servo_organic" and "Arduino"
13. Connections between "led_res_toxic" and "Arduino"
14. Connections between "led_toxic" and "Arduino"
15. Connections between "led_res_anorganic" and "Arduino"
16. Connections between "led_anorganic" and "Arduino"
17. Connections between "led_res_organic" and "Arduino"
18. Connections between "led_organic" and "Arduino"
Deploy the firmware
#include <Arduino.h>
#include <Servo.h>
#define TOXIC_TRIG_PIN 2
#define TOXIC_ECHO_PIN 6
#define ANORGANIC_TRIG_PIN 3
#define ANORGANIC_ECHO_PIN 7
#define ORGANIC_TRIG_PIN 4
#define ORGANIC_ECHO_PIN 8
#define GESTURE_TRIG_PIN 5
#define GESTURE_ECHO_PIN 9
#define TOXIC_FULL_IR_PIN 10
#define ANORGANIC_FULL_IR_PIN 11
#define ORGANIC_FULL_IR_PIN 12
#define MOISTURE_PIN A0
#define TOXIC_SERVO_PIN 13
#define ANORGANIC_SERVO_PIN A1
#define ORGANIC_SERVO_PIN A2
#define TOXIC_LED_PIN A3
#define ANORGANIC_LED_PIN A4
#define ORGANIC_LED_PIN A5
const int FULL_DISTANCE_CM = 5;
const int GESTURE_DISTANCE_CM = 8;
const int MOISTURE_WET_THRESHOLD = 450;
const unsigned long GESTURE_WINDOW_MS = 500;
const unsigned long LID_OPEN_MS = 1500;
Servo toxicServo, anorganicServo, organicServo;
int toxicDistance = 400, anorganicDistance = 400, organicDistance = 400;
bool gesturePresentLast = false;
unsigned long firstGestureAt = 0, nextBinReadAt = 0;
uint8_t gestureCount = 0;
int readDistanceCm(uint8_t trig, uint8_t echo, int maximum) {
digitalWrite(trig, LOW); delayMicroseconds(3);
digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW);
unsigned long duration = pulseIn(echo, HIGH, (unsigned long)maximum * 58UL + 2000UL);
return duration ? (int)(duration / 58UL) : maximum + 1;
}
bool binIsFull(int distance, uint8_t irPin) { return distance <= FULL_DISTANCE_CM || digitalRead(irPin) == LOW; }
bool materialIsWet() { return analogRead(MOISTURE_PIN) < MOISTURE_WET_THRESHOLD; }
void openLid(Servo &servo, uint8_t ledPin, bool full, const char *name) {
if (full) { Serial.print(name); Serial.println(" bin is full; lid stays closed."); return; }
digitalWrite(ledPin, HIGH); servo.write(90); Serial.print("Opening "); Serial.println(name);
delay(LID_OPEN_MS); servo.write(0); digitalWrite(ledPin, LOW);
}
void updateBinLevels() {
toxicDistance = readDistanceCm(TOXIC_TRIG_PIN, TOXIC_ECHO_PIN, 30); delay(25);
anorganicDistance = readDistanceCm(ANORGANIC_TRIG_PIN, ANORGANIC_ECHO_PIN, 30); delay(25);
organicDistance = readDistanceCm(ORGANIC_TRIG_PIN, ORGANIC_ECHO_PIN, 30);
}
void setup() {
Serial.begin(115200);
const uint8_t trigPins[] = {TOXIC_TRIG_PIN, ANORGANIC_TRIG_PIN, ORGANIC_TRIG_PIN, GESTURE_TRIG_PIN};
const uint8_t echoPins[] = {TOXIC_ECHO_PIN, ANORGANIC_ECHO_PIN, ORGANIC_ECHO_PIN, GESTURE_ECHO_PIN};
for (uint8_t p : trigPins) pinMode(p, OUTPUT);
for (uint8_t p : echoPins) pinMode(p, INPUT);
pinMode(TOXIC_FULL_IR_PIN, INPUT); pinMode(ANORGANIC_FULL_IR_PIN, INPUT); pinMode(ORGANIC_FULL_IR_PIN, INPUT);
pinMode(TOXIC_LED_PIN, OUTPUT); pinMode(ANORGANIC_LED_PIN, OUTPUT); pinMode(ORGANIC_LED_PIN, OUTPUT);
digitalWrite(TOXIC_LED_PIN, LOW); digitalWrite(ANORGANIC_LED_PIN, LOW); digitalWrite(ORGANIC_LED_PIN, LOW);
toxicServo.attach(TOXIC_SERVO_PIN); anorganicServo.attach(ANORGANIC_SERVO_PIN); organicServo.attach(ORGANIC_SERVO_PIN);
toxicServo.write(0); anorganicServo.write(0); organicServo.write(0);
updateBinLevels(); nextBinReadAt = millis() + 400; Serial.println("Smart trash sorter ready.");
}
void loop() {
unsigned long now = millis();
if (now >= nextBinReadAt) { updateBinLevels(); nextBinReadAt = millis() + 400; }
if (materialIsWet()) {
openLid(organicServo, ORGANIC_LED_PIN, binIsFull(organicDistance, ORGANIC_FULL_IR_PIN), "organic");
gestureCount = 0; firstGestureAt = 0; delay(100); return;
}
int gestureDistance = readDistanceCm(GESTURE_TRIG_PIN, GESTURE_ECHO_PIN, 12);
bool gesturePresent = gestureDistance <= GESTURE_DISTANCE_CM;
if (gesturePresent && !gesturePresentLast) {
if (gestureCount == 0 || now - firstGestureAt > GESTURE_WINDOW_MS) { gestureCount = 1; firstGestureAt = now; }
else { gestureCount++; }
}
gesturePresentLast = gesturePresent;
if (gestureCount >= 2 && now - firstGestureAt <= GESTURE_WINDOW_MS) {
openLid(toxicServo, TOXIC_LED_PIN, binIsFull(toxicDistance, TOXIC_FULL_IR_PIN), "toxic"); gestureCount = 0; firstGestureAt = 0;
} else if (gestureCount == 1 && now - firstGestureAt > GESTURE_WINDOW_MS) {
openLid(anorganicServo, ANORGANIC_LED_PIN, binIsFull(anorganicDistance, ANORGANIC_FULL_IR_PIN), "anorganic"); gestureCount = 0; firstGestureAt = 0;
}
delay(20);
}Download project files
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




