Panduan · 18 mnt baca

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.

Sensor jarak ultrasonik HC-SR04
HC-SR04 punya dua tugas di tempat sampah pintar: sensor di bagian depan mengukur tangan yang mendekat, sedangkan sensor di bawah tutup mengukur tinggi sampah. Sensor ini melihat dari 2 sampai 400 cm dalam berkas yang sempit.

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).

KomponenTugasCatatan
Arduino Uno (atau Nano)Otaknya: mengukur, memutuskan, dan menggerakkan servo serta LEDESP32 atau Pico juga bisa
2 × HC-SR04Satu mendeteksi tangan, satu lagi mengukur tingkat isi5 V, sekitar 15 mA ketika mengukur
Servo SG90, MG90S, atau MG996RMembuka dan menutup tutupDipilih berdasarkan berat tutup (perhitungannya di bawah)
3 LED (hijau, kuning, merah) dan 3 × 220 ΩIndikator tingkat isiSatu resistor untuk setiap LED
Buzzer aktifPeringatan penuhBuzzer pasif butuh tone()
Engsel, sekrup, lem tembakMenopang tutup, menahan lengan servoBerat tutup harus ditopang engsel, bukan servo
Kapasitor 470 µFMeredam arus awal servo ketika mulai bergerakDipasang di antara + dan − servo, perhatikan polaritasnya
Catu dayaAdaptor 5 V, power bank, atau bateraiPerhitungan lama pemakaian di bawah
ESP32 (opsional)Notifikasi tingkat isi di ponselmuButuh Wi-Fi
Arduino Uno
Arduino Uno
Motor servo SG90
Motor servo SG90
Buzzer
Buzzer
LED
LED

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:

SensorCara mendeteksiUntuk tempat sampah
HC-SR04 (ultrasonik)Gema suara, 2–400 cm, kerucut sempitAmbang diatur di kode; pilihan paling seimbang
Sensor rintangan IR (FC-51)Pantulan cahaya inframerah, sekitar 2–30 cmMurah dan cepat; bisa terkecoh sinar matahari dan sarung tangan gelap
PIR (HC-SR501)Gerakan panas tubuh, sampai 7 m, sudut lebarTerpicu oleh setiap orang yang lewat dan bertahan beberapa detik; tidak cocok
APDS-9960Kedekatan jarak pendek dan gestur tanganVersi 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.

Jangan pernah memicu kedua HC-SR04 bersamaan. Masing-masing akan mengira gema sensor lain sebagai gemanya sendiri, dan keduanya membaca angka ngawur. Di kode, kedua sensor diukur bergantian dengan jeda minimal 60 ms; sensor tangan menunggu selama sensor isi mengambil 5 pembacaannya. Bagian depan sensor juga harus tetap bersih: tepi lubang yang kamu potong di tempat sampah harus rata dengan muka sensor, dan bahkan sepotong plastik tipis atau selotip bening di depannya akan menghalangi gema.

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.

KoneksiArduino UnoESP32Raspberry Pi Pico
TRIG sensor tanganD2GPIO 18GP2
ECHO sensor tanganD3 (langsung)GPIO 19, lewat pembagi 1 kΩ / 2 kΩGP3, lewat pembagi 1 kΩ / 2 kΩ
TRIG sensor isiD4GPIO 25GP4
ECHO sensor isiD5 (langsung)GPIO 26, lewat pembagiGP5, lewat pembagi
VCC HC-SR04 (keduanya)5V5V (VIN)VBUS
Sinyal servo (oranye)D9GPIO 13GP15
Servo + (merah)5V (SG90) atau 5–6 V eksternal5V (VIN) atau 5–6 V eksternalVBUS atau 5–6 V eksternal
LED hijau, kuning, merah (dengan 220 Ω)D10, D11, D12GPIO 27, 32, 33GP10, GP11, GP12
Buzzer aktif (+)D8GPIO 23GP13
Semua GNDGNDGNDGND
Pin ECHO pada HC-SR04 mengeluarkan pulsa 5 V, sedangkan pin ESP32 dan Pico bekerja di 3,3 V dan tidak tahan 5 V. Buat pembagi tegangan terpisah di jalur ECHO setiap sensor: ECHO → 1 kΩ → titik yang menuju board → 2 kΩ → GND. Hasilnya 5 V × 2 / 3 ≈ 3,3 V. TRIG tidak butuh pembagi; pemicu 3,3 V sudah cukup untuk sensor. Pin 5V (VIN) di ESP32 dan pin VBUS di Pico hanya memberi 5 V selama board mendapat daya dari USB.

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.

