Tempat Sampah Pintar dengan Arduino: HC-SR04, Tutup Servo, dan Peringatan Penuh
Buat tempat sampah pintar dengan Arduino: deteksi tangan HC-SR04, tutup servo yang menutup pelan, LED tingkat isi dan buzzer, perhitungan baterai, serta notifikasi Telegram dari ESP32.
Tempat sampah pintar dengan Arduino adalah proyek otomasi yang sederhana tapi sangat mendidik: tutup tempat sampah terbuka tanpa perlu kamu sentuh, dan proyek ini termasuk salah satu proyek sekolah paling populer. Sensor ultrasonik HC-SR04 di bagian depan tempat sampah mendeteksi tangan yang mendekat, Arduino membuka tutupnya dengan motor servo, lalu beberapa detik setelah kamu menarik tangan, tutup ditutup pelan-pelan, bukan dibanting. HC-SR04 kedua di bawah tutup mengukur tinggi sampah: makin penuh tempat sampahnya, LED hijau, kuning, dan merah menyala bergantian, dan ketika sudah benar-benar penuh, buzzer berbunyi.
Di panduan ini kita mulai dari daftar komponen, lalu membahas langkah demi langkah di mana sensor dipasang, cara menghitung torsi servo, cara memasang tutup ke engsel, kalibrasi, dan kode lengkap yang mengatur waktu tunggu sekaligus penutupan pelan. Setelah itu kita hitung berapa lama proyek ini benar-benar bisa berjalan dengan baterai, mengirim notifikasi tingkat isi dari ESP32 ke ponselmu sebagai pesan Telegram, dan menulis proyek yang sama untuk Raspberry Pi Pico dengan MicroPython. Di bagian akhir ada juga kerangka presentasi untuk proyek sekolah dan tabel uji yang bisa kamu isi dengan hasil pengukuranmu sendiri.

Bagaimana cara kerja tempat sampah pintar?
Proyek ini adalah sebuah loop yang berulang puluhan kali per detik. Arduino membaca sensor tangan setiap 60 milidetik. Jika ada benda yang lebih dekat dari 20 cm muncul pada dua pembacaan berturut-turut, Arduino menganggapnya tangan dan mengirim servo ke posisi terbuka. Selama tangan masih di sana, waktu tunggu dimulai ulang di setiap pembacaan; 4 detik setelah tangan pergi, tutup menutup pelan dengan kecepatan sekitar 50 derajat per detik. Jika tangan datang lagi ketika tutup sedang menutup, tutup langsung terbuka kembali. Satu detik setelah tutup tertutup, sensor isi mengambil 5 pembacaan, memakai nilai mediannya sebagai jarak ke permukaan sampah, lalu mengubahnya menjadi persentase. Kodenya memakai state machine kecil, dan tutup selalu berada di salah satu dari tiga state: CLOSED (tertutup), OPEN (terbuka), dan CLOSING (sedang menutup).
| Komponen | Tugas | Catatan |
|---|---|---|
| Arduino Uno (atau Nano) | Otaknya: mengukur, memutuskan, dan menggerakkan servo serta LED | ESP32 atau Pico juga bisa |
| 2 × HC-SR04 | Satu mendeteksi tangan, satu lagi mengukur tingkat isi | 5 V, sekitar 15 mA ketika mengukur |
| Servo SG90, MG90S, atau MG996R | Membuka dan menutup tutup | Dipilih berdasarkan berat tutup (perhitungannya di bawah) |
| 3 LED (hijau, kuning, merah) dan 3 × 220 Ω | Indikator tingkat isi | Satu resistor untuk setiap LED |
| Buzzer aktif | Peringatan penuh | Buzzer pasif butuh tone() |
| Engsel, sekrup, lem tembak | Menopang tutup, menahan lengan servo | Berat tutup harus ditopang engsel, bukan servo |
| Kapasitor 470 µF | Meredam arus awal servo ketika mulai bergerak | Dipasang di antara + dan − servo, perhatikan polaritasnya |
| Catu daya | Adaptor 5 V, power bank, atau baterai | Perhitungan lama pemakaian di bawah |
| ESP32 (opsional) | Notifikasi tingkat isi di ponselmu | Butuh Wi-Fi |




Sensor apa untuk mendeteksi tangan?
Ada beberapa sensor yang bisa membuka tempat sampah, tapi tidak semuanya sama cocoknya untuk tugas ini. Yang sebenarnya kamu butuhkan adalah mendeteksi tangan yang mendekat dalam jarak 15–25 cm dari tempat sampah, sambil mengabaikan orang yang cuma lewat. Karena HC-SR04 memberi jarak dalam sentimeter, kamu bisa mengatur ambangnya di kode persis sesuai keinginan; itulah sebabnya kebanyakan proyek tempat sampah pintar memakainya. Berikut kelebihan dan kekurangan alternatifnya:
| Sensor | Cara mendeteksi | Untuk tempat sampah |
|---|---|---|
| HC-SR04 (ultrasonik) | Gema suara, 2–400 cm, kerucut sempit | Ambang diatur di kode; pilihan paling seimbang |
| Sensor rintangan IR (FC-51) | Pantulan cahaya inframerah, sekitar 2–30 cm | Murah dan cepat; bisa terkecoh sinar matahari dan sarung tangan gelap |
| PIR (HC-SR501) | Gerakan panas tubuh, sampai 7 m, sudut lebar | Terpicu oleh setiap orang yang lewat dan bertahan beberapa detik; tidak cocok |
| APDS-9960 | Kedekatan jarak pendek dan gestur tangan | Versi keren yang terbuka dengan lambaian tangan; butuh I2C dan 3,3 V |
Cara kerja sensor PIR bisa kamu baca di artikel Sensor Gerak PIR, dan versi yang dikendalikan gestur ada di panduan sensor gestur APDS-9960. Singkatnya, begini cara kerja HC-SR04: sensor mengirim semburan suara 40 kHz yang singkat, lalu mengeluarkan waktu tempuh gemanya sebagai pulsa di pin ECHO. Karena suara merambat sekitar 343 m/dtk di udara bersuhu 20 °C dan jalurnya bolak-balik, membagi waktu dalam mikrodetik dengan 58 memberi jarak dalam sentimeter. Detailnya ada di artikel Sensor Jarak HC-SR04.
Posisi sensor
Sensor tangan dipasang di badan tempat sampah, di bagian atas sisi depan, bukan di tutupnya, karena ketika tutup terbuka sensornya akan ikut berputar dan menghadap ke langit-langit. Memiringkan sensor ke atas sebesar 10–20 derajat membuatnya menangkap tangan yang terulur di atas tempat sampah, tapi tidak menangkap kaki orang yang lewat. Jika tempat sampah berdiri di samping dinding atau lemari, tidak boleh ada permukaan tetap dalam jarak 30 cm ke arah sensor menghadap; kalau ada, sensor mengira permukaan itu tangan dan tutupnya tidak pernah menutup.
Sensor isi ditempel di bawah tutup, dekat bagian tengah, menghadap lurus ke bawah. Di posisi ini sensor hanya mengukur dengan benar ketika tutup tertutup; ketika tutup terbuka, sensor menghadap ke dinding atau langit-langit. Karena itu kodenya baru mengukur tingkat isi satu detik setelah tutup tertutup. Meskipun kerucut suara sensor ini sempit (15 derajat di datasheet, sedikit lebih lebar dalam praktik), di kedalaman 35 cm kerucut itu mencakup area selebar 10–20 cm; di tempat sampah yang lebih sempit dari 20 cm, suara bisa memantul dari dinding samping dan menyebabkan pembacaan palsu. Lipat tepi kantong sampah ke bagian luar tempat sampah: tepi kantong yang menggantung ke dalam akan berada di depan sensor dan membuat tempat sampah terlihat penuh padahal masih kosong.
Diagram pengkabelan: Arduino Uno, ESP32, dan Pico
Tabel di bawah sesuai persis dengan setiap kode di artikel ini. Di Uno, sensor tangan ke D2–D3, sensor isi ke D4–D5, servo ke D9, LED ke D10–D12, dan buzzer ke D8. Karena library Servo memakai Timer1 di Uno, output PWM di D9 dan D10 jadi tidak aktif; kita hanya menyalakan dan mematikan LED di D10, jadi ini tidak berpengaruh. Pasang resistor 220 Ω di depan setiap LED; nilai untuk LED-mu sendiri bisa kamu hitung dengan kalkulator resistor LED. Tata letak pin board-mu bisa kamu lihat di alat diagram pin.
| Koneksi | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| TRIG sensor tangan | D2 | GPIO 18 | GP2 |
| ECHO sensor tangan | D3 (langsung) | GPIO 19, lewat pembagi 1 kΩ / 2 kΩ | GP3, lewat pembagi 1 kΩ / 2 kΩ |
| TRIG sensor isi | D4 | GPIO 25 | GP4 |
| ECHO sensor isi | D5 (langsung) | GPIO 26, lewat pembagi | GP5, lewat pembagi |
| VCC HC-SR04 (keduanya) | 5V | 5V (VIN) | VBUS |
| Sinyal servo (oranye) | D9 | GPIO 13 | GP15 |
| Servo + (merah) | 5V (SG90) atau 5–6 V eksternal | 5V (VIN) atau 5–6 V eksternal | VBUS atau 5–6 V eksternal |
| LED hijau, kuning, merah (dengan 220 Ω) | D10, D11, D12 | GPIO 27, 32, 33 | GP10, GP11, GP12 |
| Buzzer aktif (+) | D8 | GPIO 23 | GP13 |
| Semua GND | GND | GND | GND |
Memilih servo dan menghitung torsi
Masalah paling umum di proyek tempat sampah pintar adalah tutup yang hanya terbuka setengah lalu bergetar, atau sama sekali tidak terangkat. Penyebabnya hampir selalu servo yang terlalu lemah untuk tutupnya. Memperkirakan torsi yang dibutuhkan itu mudah: Torsi (kg·cm) = berat tutup (kg) × jarak dari engsel ke titik beratnya (cm). Tutup datar yang tebalnya merata punya titik berat tepat di tengah; untuk tutup sepanjang 24 cm, jarak itu 12 cm. Momen terberat adalah awal pembukaan, ketika tutup masih mendatar; makin tinggi tutup terangkat, makin kecil torsi yang dibutuhkan, dan ketika tutup tegak, torsinya hampir nol. Angka torsi di katalog servo adalah stall torque, yaitu titik ketika servo mengerahkan tenaga penuh lalu berhenti; servo yang bekerja dekat batas itu akan panas dan giginya cepat aus. Jadi kalikan hasilmu minimal 2.
| Tutup | Berat | Titik berat | Torsi yang dibutuhkan | Dengan margin 2× | Saran |
|---|---|---|---|---|---|
| Karton atau foam board 20 × 20 cm | 50 g | 10 cm | 0,5 kg·cm | 1,0 kg·cm | SG90 |
| Tutup tempat sampah plastik 25 cm | 120 g | 12,5 cm | 1,5 kg·cm | 3,0 kg·cm | MG996R (MG90S pas-pasan) |
| Tutup MDF atau tripleks 30 cm | 300 g | 15 cm | 4,5 kg·cm | 9,0 kg·cm | MG996R ditambah pemberat penyeimbang |
| Servo | Torsi (4,8 V / 6 V) | Gigi | Arus | Catatan |
|---|---|---|---|---|
| SG90 | 1,8 kg·cm (hanya ada rating 4,8 V) | Plastik | 100–250 mA ketika bergerak | Bisa diberi daya dari pin 5V Arduino |
| MG90S | 1,8 / 2,2 kg·cm | Logam | 150–300 mA ketika bergerak | Ukurannya sama dengan SG90, lebih awet |
| MG996R | 9,4 / 11 kg·cm | Logam | 0,5–0,9 A ketika bergerak, sampai 2,5 A ketika macet (stall) | Wajib diberi daya dari catu 5–6 V terpisah |

