IoT Based Smart Bin
Circuit Explanation
In this IoT-based smart bin project, an Arduino Uno R4 WiFi acts as the central control unit, interfacing with two ultrasonic sensors and a servo motor. The power bank provides 5V via the USB-C port, supplying sufficient power for all components.
Fig 1. Automated trash bin setup using an ESP32, ultrasonic sensors, and a servo motor
One ultrasonic sensor is positioned to detect hand proximity, triggering the servo motor to open the bin lid when an object (like a hand) is nearby. This sensor sends a signal to the Arduino, which then activates the servo motor. The servo, mounted on the bin’s edge, functions as a lever, lifting the lid when the bin needs to open.
The second ultrasonic sensor monitors the bin’s fill level by measuring the distance from the sensor to the top of the garbage. When the detected distance indicates that the bin is full, a notification can be sent to a connected device (if implemented), or a status LED can be turned on.
All components are powered directly by the Arduino’s 5V supply, with wiring and connections visualized in the Fritzing diagram for easy assembly.
Code Explanation
Setup
Fig 2. User interface of IoT-based Smart Bin displaying bin status, fill level, lid position, and sensor connectivity.
Libraries and Constants
- Libraries: Includes Servo, Firebase, and ArduinoJson libraries.
- Constants: Define key pins (e.g.,
servoPin
), WiFi credentials, and Firebase URL for configuration.
Variable Initialization
Key variables are initialized to manage sensor readings, component statuses, and control flags. Examples include:
lidDistance
- Stores the measured distance from the lid sensor.isServoMoving
- Flag indicating if the servo is currently moving.isMeasurementPaused
- Pauses measurements during lid operation.
#include <Servo.h>
#include <Firebase.h>
#include <ArduinoJson.h>
#include "secrets.h"
// Servo instance
Servo myservo;
// Pin definitions
const int binLidTriggerPin = 7;
const int binLidEchoPin = 6;
const int binStoreTriggerPin = 5;
const int binStoreEchoPin = 4;
const int servoPin = 3;
// Firebase instance
Firebase fb(REFERENCE_URL);
// Variables for distance measurement
float lidDistance;
float storeDistance;
float duration;
bool isServoMoving = false;
unsigned long servoStartTime = 0;
unsigned long measurementPauseTime = 0;
bool isMeasurementPaused = false;
// Variables for pin status
bool lidSensorWorking = false;
bool storeSensorWorking = false;
bool servoWorking = false;
int binFillPercentage = 0;
bool binStatus = true;
int binHeight = 30;
WiFi Connection
Connects to WiFi, turning on the built-in LED if the connection is successful. This enables Firebase updates.
Component Configuration
- Sets up ultrasonic sensor pins.
- Positions servo motor at the initial angle (0 degrees).
- Loads bin configuration data from Firebase.
void setup() {
Serial.begin(9600);
delay(1000);
// Initialize WiFi for non-Uno WiFi R4 boards
#if !defined(ARDUINO_UNOWIFIR4)
WiFi.mode(WIFI_STA);
#else
// Configure LED for Uno WiFi R4
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
#endif
WiFi.disconnect();
delay(1000);
// Connect to WiFi
Serial.println();
Serial.println();
Serial.print("Connecting to: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print("-");
delay(500);
}
Serial.println();
Serial.println("WiFi Connected");
// Turn on LED if Uno WiFi R4 is used
#if defined(ARDUINO_UNOWIFIR4)
digitalWrite(LED_BUILTIN, HIGH);
#endif
// Pin setup for ultrasonic sensors
pinMode(binLidTriggerPin, OUTPUT);
pinMode(binLidEchoPin, INPUT);
pinMode(binStoreTriggerPin, OUTPUT);
pinMode(binStoreEchoPin, INPUT);
digitalWrite(binLidTriggerPin, LOW);
digitalWrite(binStoreTriggerPin, LOW);
// Verify connections for ultrasonic sensors and servo
lidSensorWorking = verifyUltrasonicSensor(binLidTriggerPin, binLidEchoPin);
storeSensorWorking = verifyUltrasonicSensor(binStoreTriggerPin, binStoreEchoPin);
myservo.attach(servoPin);
servoWorking = verifyServo();
// Initialize servo position
myservo.write(0);
// Initial Firebase update to get bin configuration
getBinConfiguration();
}
Loop
The loop()
function runs continuously to monitor bin operation.
Configuration Check
Fetches bin configuration from Firebase if a status change is detected.
Component Check
Verifies if all components (lid sensor, store sensor, servo motor) are functioning. Pauses briefly (5 seconds) before rechecking if any component fails.
Lid Distance and Fill Level Measurement
- Lid Distance: Measures distance to detect nearby objects for lid operation.
- Fill Level: Calculates the bin fill percentage and sends updates to Firebase if needed.
void loop() {
if (!binStatus) {
if (millis() % 10000 == 0) { // Check status every 10 seconds
getBinConfiguration();
}
return;
}
if (!checkComponents()) return;
if (isMeasurementPaused) {
if (millis() - measurementPauseTime >= 8000) {
isMeasurementPaused = false;
}
return;
}
measureLidDistance();
if (lidSensorWorking && servoWorking && lidDistance < 5 && !isServoMoving) {
operateLid();
}
measureStoreLevel();
delay(100);
}
Key Functions
Component Verification (checkComponents()
)
Ensures that the lid sensor, store sensor, and servo motor are working. If critical components are not functional, the function waits for 5 seconds before retrying.
Distance Measurement (measureDistance()
)
Measures distance by sending a pulse from the ultrasonic sensor and calculating the time for the echo to return. Returns -1 for reading errors.
Lid Operation (operateLid()
)
Controls the servo to open and close the lid:
- Opens lid by rotating servo to 180 degrees.
- Waits for 4 seconds (time for disposal).
- Closes lid by rotating servo back to 0 degrees.
- Pauses measurements and updates Firebase with the current bin status.
Store Level Measurement (measureStoreLevel()
)
Measures the fill level of the bin and calculates the fill percentage. Sends an alert to Firebase if the bin is nearly full (95% or higher).
Utility Functions
Additional utility functions:
verifyUltrasonicSensor()
: Verifies if the ultrasonic sensor is functioning correctly by sending a test pulse.verifyServo()
: Ensures the servo motor is attached and responsive.calculateFillPercentage()
: Converts the distance reading to a fill percentage based on bin dimensions.
// Function to check component functionality
bool checkComponents() {
if (!lidSensorWorking && !storeSensorWorking && !servoWorking) {
Serial.println("Critical failure: No components working.");
delay(5000);
return false;
}
return true;
}
// Function to handle lid distance measurement
void measureLidDistance() {
if (lidSensorWorking) {
lidDistance = measureDistance(binLidTriggerPin, binLidEchoPin);
if (lidDistance >= 0) {
Serial.print("Lid Distance: ");
Serial.print(lidDistance);
Serial.println(" cm");
}
else {
Serial.println("Lid Sensor: Reading Error");
}
}
}
// Function to perform lid opening operation
void operateLid() {
isServoMoving = true;
isMeasurementPaused = true;
measurementPauseTime = millis();
myservo.write(180); // Open lid
delay(4000); // Wait for garbage to be thrown in
updateFirebase(); // Update Firebase to show lid open
Serial.println("Lid is Opened");
myservo.write(0); // Close lid
delay(1000); // Short delay to ensure lid closes
Serial.println("Lid is Closed");
isServoMoving = false;
measureStoreLevel(); // Check bin store level
updateFirebase(); // Update Firebase with new data
}
// Measure bin store level and update bin fill percentage
void measureStoreLevel() {
if (storeSensorWorking && !isServoMoving) {
storeDistance = measureDistance(binStoreTriggerPin, binStoreEchoPin);
if (storeDistance >= 0) {
int newFillPercentage = calculateFillPercentage(storeDistance);
if (newFillPercentage != binFillPercentage) {
binFillPercentage = newFillPercentage;
Serial.print("Bin Fill: ");
Serial.print(binFillPercentage);
Serial.println("%");
if (binFillPercentage >= 95) {
Serial.println(" **_ BIN FULL - ALERT! _**");
}
}
}
else {
Serial.println("Bin Store Sensor: Reading Error");
}
}
}
// Utility functions
bool verifyUltrasonicSensor(int trigPin, int echoPin) {
for (int i = 0; i < 3; i++) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 35000);
if (duration > 0) {
return true;
}
delay(50);
}
return false;
}
bool verifyServo() {
return myservo.attached();
}
float measureDistance(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
return (duration == 0) ? -1 : (duration * 0.034) / 2;
}
int calculateFillPercentage(float distance) {
if (distance >= binHeight)
return 0;
if (distance <= 5)
return 100;
return (int)(100 - ((distance - 5) * 100) / (binHeight - 5));
}
Components Required
- Arduino UNO R4 WiFi
- 1 MG90S Servo Motor
- 1 HC-SR04 Ultrasonic Sensor
- 2 Connecting Jumper Wires
- Required Quantity Power Bank
For More Information
+250783159293