TutupBeratTitik beratTorsi yang dibutuhkanDengan margin 2×Saran
Karton atau foam board 20 × 20 cm50 g10 cm0,5 kg·cm1,0 kg·cmSG90
Tutup tempat sampah plastik 25 cm120 g12,5 cm1,5 kg·cm3,0 kg·cmMG996R (MG90S pas-pasan)
Tutup MDF atau tripleks 30 cm300 g15 cm4,5 kg·cm9,0 kg·cmMG996R ditambah pemberat penyeimbang
ServoTorsi (4,8 V / 6 V)GigiArusCatatan
SG901,8 kg·cm (hanya ada rating 4,8 V)Plastik100–250 mA ketika bergerakBisa diberi daya dari pin 5V Arduino
MG90S1,8 / 2,2 kg·cmLogam150–300 mA ketika bergerakUkurannya sama dengan SG90, lebih awet
MG996R9,4 / 11 kg·cmLogam0,5–0,9 A ketika bergerak, sampai 2,5 A ketika macet (stall)Wajib diberi daya dari catu 5–6 V terpisah
Motor servo bergigi logam MG996R
MG996R: servo bergigi logam dengan torsi sekitar 11 kg·cm pada 6 V. Servo ini mudah mengangkat tutup plastik tempat sampah sungguhan, tapi karena bisa menarik arus sampai 2,5 A ketika macet, servo ini wajib diberi daya dari catu terpisah, bukan dari Arduino.

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.

C++ (Arduino IDE)
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}
  1. Upload kodenya tanpa memasang lengan servo, lalu buka Serial Monitor di 9600 baud; atur akhir baris ke Newline. Servo bergerak ke 90 derajat.
  2. Ketik 10 lalu tekan Enter. Tahan tutup dalam posisi tertutup, pasang lengan servo ke poros di posisi ini, lalu kencangkan ke tutup.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.

C++ (Arduino IDE)
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 pengaturanKegunaannya
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
handHitsMenghitung berapa pembacaan berturut-turut yang melihat tangan; satu pembacaan palsu saja tidak akan membuka tutup
OPEN_TIMEWaktu dari terakhir kali tangan terlihat sampai penutupan dimulai (4000 ms)
CLOSE_STEP_MSWaktu per derajat ketika menutup: 100 derajat × 20 ms = penutupan 2 detik
lid.detach()Berhenti mengirim pulsa ke servo 0,4 dtk setelah tutup tertutup
fullWarnedMembunyikan 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 isiLEDBuzzerArtinya
0–49%HijauDiamMasih banyak ruang
50–79%KuningDiamLebih dari setengah penuh, segera kosongkan
80–89%MerahDiamHampir penuh
90–100%Merah3 bunyi pendek ketika penuh, 2 bunyi setiap kali terbukaKosongkan 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.

