IoT Based Smart Bin

Published  November 14, 2024   0
IoT Based Smart Bin

Our IoT-Based Smart Bin project features a custom-built IoT system and Firebase database, using the Arduino Uno R4 WiFi. Dual ultrasonic sensors handle motion and fill-level monitoring, with an automated lid synced to a Firebase dashboard built on Vite+React for real-time updates. This solution uniquely integrates our own IoT network for efficient waste management. We’re moving forward with multi-node testing to enhance scalability and user experience.

Components Required

 

Navigate to This YouTube Video for Full Demonstration of the Project

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.

Smart Bin Circuit Diagram

 

IoT Smart Bin Circuit Connection


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

IoT Smart Bin UI


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

}

 

Click on the GitHub Image to View or download code

Have any question realated to this Article?

Ask Our Community Members