Daripada membeli servo yang lebih kuat, menyeimbangkan tutup sering kali sudah cukup. Jika tutup punya lengan pendek yang menjulur ke belakang engsel, beberapa baut atau koin yang ditempel di sana akan mengimbangi sebagian beratnya; pemberat penyeimbang ini bisa memangkas torsi yang dibutuhkan sampai setengahnya. Kamu juga bisa membuat lengan servo mendorong tutup di titik yang jauh dari engsel, tapi tuas tidak memberi torsi secara gratis: makin jauh dari engsel, makin kecil gaya yang dibutuhkan, tetapi titik yang didorong menempuh jarak lebih jauh, jadi kamu butuh lengan servo yang lebih panjang, dan lengan yang lebih panjang menaikkan lagi torsi yang dituntut dari servo. Kalau kamu ingin tutup terbuka mendekati 90 derajat, torsi servo yang dibutuhkan hampir sama dengan servo yang dipasang langsung di engsel. Perbandingan detail jenis-jenis servo ada di artikel Apa Itu Motor Servo? dan servo MG996R.
Tips pemasangan: engsel, lengan servo, dan kabel
- Biarkan engsel yang menopang berat: Tutup harus terpasang pada engsel sungguhan (engsel bawaan tempat sampah atau engsel lemari kecil). Jika tutup hanya bertumpu pada poros servo, seluruh beratnya menekan bantalan servo dan gigi plastik SG90 akan cepat patah.
- Luruskan poros servo dengan sumbu engsel: Cara termudah adalah menyekrup servo ke tepi belakang tempat sampah sehingga porosnya tepat berada di ujung garis engsel, lalu memasang lengan servo ke tutup dengan sekrup atau lem tembak. Jika sumbunya tidak segaris, servo akan mendorong tutup ke samping setiap kali terbuka.
- Pasang badan servo dengan kokoh: Jangan menahan servo hanya dengan selotip dua sisi; badannya akan terpuntir ketika mengangkat tutup. Pakai dua sekrup lewat telinga pemasangan servo atau braket L kecil.
- Jangan menekan tutup ke bibir tempat sampah: Atur sudut tertutup di posisi tutup sudah bertumpu di bibir tempat sampah tapi servo tidak mendorongnya. Jika servo terus memaksa tutup yang sudah tertutup, servo berdengung, panas, dan membuang arus.
- Sisakan kelonggaran di kabel: Kabel sensor isi ikut bergerak bersama tutup. Lewatkan kabelnya di samping engsel, cukup panjang agar tidak tertarik walaupun tutup terbuka penuh, lalu kencangkan dengan cable tie.
- Jauhkan elektronik dari sampah: Taruh Arduino, baterai, dan breadboard di kotak kecil yang ditempel di bagian belakang atau bawah tempat sampah. Cairan atau lembap yang merembes dari kantong sampah tidak boleh sampai ke rangkaian.
- Mulai dengan model karton: Untuk proyek sekolah, tutup ringan dari kotak sepatu atau foam board sudah berfungsi baik bahkan dengan SG90, dan ini contoh bagus untuk menunjukkan perhitungan torsi di presentasimu.
Pemasangan dan kalibrasi langkah demi langkah
Sebelum lanjut ke kode utama, upload dulu sketch kalibrasi kecil di bawah. Sketch ini menggerakkan servo ke sudut berapa pun yang kamu ketik di Serial Monitor dan menampilkan jarak yang dibaca kedua sensor setiap setengah detik. Dengan begitu kamu bisa mengukur sudut tutup tertutup dan terbuka, kedalaman tempat sampah kosong, dan ambang deteksi tangan untuk tempat sampahmu sendiri.
1#include <Servo.h>
2
3const int HAND_TRIG = 2, HAND_ECHO = 3; // el sensörü / hand sensor
4const int FILL_TRIG = 4, FILL_ECHO = 5; // doluluk sensörü / fill sensor
5const int SERVO_PIN = 9;
6
7Servo lid;
8unsigned long lastPrint = 0;
9
10int pingCm(int trig, int echo) {
11 digitalWrite(trig, LOW); delayMicroseconds(2);
12 digitalWrite(trig, HIGH); delayMicroseconds(10); // 10 µs tetik darbesi / 10 µs trigger pulse
13 digitalWrite(trig, LOW);
14 unsigned long t = pulseIn(echo, HIGH, 30000UL); // en fazla 30 ms bekle / wait at most 30 ms
15 return t == 0 ? 999 : (int)(t / 58); // 999 = yankı yok / 999 = no echo
16}
17
18void setup() {
19 Serial.begin(9600);
20 pinMode(HAND_TRIG, OUTPUT); pinMode(HAND_ECHO, INPUT);
21 pinMode(FILL_TRIG, OUTPUT); pinMode(FILL_ECHO, INPUT);
22 lid.write(90); // başlangıçta orta konum / start at the middle position
23 lid.attach(SERVO_PIN);
24 Serial.println(F("Açı yaz (0-180) ve Enter'a bas / Type an angle (0-180) and press Enter"));
25}
26
27void loop() {
28 if (Serial.available()) {
29 String s = Serial.readStringUntil('\n');
30 s.trim();
31 if (s.length() > 0) { // boş satırı yok say / ignore empty lines
32 int a = constrain(s.toInt(), 0, 180);
33 lid.write(a);
34 Serial.print(F("Servo: "));
35 Serial.println(a);
36 }
37 }
38
39 if (millis() - lastPrint >= 500) { // yarım saniyede bir yaz / print every half second
40 lastPrint = millis();
41 int hand = pingCm(HAND_TRIG, HAND_ECHO);
42 delay(60); // iki sensör arasında bekle / wait between the two sensors
43 int fill = pingCm(FILL_TRIG, FILL_ECHO);
44 Serial.print(F("El / Hand: "));
45 Serial.print(hand);
46 Serial.print(F(" cm Doluluk / Fill: "));
47 Serial.print(fill);
48 Serial.println(F(" cm"));
49 }
50}- Upload kodenya tanpa memasang lengan servo, lalu buka Serial Monitor di 9600 baud; atur akhir baris ke Newline. Servo bergerak ke 90 derajat.
- Ketik 10 lalu tekan Enter. Tahan tutup dalam posisi tertutup, pasang lengan servo ke poros di posisi ini, lalu kencangkan ke tutup.
- Naikkan sudutnya bertahap 20, 40, 60 untuk mencari nilai ketika tutup terbuka penuh; biasanya 90–110 derajat. Jangan membuka tutup melewati posisi tegak. Nilai itu menjadi LID_OPEN. Jika servomu berputar ke arah sebaliknya, pilih nilai tertutup dan terbuka sesuai arahnya; kodenya bekerja di kedua arah.
- Turun lagi ke sudut kecil. Dari sudut ketika tutup sudah duduk penuh di bibir tempat sampah, mundurkan 2–3 derajat ke arah membuka; itu menjadi LID_CLOSED. Jika servo berdengung ketika tertutup, berarti servo menekan tutup.
- Dengan kantong terpasang dan tempat sampah kosong, catat nilai yang dibaca sensor isi; itulah EMPTY_CM. Pilih 6–10 cm untuk FULL_CM: ketika sampah mencapai tinggi ini, tutup harus masih mudah menutup dan sensor masih harus bisa mengukur dengan andal, karena HC-SR04 tidak bisa mengukur lebih dekat dari 2–3 cm.
- Tahan tanganmu di depan sensor tangan pada jarak 5, 10, 20, dan 30 cm, lalu lihat hasil pembacaannya. Setelah itu berjalanlah melewati tempat sampah dan catat nilai terdekat yang terbaca. HAND_CM harus tetap di bawah nilai itu; 15–25 cm cocok untuk kebanyakan tempat sampah.
- Masukkan nilai-nilai yang kamu temukan ke pengaturan di bagian atas kode utama, lalu upload.
Kode utama: deteksi tangan, waktu tunggu, dan penutupan pelan
Tidak ada delay() panjang di kode utama; semuanya diatur dengan cap waktu yang disimpan memakai millis(). Jadi, bahkan ketika tutup sedang menutup, sensor tangan tetap dibaca, dan jika tangan mendekat lagi, tutup langsung terbuka kembali. Ini fitur keamanan yang sederhana tapi penting, karena mencegah tutup menjepit tangan anak kecil. Detail pengaturan waktu tanpa blocking ada di millis() dan delay(), dan cara berpikir dengan state ada di artikel state machine Arduino.
1#include <Servo.h>
2
3// Pinler / Pins
4const int HAND_TRIG = 2, HAND_ECHO = 3; // el sensörü, kutunun önünde / hand sensor, front of the bin
5const int FILL_TRIG = 4, FILL_ECHO = 5; // doluluk sensörü, kapağın altında / fill sensor, under the lid
6const int SERVO_PIN = 9;
7const int LED_GREEN = 10, LED_YELLOW = 11, LED_RED = 12;
8const int BUZZER = 8; // aktif buzzer / active buzzer
9
10// Ayarlar: kalibrasyon kodunda bulduğun değerleri yaz / Settings: use the values from the calibration sketch
11const int HAND_CM = 20; // bundan yakın el kapağı açar / a hand closer than this opens the lid
12const int LID_CLOSED = 10; // kapak kenara oturuyor, bastırmıyor / lid rests on the rim, not pressing
13const int LID_OPEN = 110; // kapak tam açık / lid fully open
14const unsigned long OPEN_TIME = 4000; // son el algılamadan sonra açık kalma (ms) / stay open after the last hand (ms)
15const unsigned long CLOSE_STEP_MS = 20; // kapanırken derece başına ms / ms per degree while closing
16const int EMPTY_CM = 35; // boş kutuda sensörden dibe / sensor to bottom when empty
17const int FULL_CM = 8; // bu mesafede kutu %100 dolu / the bin is 100% full at this distance
18
19enum LidState { CLOSED, OPEN, CLOSING };
20LidState state = CLOSED;
21Servo lid;
22
23unsigned long lastHand = 0, lastHandPing = 0, closeStart = 0, closedAt = 0, lastFill = 0;
24int fillPercent = 0;
25byte handHits = 0;
26bool fullWarned = false;
27
28int pingCm(int trig, int echo) {
29 digitalWrite(trig, LOW); delayMicroseconds(2);
30 digitalWrite(trig, HIGH); delayMicroseconds(10); // 10 µs tetik darbesi / 10 µs trigger pulse
31 digitalWrite(trig, LOW);
32 unsigned long t = pulseIn(echo, HIGH, 30000UL); // en fazla 30 ms bekle / wait at most 30 ms
33 return t == 0 ? 999 : (int)(t / 58); // 999 = yankı yok / 999 = no echo
34}
35
36int medianCm(int trig, int echo) { // 5 ölçümün ortancası / median of 5 readings
37 int v[5];
38 delay(60); // önce el sensörünün yankısı sönsün / first let the hand sensor's echo die out
39 for (int i = 0; i < 5; i++) {
40 v[i] = pingCm(trig, echo);
41 delay(60); // yankılar sönsün / let the echoes die out
42 }
43 for (int i = 0; i < 4; i++) // küçükten büyüğe sırala / sort ascending
44 for (int j = i + 1; j < 5; j++)
45 if (v[j] < v[i]) { int tmp = v[i]; v[i] = v[j]; v[j] = tmp; }
46 return v[2];
47}
48
49int toPercent(int cm) { // mesafe → doluluk yüzdesi / distance → fill percent
50 long p = (long)(EMPTY_CM - cm) * 100 / (EMPTY_CM - FULL_CM);
51 if (p < 0) p = 0;
52 if (p > 100) p = 100;
53 return (int)p;
54}
55
56void showLevel() {
57 digitalWrite(LED_GREEN, fillPercent < 50);
58 digitalWrite(LED_YELLOW, fillPercent >= 50 && fillPercent < 80);
59 digitalWrite(LED_RED, fillPercent >= 80);
60}
61
62void beep(int n) {
63 for (int i = 0; i < n; i++) {
64 digitalWrite(BUZZER, HIGH); delay(120);
65 digitalWrite(BUZZER, LOW); delay(120);
66 }
67}
68
69void openLid() {
70 if (!lid.attached()) lid.attach(SERVO_PIN);
71 lid.write(LID_OPEN); // hızlı aç / open quickly
72 state = OPEN;
73 if (fillPercent >= 90) beep(2); // açılırken dolu uyarısı / full warning on opening
74}
75
76void setup() {
77 Serial.begin(9600);
78 pinMode(HAND_TRIG, OUTPUT); pinMode(HAND_ECHO, INPUT);
79 pinMode(FILL_TRIG, OUTPUT); pinMode(FILL_ECHO, INPUT);
80 pinMode(LED_GREEN, OUTPUT); pinMode(LED_YELLOW, OUTPUT); pinMode(LED_RED, OUTPUT);
81 pinMode(BUZZER, OUTPUT);
82 lid.write(LID_CLOSED); // attach'tan önce: açılışta 90°'ye sıçramasın / before attach: no jump to 90° at power-up
83 lid.attach(SERVO_PIN);
84 delay(500);
85 lid.detach(); // kapalıyken servoyu bırak / release the servo while closed
86 closedAt = millis();
87 showLevel();
88}
89
90void loop() {
91 unsigned long now = millis();
92
93 // 1) El algılama, 60 ms'de bir / Hand detection, every 60 ms
94 if (now - lastHandPing >= 60) {
95 lastHandPing = now;
96 int d = pingCm(HAND_TRIG, HAND_ECHO);
97 if (d >= 2 && d <= HAND_CM) {
98 if (handHits < 2) handHits++;
99 } else {
100 handHits = 0;
101 }
102 if (handHits >= 2) { // art arda 2 ölçüm / 2 readings in a row
103 lastHand = now; // bekleme süresi yeniden başlar / the wait time restarts
104 if (state != OPEN) openLid(); // kapanırken el gelirse yeniden aç / reopen if a hand appears while closing
105 }
106 }
107
108 // 2) Bekleme süresi doldu mu? / Has the wait time passed?
109 if (state == OPEN && now - lastHand >= OPEN_TIME) {
110 state = CLOSING;
111 closeStart = now;
112 }
113
114 // 3) Yavaş kapanma: açı geçen süreden hesaplanır / Slow close: angle is computed from elapsed time
115 if (state == CLOSING) {
116 int moved = (now - closeStart) / CLOSE_STEP_MS;
117 int range = abs(LID_OPEN - LID_CLOSED);
118 if (moved >= range) {
119 lid.write(LID_CLOSED);
120 state = CLOSED;
121 closedAt = now;
122 } else {
123 lid.write(LID_OPEN > LID_CLOSED ? LID_OPEN - moved : LID_OPEN + moved);
124 }
125 }
126
127 // 4) Kapandıktan 0,4 s sonra servoyu bırak / Release the servo 0.4 s after closing
128 if (state == CLOSED && lid.attached() && now - closedAt > 400) lid.detach();
129
130 // 5) Doluluk: yalnızca kapak kapalı ve durgunken / Fill level: only while the lid is closed and still
131 if (state == CLOSED && now - closedAt > 1000 && now - lastFill >= 3000) {
132 lastFill = now;
133 int cm = medianCm(FILL_TRIG, FILL_ECHO);
134 if (cm < 999) fillPercent = toPercent(cm); // yankı yoksa eski değeri koru / keep the old value if there is no echo
135 showLevel();
136 Serial.print(F("Doluluk / Fill: "));
137 Serial.print(cm);
138 Serial.print(F(" cm = %"));
139 Serial.println(fillPercent);
140 if (fillPercent >= 90 && !fullWarned) { // doldu: bir kez öt / just filled: beep once
141 fullWarned = true;
142 beep(3);
143 }
144 if (fillPercent < 70) fullWarned = false; // boşaltıldı / emptied
145 }
146}| Fungsi atau pengaturan | Kegunaannya |
|---|---|
| pingCm() | Mengambil satu pembacaan; mengembalikan 999 jika gema tidak datang dalam 30 ms |
| medianCm() | Mengambil 5 pembacaan dengan jeda 60 ms, mengurutkannya, lalu mengembalikan nilai tengahnya |
| toPercent() | Mengubah jarak menjadi persentase 0–100 berdasarkan EMPTY_CM dan FULL_CM |
| handHits | Menghitung berapa pembacaan berturut-turut yang melihat tangan; satu pembacaan palsu saja tidak akan membuka tutup |
| OPEN_TIME | Waktu dari terakhir kali tangan terlihat sampai penutupan dimulai (4000 ms) |
| CLOSE_STEP_MS | Waktu per derajat ketika menutup: 100 derajat × 20 ms = penutupan 2 detik |
| lid.detach() | Berhenti mengirim pulsa ke servo 0,4 dtk setelah tutup tertutup |
| fullWarned | Membunyikan peringatan penuh hanya sekali; direset ketika tingkat isi turun di bawah 70% |
Trik di balik penutupan pelan adalah sudutnya dihitung dari waktu yang sudah berlalu, bukan dinaikkan satu derajat demi satu derajat. 600 ms setelah penutupan dimulai, tutup seharusnya sudah bergerak 600 / 20 = 30 derajat; walaupun loop sempat tertahan sebentar oleh pengukuran isi atau buzzer, kode tetap menaruh tutup di sudut yang benar sehingga gerakannya tidak tersendat. Untuk memperlambat penutupan, naikkan CLOSE_STEP_MS: dengan 30 ms, 100 derajat butuh 3 detik. Begitu tutup tertutup, servo dilepas dengan detach(); tutup sudah bertumpu di bibir tempat sampah, jadi servo tidak perlu menahannya, tidak berdengung, dan lebih hemat baterai. Memanggil write() sebelum attach() di kode juga disengaja: ketika Arduino menyala, servo tidak melompat dulu ke 90 derajat, tapi langsung mulai di posisi tertutup.
Pengukuran tingkat isi serta peringatan LED dan buzzer
Sensor isi mengukur jarak dari bawah tutup ke titik tertinggi sampah. Jarak ini paling besar ketika tempat sampah kosong (EMPTY_CM) dan paling kecil ketika penuh (FULL_CM). Persentasenya didapat dari rumus ini: Tingkat isi (%) = (EMPTY_CM − terukur) / (EMPTY_CM − FULL_CM) × 100. Contohnya, dengan EMPTY_CM = 35 cm, FULL_CM = 8 cm, dan jarak terukur 20 cm, tingkat isinya (35 − 20) / 27 × 100 ≈ 55% dan LED kuning menyala. Jika hasil pembacaan lebih besar dari 35 cm (suaranya memantul miring dari dasar), hasilnya dibatasi ke 0%; jika lebih kecil dari 8 cm, dibatasi ke 100%.
| Tingkat isi | LED | Buzzer | Artinya |
|---|---|---|---|
| 0–49% | Hijau | Diam | Masih banyak ruang |
| 50–79% | Kuning | Diam | Lebih dari setengah penuh, segera kosongkan |
| 80–89% | Merah | Diam | Hampir penuh |
| 90–100% | Merah | 3 bunyi pendek ketika penuh, 2 bunyi setiap kali terbuka | Kosongkan sekarang |
Permukaan sampah tidak rata: kalau ada satu botol berdiri tegak tepat di bawah sensor, pembacaan akan melihat titik itu dan menunjukkan tempat sampah lebih penuh dari kenyataannya. Filter median membuang pembacaan aneh yang melonjak, tapi tidak bisa memperbaiki bentuk tumpukan sampah, jadi anggap ambang seperti 80% dan 90% sebagai peringatan “segera kosongkan”, bukan pengukuran yang persis. Agar peringatan tidak terus berbunyi, kodenya memakai histeresis: peringatan penuh berbunyi sekali di 90% dan tidak akan berbunyi lagi sampai tempat sampah dikosongkan dan tingkat isinya turun di bawah 70%. Perbedaan berbagai filter kami jelaskan secara detail di artikel menyaring data sensor.
Daya baterai: tahan berapa lama?
Menjalankan tempat sampah pintar tanpa kabel memang menggoda, tapi Arduino Uno bukan board yang ramah baterai. Dengan chip USB, regulator, dan LED power-nya, board ini menarik sekitar 45–50 mA walaupun tidak melakukan apa-apa. Tambahkan arus idle dua HC-SR04, satu LED yang menyala, dan elektronik servo yang sudah dilepas, maka arus rata-ratanya naik menjadi sekitar 70–80 mA. Arus 100–250 mA yang ditarik servo ketika membuka dan menutup hanya berlangsung beberapa detik, jadi pada tempat sampah yang dibuka 50 kali sehari, rata-ratanya hanya naik sekitar 1 mA. Umur baterai kira-kira kapasitas (mAh) / arus rata-rata (mA); untuk menghitungnya dengan nilaimu sendiri, pakai kalkulator umur baterai.
| Sumber daya | Koneksi | Perkiraan lama pakai (75 mA) | Penilaian |
|---|---|---|---|
| Baterai 9 V PP3 (sekitar 500 mAh) | VIN | 5–6 jam | Tidak disarankan: tegangannya anjlok ketika servo mulai bergerak dan board ter-reset |
| 6 × AA alkaline (9 V) | Jack DC atau VIN | Sekitar 1 hari | Cukup untuk hari presentasi |
| 2 × 18650 (7,4 V, 2500 mAh) | VIN; LM2596 diatur ke 5–6 V untuk servo | Sekitar 1,5 hari | Bisa diisi ulang; butuh charger 2S dan board proteksi |
| Power bank 10.000 mAh | USB | 3–4 hari | Sebagian power bank mati sendiri dengan beban di bawah 50–100 mA |
| Adaptor 5 V 2 A | USB atau pin 5V | Tanpa batas | Pilihan terbaik untuk pemakaian permanen di rumah |