Kecepatan suara berubah mengikuti suhu: kira-kira v = 331,3 + 0,606 × T (m/dtk). Angka 58 tepat untuk 20 °C; di balkon bersuhu 5 °C suara merambat lebih lambat, jadi hasil pembacaan sekitar 3% terlalu panjang. Di tempat sampah sedalam 35 cm, itu kesalahan kurang dari 1 cm dan tidak berpengaruh pada tingkat isi, tapi kalau juri bertanya, tahu alasannya akan memberi kesan yang bagus.

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 dayaKoneksiPerkiraan lama pakai (75 mA)Penilaian
Baterai 9 V PP3 (sekitar 500 mAh)VIN5–6 jamTidak disarankan: tegangannya anjlok ketika servo mulai bergerak dan board ter-reset
6 × AA alkaline (9 V)Jack DC atau VINSekitar 1 hariCukup untuk hari presentasi
2 × 18650 (7,4 V, 2500 mAh)VIN; LM2596 diatur ke 5–6 V untuk servoSekitar 1,5 hariBisa diisi ulang; butuh charger 2S dan board proteksi
Power bank 10.000 mAhUSB3–4 hariSebagian power bank mati sendiri dengan beban di bawah 50–100 mA
Adaptor 5 V 2 AUSB atau pin 5VTanpa batasPilihan terbaik untuk pemakaian permanen di rumah
Tempat baterai Li-ion 18650
Tempat baterai 18650: dua sel yang dipasang seri memberi 7,4 V. Tegangan itu cocok untuk memberi daya ke Arduino lewat VIN; untuk servo, modul step-down yang diatur ke 5–6 V dipasang di antaranya.

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.

Semua GND servo, sensor, dan Arduino harus tersambung bersama; jika GND servo yang diberi daya dari catu terpisah tidak dihubungkan ke Arduino, servo tidak bisa memahami sinyalnya dan bergetar. Pasang kapasitor 470 µF di antara kabel catu daya servo. Jika Arduino restart setiap kali tutup terbuka, berarti servo menarik turun jalur 5 V ketika mulai bergerak; penyebab dan solusinya ada di artikel Arduino terus reset.

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.

Board pengembangan ESP32
ESP32: berkat Wi-Fi-nya, board ini mengirim pesan Telegram ke ponselmu ketika tempat sampah penuh. Jalur ECHO dari HC-SR04 tidak boleh disambungkan ke pin-nya tanpa diturunkan dulu ke 3,3 V.
C++ (Arduino IDE)
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.

MicroPython
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:

  1. 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.
  2. Tujuan: Tempat sampah yang terbuka tanpa disentuh, memberi peringatan ketika penuh, dan bisa juga mengirim notifikasi ke ponselmu.
  3. 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.
  4. Bahan dan biaya: Tampilkan daftar komponen dan pilihan servomu dalam bentuk tabel, bersama perhitungan torsinya.
  5. 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.
  6. Hasil uji: Isi tabel di bawah dengan hasil pengukuranmu sendiri, lalu ubah hasilnya menjadi grafik.
  7. Kesimpulan dan perbaikan: Jelaskan dengan jujur apa yang berjalan baik, apa yang tidak, dan apa yang akan kamu ubah di versi berikutnya.
UjiCara melakukannyaNilai yang dicatat
Jarak deteksiTahan tanganmu pada jarak 5, 10, 15, 20, dan 25 cm, masing-masing 10 kaliBerapa kali tutup terbuka di setiap jarak (mis. 10/10)
Waktu responsRekam dengan ponsel dalam gerak lambat (240 fps)Waktu antara tangan muncul dan tutup mulai bergerak (ms)
Pembukaan palsuBerjalan melewati tempat sampah 20 kaliJumlah pembukaan yang tidak diinginkan
Akurasi tingkat isiIsi tempat sampah dengan kertas sampai seperempat, setengah, dan tiga perempat, diukur dengan penggarisSelisih antara tingkat isi sebenarnya dan persentase terukur
Kecepatan menutupAtur CLOSE_STEP_MS ke 5, 20, dan 40 msLama penutupan dan tingkat kebisingan yang diukur dengan ponsel
Umur bateraiJalankan dengan baterai penuh dan ukur tegangannya setiap jamBerapa jam tempat sampah bekerja
Juri biasanya bertanya soal titik lemah, jadi siapkan jawabanmu dari awal. HC-SR04 kurang bisa melihat permukaan yang lunak dan berpori, jadi tutup mungkin terbuka terlambat untuk sarung tangan kain yang tebal. Pengukuran isi melihat titik tertinggi sampah, bukan rata-ratanya. Tempat sampah berbasis Uno hanya bertahan 1–2 hari dengan baterai. Menunjukkan bahwa kamu tahu batasan-batasan ini dan menawarkan solusi untuk masing-masing akan memberimu nilai jauh lebih tinggi daripada menampilkan proyekmu seolah-olah tanpa cela.

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