Kesimpulan dari tabel ini jelas: tempat sampah berbasis Uno yang memakai baterai ideal untuk presentasi dan demo, tapi untuk tempat sampah yang akan bekerja berbulan-bulan di rumah, pakai adaptor 5 V. Cara mengatur modul step-down yang dipasang di antara dua 18650 dan servo dibahas di artikel LM2596. Kalau kamu benar-benar ingin memperpanjang umur baterai, kamu bisa memakai Arduino Pro Mini yang LED power-nya sudah dilepas sebagai pengganti Uno, menidurkan prosesor di antara pembacaan, dan menyalakan LED hanya sebentar ketika tutup terbuka; dengan langkah-langkah ini arus rata-rata turun menjadi 15–20 mA dan baterai yang sama bertahan 4–5 kali lebih lama. Perbedaan cara memberi daya ke Arduino (USB, jack DC, VIN, pin 5V) ada di artikel Cara Memberi Daya ke Arduino.
Notifikasi tingkat isi dengan ESP32 (Telegram)
Untuk melihat LED ketika tempat sampah penuh, kamu harus berjalan mendekatinya; sebaliknya, ESP32 bisa mengirim informasi itu langsung ke ponselmu. Cara termudah adalah Telegram, karena gratis dan kamu bisa membuat bot sendiri dalam beberapa menit. Di Telegram, kirim pesan ke @BotFather, buat bot dengan perintah /newbot, lalu catat token yang diberikannya. Setelah itu kirim /start sekali ke bot-mu sendiri; bot tidak bisa mengirim pesan ke orang yang belum pernah mengobrol dengannya. Untuk mengetahui chat ID-mu, kamu bisa mengirim pesan ke bot seperti @userinfobot atau memakai permintaan getUpdates di Bot API. Kodenya tidak butuh library tambahan: kode mengirim permintaan ke alamat sendMessage Telegram dengan HTTPClient bawaan ESP32.
Kode ini memakai state machine yang sama dengan versi Uno; bedanya hanya sinyal servo dibuat dengan unit PWM ESP32, yaitu LEDC, bukan dengan library Servo. Pada sinyal 50 Hz, pulsa 0,544–2,4 ms sama dengan 0–180 derajat, dan menghentikan pulsa (menulis 0 dengan ledcWrite) akan melepas servo. Kodenya untuk ESP32 Arduino core versi 3.x; versi 2.x tidak punya fungsi ledcAttach(), jadi perbarui core-nya di Boards Manager.

1// ESP32 Arduino çekirdeği 3.x / ESP32 Arduino core 3.x
2#include <WiFi.h>
3#include <WiFiClientSecure.h>
4#include <HTTPClient.h>
5
6const char* WIFI_SSID = "WIFI_ADIN"; // kendi ağın / your network
7const char* WIFI_PASS = "WIFI_SIFREN";
8const char* BOT_TOKEN = "123456789:ABCdefGhIJKlmNoPQRstuVWxyz"; // BotFather'dan / from BotFather
9const char* CHAT_ID = "123456789"; // senin sohbet kimliğin / your chat ID
10
11// Pinler: ECHO'lar 1 kΩ / 2 kΩ bölücüyle / Pins: ECHOs via a 1 kΩ / 2 kΩ divider
12const int HAND_TRIG = 18, HAND_ECHO = 19;
13const int FILL_TRIG = 25, FILL_ECHO = 26;
14const int SERVO_PIN = 13;
15const int LED_GREEN = 27, LED_YELLOW = 32, LED_RED = 33;
16const int BUZZER = 23;
17
18const int HAND_CM = 20;
19const int LID_CLOSED = 10, LID_OPEN = 110;
20const unsigned long OPEN_TIME = 4000, CLOSE_STEP_MS = 20;
21const int EMPTY_CM = 35, FULL_CM = 8;
22const int NOTIFY_PCT = 85; // bu yüzdede bildir / notify at this percent
23const int RESET_PCT = 30; // bunun altına inince "boşaltıldı" / below this: "emptied"
24
25enum LidState { CLOSED, OPEN, CLOSING };
26LidState state = CLOSED;
27unsigned long lastHand = 0, lastHandPing = 0, closeStart = 0, closedAt = 0, lastFill = 0, lastTry = 0;
28int fillPercent = 0;
29byte handHits = 0;
30bool notified = false, servoOn = false, fullWarned = false;
31
32void servoWrite(int angle) { // 0–180° → 544–2400 µs, 50 Hz
33 uint32_t us = map(angle, 0, 180, 544, 2400);
34 ledcWrite(SERVO_PIN, us * 16384 / 20000); // 14 bit, 20 ms periyot / 14-bit, 20 ms period
35 servoOn = true;
36}
37
38void servoRelease() { // darbe yok: servo serbest kalır / no pulses: the servo relaxes
39 ledcWrite(SERVO_PIN, 0);
40 servoOn = false;
41}
42
43int pingCm(int trig, int echo) {
44 digitalWrite(trig, LOW); delayMicroseconds(2);
45 digitalWrite(trig, HIGH); delayMicroseconds(10);
46 digitalWrite(trig, LOW);
47 unsigned long t = pulseIn(echo, HIGH, 30000UL);
48 return t == 0 ? 999 : (int)(t / 58); // 999 = yankı yok / 999 = no echo
49}
50
51int medianCm(int trig, int echo) { // 5 ölçümün ortancası / median of 5 readings
52 int v[5];
53 delay(60); // önce el sensörünün yankısı sönsün / first let the hand sensor's echo die out
54 for (int i = 0; i < 5; i++) {
55 v[i] = pingCm(trig, echo);
56 delay(60);
57 }
58 for (int i = 0; i < 4; i++)
59 for (int j = i + 1; j < 5; j++)
60 if (v[j] < v[i]) { int tmp = v[i]; v[i] = v[j]; v[j] = tmp; }
61 return v[2];
62}
63
64int toPercent(int cm) {
65 long p = (long)(EMPTY_CM - cm) * 100 / (EMPTY_CM - FULL_CM);
66 return (int)constrain(p, 0L, 100L);
67}
68
69void showLevel() {
70 digitalWrite(LED_GREEN, fillPercent < 50);
71 digitalWrite(LED_YELLOW, fillPercent >= 50 && fillPercent < 80);
72 digitalWrite(LED_RED, fillPercent >= 80);
73}
74
75void beep(int n) {
76 for (int i = 0; i < n; i++) {
77 digitalWrite(BUZZER, HIGH); delay(120);
78 digitalWrite(BUZZER, LOW); delay(120);
79 }
80}
81
82String urlEncode(const String& s) { // Türkçe harfler ve boşluk için / for Turkish letters and spaces
83 const char* hex = "0123456789ABCDEF";
84 String out;
85 for (size_t i = 0; i < s.length(); i++) {
86 uint8_t c = s[i];
87 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
88 out += (char)c;
89 } else {
90 out += '%';
91 out += hex[c >> 4];
92 out += hex[c & 15];
93 }
94 }
95 return out;
96}
97
98bool sendTelegram(const String& text) {
99 if (WiFi.status() != WL_CONNECTED) return false;
100 WiFiClientSecure client;
101 client.setInsecure(); // sertifika denetimi yok, hobi projesi için yeterli / no certificate check, fine for a hobby project
102 HTTPClient http;
103 String url = String("https://api.telegram.org/bot") + BOT_TOKEN +
104 "/sendMessage?chat_id=" + CHAT_ID + "&text=" + urlEncode(text);
105 if (!http.begin(client, url)) return false;
106 int code = http.GET(); // 200 = gönderildi / 200 = sent
107 Serial.printf("Telegram HTTP %d\n", code);
108 http.end();
109 return code == 200;
110}
111
112void openLid() {
113 servoWrite(LID_OPEN);
114 state = OPEN;
115 if (fillPercent >= 90) beep(2);
116}
117
118void setup() {
119 Serial.begin(115200);
120 pinMode(HAND_TRIG, OUTPUT); pinMode(HAND_ECHO, INPUT);
121 pinMode(FILL_TRIG, OUTPUT); pinMode(FILL_ECHO, INPUT);
122 pinMode(LED_GREEN, OUTPUT); pinMode(LED_YELLOW, OUTPUT); pinMode(LED_RED, OUTPUT);
123 pinMode(BUZZER, OUTPUT);
124 ledcAttach(SERVO_PIN, 50, 14); // 50 Hz, 14 bit servo sinyali / 50 Hz, 14-bit servo signal
125 servoWrite(LID_CLOSED);
126 delay(500);
127 servoRelease();
128 WiFi.mode(WIFI_STA);
129 WiFi.begin(WIFI_SSID, WIFI_PASS); // arka planda bağlanır; kutu Wi-Fi olmadan da çalışır / connects in the background; the bin works without Wi-Fi too
130 closedAt = millis();
131 showLevel();
132}
133
134void loop() {
135 unsigned long now = millis();
136
137 if (now - lastHandPing >= 60) { // el sensörü / hand sensor
138 lastHandPing = now;
139 int d = pingCm(HAND_TRIG, HAND_ECHO);
140 if (d >= 2 && d <= HAND_CM) {
141 if (handHits < 2) handHits++;
142 } else {
143 handHits = 0;
144 }
145 if (handHits >= 2) {
146 lastHand = now;
147 if (state != OPEN) openLid();
148 }
149 }
150
151 if (state == OPEN && now - lastHand >= OPEN_TIME) {
152 state = CLOSING;
153 closeStart = now;
154 }
155
156 if (state == CLOSING) { // yavaş kapanma / slow close
157 int moved = (now - closeStart) / CLOSE_STEP_MS;
158 int range = abs(LID_OPEN - LID_CLOSED);
159 if (moved >= range) {
160 servoWrite(LID_CLOSED);
161 state = CLOSED;
162 closedAt = now;
163 } else {
164 servoWrite(LID_OPEN > LID_CLOSED ? LID_OPEN - moved : LID_OPEN + moved);
165 }
166 }
167
168 if (state == CLOSED && servoOn && now - closedAt > 400) servoRelease();
169
170 if (state == CLOSED && now - closedAt > 1000 && now - lastFill >= 3000) {
171 lastFill = now;
172 int cm = medianCm(FILL_TRIG, FILL_ECHO);
173 if (cm < 999) fillPercent = toPercent(cm);
174 showLevel();
175 Serial.printf("Doluluk / Fill: %d cm = %%%d\n", cm, fillPercent);
176
177 if (fillPercent >= 90 && !fullWarned) { fullWarned = true; beep(3); }
178 if (fillPercent < 70) fullWarned = false;
179
180 // Bildirim: kapak kapalıyken, en fazla dakikada bir dene / Notify: only with the lid closed, retry at most once a minute
181 if (!notified && fillPercent >= NOTIFY_PCT && (lastTry == 0 || now - lastTry > 60000UL)) {
182 lastTry = now;
183 notified = sendTelegram("Çöp kutusu %" + String(fillPercent) + " dolu, boşaltma zamanı. / The bin is " +
184 String(fillPercent) + "% full.");
185 }
186 if (notified && fillPercent < RESET_PCT) { // boşaltıldı: yeniden kur / emptied: re-arm
187 notified = false;
188 lastTry = 0;
189 sendTelegram("Çöp kutusu boşaltıldı. / The bin has been emptied.");
190 }
191 }
192}Notifikasi dikirim sekali ketika tempat sampah mencapai 85%, lalu diaktifkan lagi dengan pesan “sudah dikosongkan” ketika tingkat isinya turun di bawah 30%, jadi ponselmu tidak bergetar setiap 3 detik. Jika tidak ada Wi-Fi atau pengiriman gagal, kodenya mencoba lagi sekali per menit, dan selama itu tempat sampah tetap bekerja normal. Mengirim pesan butuh 1–3 detik karena koneksinya terenkripsi (TLS), itulah sebabnya kode hanya mengirim ketika tutup tertutup. setInsecure() terhubung tanpa memverifikasi sertifikat server; itu tidak masalah untuk proyek hobi, tapi ingat bahwa token adalah informasi rahasia, jadi hapus dulu sebelum membagikan kodemu. Jika kamu melihat “Telegram HTTP 200” di Serial Monitor, pesannya sudah terkirim; 401 berarti token salah, 400 berarti chat ID salah, dan 403 berarti kamu belum mengirim /start ke bot. Untuk bot lengkap yang menanggapi perintah, lihat panduan bot Telegram ESP32.
Tempat sampah pintar dengan Raspberry Pi Pico (MicroPython)
Di Raspberry Pi Pico, logika yang sama dibuat dengan MicroPython. Fungsi time_pulse_us() bekerja seperti pulseIn() di Arduino; karena fungsi ini mengembalikan nilai negatif ketika tidak ada gema, kita menganggapnya 999, yang berarti “tidak ada gema”. Servo memakai PWM 50 Hz dan duty_ns(), yang menerima lebar pulsa dalam nanodetik; duty_ns(0) menghentikan pulsa dan melepas servo. Perbandingan waktu dilakukan dengan ticks_ms() dan ticks_diff(); ticks_diff memberi selisih yang benar bahkan ketika penghitungnya berputar kembali ke awal. Jika kamu menyimpan kodenya ke Pico sebagai main.py dengan Thonny, kode akan berjalan sendiri setiap kali board menyala. Kalau kamu memakai Pico W, kamu bisa menambahkan cara dari artikel web server Pico W untuk menampilkan tingkat isi lewat Wi-Fi.
1from machine import Pin, PWM, time_pulse_us
2import time
3
4# Pinler: ECHO'lar 1 kΩ / 2 kΩ bölücüyle / Pins: ECHOs via a 1 kΩ / 2 kΩ divider
5hand_trig, hand_echo = Pin(2, Pin.OUT), Pin(3, Pin.IN)
6fill_trig, fill_echo = Pin(4, Pin.OUT), Pin(5, Pin.IN)
7green, yellow, red = Pin(10, Pin.OUT), Pin(11, Pin.OUT), Pin(12, Pin.OUT)
8buzzer = Pin(13, Pin.OUT)
9servo = PWM(Pin(15))
10servo.freq(50) # servo için 50 Hz / 50 Hz for the servo
11
12HAND_CM = 20
13LID_CLOSED, LID_OPEN = 10, 110
14OPEN_MS, CLOSE_STEP_MS = 4000, 20
15EMPTY_CM, FULL_CM = 35, 8
16
17def ping_cm(trig, echo):
18 trig.low(); time.sleep_us(2)
19 trig.high(); time.sleep_us(10) # 10 µs tetik / 10 µs trigger
20 trig.low()
21 t = time_pulse_us(echo, 1, 30000) # yankı yoksa negatif / negative if there is no echo
22 return 999 if t < 0 else t // 58
23
24def median_cm(trig, echo): # 5 ölçümün ortancası / median of 5 readings
25 v = []
26 time.sleep_ms(60) # önce el sensörünün yankısı sönsün / first let the hand sensor's echo die out
27 for _ in range(5):
28 v.append(ping_cm(trig, echo))
29 time.sleep_ms(60)
30 v.sort()
31 return v[2]
32
33def servo_write(angle): # 0–180° → 544–2400 µs
34 servo.duty_ns((544 + angle * 1856 // 180) * 1000)
35
36def servo_release(): # darbe yok: servo serbest / no pulses: servo relaxes
37 servo.duty_ns(0)
38
39def show_level(p):
40 green.value(p < 50)
41 yellow.value(50 <= p < 80)
42 red.value(p >= 80)
43
44def beep(n):
45 for _ in range(n):
46 buzzer.on(); time.sleep_ms(120)
47 buzzer.off(); time.sleep_ms(120)
48
49state = "closed"
50fill, hits, warned, released = 0, 0, False, False
51last_hand = last_ping = close_start = last_fill = time.ticks_ms()
52servo_write(LID_CLOSED)
53time.sleep_ms(500)
54servo_release()
55released = True
56closed_at = time.ticks_ms()
57show_level(fill)
58
59while True:
60 now = time.ticks_ms()
61
62 if time.ticks_diff(now, last_ping) >= 60: # el sensörü, 60 ms'de bir / hand sensor, every 60 ms
63 last_ping = now
64 d = ping_cm(hand_trig, hand_echo)
65 hits = min(hits + 1, 2) if 2 <= d <= HAND_CM else 0
66 if hits >= 2:
67 last_hand = now
68 if state != "open": # kapanırken de yeniden açar / also reopens while closing
69 servo_write(LID_OPEN)
70 state, released = "open", False
71 if fill >= 90:
72 beep(2)
73
74 if state == "open" and time.ticks_diff(now, last_hand) >= OPEN_MS:
75 state, close_start = "closing", now
76
77 if state == "closing": # yavaş kapanma / slow close
78 moved = time.ticks_diff(now, close_start) // CLOSE_STEP_MS
79 if moved >= abs(LID_OPEN - LID_CLOSED):
80 servo_write(LID_CLOSED)
81 state, closed_at = "closed", now
82 else:
83 servo_write(LID_OPEN - moved if LID_OPEN > LID_CLOSED else LID_OPEN + moved)
84
85 if state == "closed" and not released and time.ticks_diff(now, closed_at) > 400:
86 servo_release()
87 released = True
88
89 if state == "closed" and time.ticks_diff(now, closed_at) > 1000 and time.ticks_diff(now, last_fill) >= 3000:
90 last_fill = now
91 cm = median_cm(fill_trig, fill_echo)
92 if cm < 999: # yankı yoksa eski değer kalır / keep the old value if no echo
93 fill = max(0, min(100, (EMPTY_CM - cm) * 100 // (EMPTY_CM - FULL_CM)))
94 show_level(fill)
95 print("Doluluk / Fill:", cm, "cm =", fill, "%")
96 if fill >= 90 and not warned:
97 warned = True
98 beep(3)
99 if fill < 70:
100 warned = False
101
102 time.sleep_ms(5)Tips presentasi proyek sekolah
Tempat sampah pintar adalah proyek yang sangat sering muncul di pameran sains dan pameran sekolah seperti TÜBİTAK 4006, jadi juri tidak terlalu tertarik pada tutup yang membuka dan menutup, tapi lebih pada bagaimana kamu merumuskan masalah, bagaimana kamu mengukurnya, dan apa kesimpulanmu. Yang mengubah proyekmu dari demo biasa menjadi kajian ilmiah adalah pengukuran: berapa kali percobaan tutupnya terbuka, seberapa cepat terbukanya, seberapa akurat perkiraan tingkat isinya, berapa jam baterainya bertahan. Kamu bisa menyusun presentasimu dengan urutan ini:
- Masalah: Menyentuh tutup dengan tangan menyebarkan kuman, dan tempat sampah yang meluap menimbulkan bau dan serangga. Mulailah dengan data nyata: hitung berapa orang yang menyentuh tutup tempat sampah di sekolahmu selama satu kali jam istirahat.
- Tujuan: Tempat sampah yang terbuka tanpa disentuh, memberi peringatan ketika penuh, dan bisa juga mengirim notifikasi ke ponselmu.
- Cara kerja: Gambar satu diagram blok yang menunjukkan sensor, Arduino, servo, LED, buzzer, ESP32, dan ponsel. Jelaskan kecepatan suara dan rumus bagi 58 dalam satu slide.
- Bahan dan biaya: Tampilkan daftar komponen dan pilihan servomu dalam bentuk tabel, bersama perhitungan torsinya.
- Demo langsung: Dekatkan tanganmu dan biarkan tutupnya terbuka. Isi tempat sampah dengan kertas dan tunjukkan LED berubah dari hijau ke kuning lalu merah; tampilkan pesan Telegram yang masuk ke ponselmu di layar proyektor.
- Hasil uji: Isi tabel di bawah dengan hasil pengukuranmu sendiri, lalu ubah hasilnya menjadi grafik.
- Kesimpulan dan perbaikan: Jelaskan dengan jujur apa yang berjalan baik, apa yang tidak, dan apa yang akan kamu ubah di versi berikutnya.
| Uji | Cara melakukannya | Nilai yang dicatat |
|---|---|---|
| Jarak deteksi | Tahan tanganmu pada jarak 5, 10, 15, 20, dan 25 cm, masing-masing 10 kali | Berapa kali tutup terbuka di setiap jarak (mis. 10/10) |
| Waktu respons | Rekam dengan ponsel dalam gerak lambat (240 fps) | Waktu antara tangan muncul dan tutup mulai bergerak (ms) |
| Pembukaan palsu | Berjalan melewati tempat sampah 20 kali | Jumlah pembukaan yang tidak diinginkan |
| Akurasi tingkat isi | Isi tempat sampah dengan kertas sampai seperempat, setengah, dan tiga perempat, diukur dengan penggaris | Selisih antara tingkat isi sebenarnya dan persentase terukur |
| Kecepatan menutup | Atur CLOSE_STEP_MS ke 5, 20, dan 40 ms | Lama penutupan dan tingkat kebisingan yang diukur dengan ponsel |
| Umur baterai | Jalankan dengan baterai penuh dan ukur tegangannya setiap jam | Berapa jam tempat sampah bekerja |
Ide pengembangan
- Tempat sampah dengan layar: Tampilkan persentase isi dan grafik batang di layar OLED.
- Ucapan terima kasih: Putar suara “terima kasih” yang singkat dengan DFPlayer Mini setiap kali tutup terbuka.
- Pengukuran berat: Pasang HX711 dan load cell di bawah tempat sampah untuk mengukur berapa kilo sampah di dalamnya, lalu gabungkan data volume dan berat.
- Pemilah daur ulang: Pakai sensor warna dan servo kedua untuk mengarahkan sampah ke dua kompartemen.
- Peringatan bau: Deteksi udara di dalam tempat sampah yang mulai busuk dengan MQ-135.
- Tempat sampah luar ruangan bertenaga surya: Singkirkan kabel sepenuhnya dengan panel surya kecil, sel 18650, modul charger TP4056, dan modul boost 5 V.
- Log tingkat isi: Tulis hasil pembacaan ke Google Sheets dengan ESP32, lalu buat grafik hari apa saja tempat sampah paling cepat penuh.
- Seluruh sekolah atau kompleks perumahan: Pantau tempat sampah di area yang tidak terjangkau Wi-Fi dari jarak ratusan meter dengan modul LoRa.
Kesalahan umum dan solusinya
| Gejala | Kemungkinan penyebab | Solusi |
|---|---|---|
| Tutup membuka dan menutup sendiri | Sensor melihat dinding di dekatnya atau orang yang lewat | Turunkan HAND_CM, miringkan sensor ke atas, sisakan ruang kosong 30 cm di depannya |
| Arduino restart ketika tutup terbuka | Arus awal servo menarik turun jalur 5 V | Kapasitor 470 µF, beri daya terpisah untuk servo yang kuat, GND bersama |
| Servo berdengung dan hangat ketika tutup tertutup | LID_CLOSED menekan tutup ke bibir tempat sampah | Mundurkan sudutnya 2–3 derajat; jangan hapus baris detach() |
| Tutup berhenti di tengah jalan atau bergetar | Torsi kurang atau sumbu tidak segaris | Servo yang lebih kuat, tutup yang lebih ringan, pemberat penyeimbang; luruskan poros servo dengan engsel |
| Tingkat isi tinggi padahal tempat sampah kosong | Tepi kantong di depan sensor, atau gema dinding di tempat sampah yang sempit | Lipat kantong ke luar, posisikan sensor di tengah, ukur ulang EMPTY_CM |
| Tingkat isi tidak pernah berubah | Sensor tidak menerima gema (999) atau kabel ECHO lepas | Pantau nilai cm mentah di Serial Monitor dan periksa pengkabelannya |
| Di ESP32 jaraknya selalu 999 atau angka ngawur | Pembagi ECHO tidak ada atau salah, atau kabel tertukar | Periksa pembagi 1 kΩ / 2 kΩ dan urutan TRIG-ECHO |
| ESP32 terus restart | Wi-Fi dan servo menarik arus bersamaan, kabel USB lemah | Pakai kabel pendek yang berkualitas dan beri daya servo dari catu 5 V terpisah |
| Pesan Telegram tidak masuk | Token atau chat ID salah, /start belum dikirim ke bot | Baca kode HTTP di Serial Monitor (401, 400, 403) |
Karena tempat sampah pintar menggabungkan pembacaan sensor, kendali servo, pengaturan waktu, dan perencanaan daya dalam satu proyek, proyek ini termasuk cara paling seru untuk belajar Arduino. Setelah kamu membuatnya, membuat sensor parkir atau pintu otomatis dengan komponen yang sama akan jauh lebih mudah. Di aplikasi BlueGrays kamu bisa menemukan proyek langkah demi langkah untuk mengukur jarak dengan HC-SR04, kendali servo, memakai buzzer, sensor parkir ESP32, dan alarm gerakan dengan notifikasi Telegram, lengkap dengan skema rangkaian dan kode siap pakai.
Pertanyaan umum
Bahan apa saja yang dibutuhkan untuk tempat sampah pintar Arduino?
Untuk versi dasar, cukup Arduino Uno atau Nano, satu sensor ultrasonik HC-SR04, servo yang sesuai dengan berat tutup (SG90 untuk tutup ringan, MG996R untuk tutup tempat sampah sungguhan), kabel jumper, dan catu daya 5 V. Untuk mengukur tingkat isi, tambahkan HC-SR04 kedua, tiga LED dengan resistor 220 Ω, dan buzzer aktif. Kalau kamu ingin notifikasi di ponsel, kamu bisa memakai ESP32 sebagai pengganti Arduino.
Bagaimana cara kerja tempat sampah pintar?
Sensor ultrasonik di bagian depan tempat sampah memancarkan gelombang suara dan mengukur berapa lama gemanya kembali; ketika sensor melihat tangan yang lebih dekat dari 20 cm, Arduino membuka tutup dengan motor servo. Beberapa detik setelah tangan pergi, tutup menutup pelan. Sensor kedua di bawah tutup mengukur tinggi sampah dan menunjukkan tingkat isi dengan LED dan buzzer.
Kenapa servoku tidak bisa mengangkat tutup tempat sampah?
Biasanya torsi servo terlalu kecil untuk tutupnya. Torsi yang dibutuhkan adalah berat tutup dikalikan jarak dari engsel ke titik beratnya; tutup 120 g sepanjang 25 cm butuh sekitar 1,5 kg·cm, yang sudah di batas kemampuan SG90. Pilih servo dengan rating dua kali hasil perhitunganmu, buat tutupnya lebih ringan atau tambahkan pemberat penyeimbang, dan pastikan catu daya servo bisa memberi arus yang cukup.
Bisakah aku memakai sensor IR sebagai pengganti HC-SR04 di tempat sampah pintar?
Bisa, sensor rintangan IR seperti FC-51 bisa mendeteksi tangan dari 2 sampai 30 cm, dan kodenya malah lebih sederhana karena sensor ini hanya memberi tahu ada benda atau tidak. Tapi sensor ini terpengaruh sinar matahari dan lebih lambat melihat permukaan gelap. Sensor PIR tidak cocok untuk tutup tempat sampah, karena terpicu oleh setiap orang yang lewat.
Berapa lama tempat sampah pintar Arduino bisa bertahan dengan baterai?
Tempat sampah berbasis Arduino Uno menarik rata-rata 70–80 mA, jadi bisa berjalan sekitar satu hari dengan 6 baterai AA, sekitar satu setengah hari dengan dua sel 18650, dan 3–4 hari dengan power bank 10.000 mAh. Untuk pemakaian permanen, adaptor 5 V lebih disarankan. Pro Mini, mode sleep, dan menyalakan LED hanya ketika perlu bisa membuat baterai bertahan 4–5 kali lebih lama.
Bagaimana cara mendapat notifikasi di ponsel ketika tempat sampah penuh?
ESP32 terhubung ke Wi-Fi, dan ketika tingkat isi melewati persentase yang kamu atur, ESP32 mengirim permintaan ke Telegram Bot API yang lalu mengantarkan pesan ke ponselmu. Untuk ini kamu butuh token bot dari BotFather dan chat ID-mu sendiri. Agar notifikasi yang sama tidak terkirim berulang-ulang, kodenya menunggu sampai tempat sampah dikosongkan.
Proyek untuk dibuat setelah membaca ini
Lihat semua proyek
Pengukuran Jarak HC-SR04 (Tampilan Serial)
Sensor HC-SR04 bekerja persis seperti kelelawar yang mencari jalan dalam gelap: ia mengirim suara yang tidak bisa kamu dengar, mendengarkan pantulannya, dan mengukur seberapa jauh benda di depannya. A

Menggunakan Buzzer
Pernah penasaran bagaimana bel pintu atau alarm mengeluarkan suaranya? Arduino membuat buzzer kecil berbunyi bip dengan jeda singkat: bip, jeda, bip, jeda. Kamu melihat bagaimana suara dibuat dengan l

Menggunakan Motor Servo
Lengan motor servo kecil berputar ke tiga posisi bergantian: penuh ke awal, tepat ke tengah, dan penuh ke akhir, menunggu dua detik di setiap perhentian. Arduino memberi tahu motor sudut mana yang har

Sensor Parkir dengan HC-SR04
Versi mini sensor parkir mobil: makin dekat sesuatu, makin cepat bunyi bipnya. Sensor jarak mengukur benda di depannya; jika jaraknya lebih dari 20 sentimeter LED hijau tetap menyala, dan begitu lebih

Sensor Jarak Ultrasonik HC-SR04 ESP32
Sensor ultrasonik HC-SR04 menghitung jarak dengan mengukur waktu yang dibutuhkan gelombang suara yang dipancarkannya untuk memantul dari benda lalu kembali (Time of Flight). Di proyek ini, kita mengirim pulsa 10 mikrodetik dari ESP32 ke pin TRIG sensor dan membaca durasi pantulan dari pin ECHO dengan pulseIn(). Jarak hasil hitung ditampilkan dalam sentimeter di LCD I2C 16x2. Karena HC-SR04 bekerja di 5V, pembagi tegangan wajib dipasang di pin ECHO.

Motor Servo ESP32 (Kendali Potensiometer)
Di proyek ini, kita mengendalikan motor servo SG90 memakai potensiometer. Kita mengatur sudut servo dengan memetakan nilai analog yang dibaca dari potensiometer ke rentang 0–180 derajat. Library ESP32Servo menghasilkan sinyal servo di pin GPIO ESP32 yang sesuai dan bisa menjadi output; proyek ini memakai GPIO 18. Ini metode kendali dasar untuk lengan robot, gimbal kamera, dan mekanisme pintu otomatis.

Sensor Parkir ESP32 (HC-SR04 + Bar 5 LED + Buzzer + OLED)
Versi ESP32 dari sensor parkir mobil! Kita memakai sensor ultrasonik HC-SR04 untuk mengukur jarak ke benda di depannya. Semakin dekat jaraknya, bar 5 LED semakin penuh (hijau → kuning → merah) dan jeda bunyi bip buzzer semakin pendek. Ketika benda sudah sangat dekat (di bawah 10 cm), alarm berbunyi terus dan semua LED menyala. Layar OLED SSD1306 menampilkan jarak terkini dalam cm dengan font besar, pesan status (STOP / CAUTION / CLOSE / STOP! / DANGER), dan simulasi bar jarak.

Sistem Alarm Gerakan ESP32 (PIR + Buzzer + LED + Telegram)
Sistem alarm keamanan pintar yang menyalakan buzzer dan LED ketika sensor PIR mendeteksi gerakan, sekaligus mengirim notifikasi instan ke pemilik lewat Telegram. Cooldown 30 detik membatasi seberapa sering alarm berulang; mekanisme ini tidak memvalidasi deteksi PIR atau menghilangkan pemicu palsu. Cocok untuk rumah, garasi, gudang, atau ruang kerja. Dengan ESP32-CAM bisa ditambahkan notifikasi berfoto; dengan ESP32 DevKit V1 klasik, notifikasinya berupa teks.
Artikel lainnya
Aplikasi BlueGrays
Rakit rangkaian ini langkah demi langkah di ponselmu
Skema pengkabelan, kode, dan daftar komponen dalam satu layar. 200+ proyek Arduino, ESP32, dan Pico siap dibuat.
Pindai dengan ponselmu
Arahkan kamera ke kode ini dan toko aplikasi di ponselmu akan terbuka.
atau buka toko aplikasi