GejalaKemungkinan penyebabSolusi
Tutup membuka dan menutup sendiriSensor melihat dinding di dekatnya atau orang yang lewatTurunkan HAND_CM, miringkan sensor ke atas, sisakan ruang kosong 30 cm di depannya
Arduino restart ketika tutup terbukaArus awal servo menarik turun jalur 5 VKapasitor 470 µF, beri daya terpisah untuk servo yang kuat, GND bersama
Servo berdengung dan hangat ketika tutup tertutupLID_CLOSED menekan tutup ke bibir tempat sampahMundurkan sudutnya 2–3 derajat; jangan hapus baris detach()
Tutup berhenti di tengah jalan atau bergetarTorsi kurang atau sumbu tidak segarisServo yang lebih kuat, tutup yang lebih ringan, pemberat penyeimbang; luruskan poros servo dengan engsel
Tingkat isi tinggi padahal tempat sampah kosongTepi kantong di depan sensor, atau gema dinding di tempat sampah yang sempitLipat kantong ke luar, posisikan sensor di tengah, ukur ulang EMPTY_CM
Tingkat isi tidak pernah berubahSensor tidak menerima gema (999) atau kabel ECHO lepasPantau nilai cm mentah di Serial Monitor dan periksa pengkabelannya
Di ESP32 jaraknya selalu 999 atau angka ngawurPembagi ECHO tidak ada atau salah, atau kabel tertukarPeriksa pembagi 1 kΩ / 2 kΩ dan urutan TRIG-ECHO
ESP32 terus restartWi-Fi dan servo menarik arus bersamaan, kabel USB lemahPakai kabel pendek yang berkualitas dan beri daya servo dari catu 5 V terpisah
Pesan Telegram tidak masukToken atau chat ID salah, /start belum dikirim ke botBaca kode HTTP di Serial Monitor (401, 400, 403)
Ketika mencari masalah, uji komponennya satu per satu: pertama, periksa dengan sketch kalibrasi bahwa kedua sensor memberi nilai yang masuk akal di Serial Monitor, lalu pastikan servo bergerak mulus ke sudut tertutup dan terbuka, baru setelah itu upload kode utama. Jika kamu melihat pesan “Brownout detector was triggered” di ESP32, penyebab dan solusinya ada di artikel ESP32 terus restart.

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.

Lihat semua proyek
Pengukuran Jarak HC-SR04 (Tampilan Serial)
#27Pemula

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

4.6(46)
71
Menggunakan Buzzer
#13Pemula

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

4.7(89)
161
Menggunakan Motor Servo
#35Pemula
Premium

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

4.7(48)
67
Sensor Parkir dengan HC-SR04
#28Menengah
Premium

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

4.8(64)
85
Sensor Jarak Ultrasonik HC-SR04 ESP32
#116Menengah

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.

4.9(28)
45
Motor Servo ESP32 (Kendali Potensiometer)
#118Menengah
Premium

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.

4.3(29)
42
Sensor Parkir ESP32 (HC-SR04 + Bar 5 LED + Buzzer + OLED)
#142Mahir
Premium

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.

0.0(0)
14
Sistem Alarm Gerakan ESP32 (PIR + Buzzer + LED + Telegram)
#145Mahir
Premium

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.

0.0(0)
9