# ============================================================
# SMART WASTE BIN MONITORING SYSTEM - COMPLETE PRODUCTION CODE
# Target Platform: Raspberry Pi Pico W
# Configured for: MQ2 + HC-SR04 + OLED + 4-Pin Tactile Button
# ============================================================
from machine import Pin, ADC, I2C, time_pulse_us
import ssd1306
import time
# ============================================================
# PHYSICAL HARDWARE PIN ASSIGNMENTS
# ============================================================
# 1. MQ2 Gas Sensor (Yellow wire -> GP26 / ADC0)
mq2 = ADC(26)
# 2. HC-SR04 Ultrasonic Sensor (Trig -> GP16, Echo -> GP17 via Voltage Divider)
trig = Pin(16, Pin.OUT)
echo = Pin(17, Pin.IN)
# 3. Piezo Buzzer (Positive Leg -> GP15)
buzzer = Pin(15, Pin.OUT)
# 4. Push Button (Pin 1L -> GP14, Pin 2L -> 3.3V)
# Internal microchip Pull-Down keeps logic safely at 0 until pressed
button = Pin(14, Pin.IN, Pin.PULL_DOWN)
# ============================================================
# OLED DISPLAY CONFIGURATION & ERROR-SAFE BUS INITIALIZATION
# ============================================================
oled = None
print("Checking display hardware connection...")
try:
# Attempt Primary Map (SDA -> GP2, SCL -> GP3 on I2C1)
i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
print("-> OLED Success: Connected on I2C Bus 1 (GP2/GP3)")
except Exception:
try:
# Fallback Standard Map (SDA -> GP0, SCL -> GP1 on I2C0)
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
print("-> OLED Success: Connected on I2C Bus 0 (GP0/GP1)")
except Exception as error_msg:
print("!! SCREEN ALERT: Could not bind to I2C interface.")
print(" Verify VCC/GND power tracks or missing 'ssd1306.py' file.")
print(" Details:", error_msg)
# ============================================================
# CONTEXT CALIBRATION VARIABLES
# ============================================================
BIN_HEIGHT = 40 # Depth/Height of your physical waste bin in cm
FULL_LEVEL = 80 # The fill percentage that triggers a "BIN FULL" alert
MQ2_THRESHOLD = 28000 # Calibrated 16-bit analog boundary for organic odor spikes
# ============================================================
# HELPER ACTIONS / FUNCTIONS
# ============================================================
def beep(duration):
"""Flashes the pin high to trigger the piezo element alert tone"""
buzzer.high()
time.sleep(duration)
buzzer.low()
def get_distance():
"""Triggers the ultrasonic sensor module and records return travel duration"""
trig.low()
time.sleep_us(2)
# Send high ultrasonic pulse burst
trig.high()
time.sleep_us(10)
trig.low()
try:
# Echo pin waits for high return pulse timeout capped at 30ms max
duration = time_pulse_us(echo, 1, 30000)
if duration < 0:
return -1 # Hardware readout fault indicator
# Speed of sound parsing formula to evaluate range boundary
distance = (duration * 0.0343) / 2
return distance
except:
return -1
def get_fill_percentage(distance):
"""Translates free-space distance to total internal mass capacity percentage"""
if distance < 0:
return 0
fill = ((BIN_HEIGHT - distance) / BIN_HEIGHT) * 100
# Strict clamp safety boundaries (Keep value within 0% - 100%)
if fill < 0: fill = 0
if fill > 100: fill = 100
return fill
def display_data(gas, distance, fill, status):
"""Refreshes the memory matrix on the screen and prints layout"""
if oled is None:
return
oled.fill(0)
oled.text("SMART WASTE BIN", 0, 0)
oled.text("Gas Vol: {}".format(gas), 0, 16)
oled.text("Dist: {:.1f}cm".format(distance), 0, 30)
oled.text("Fill: {:.1f}%".format(fill), 0, 44)
oled.text("SYS: {}".format(status), 0, 56)
oled.show()
# ============================================================
# BOOT EXECUTION SPLASH
# ============================================================
if oled:
oled.fill(0)
oled.text("SMART WASTE BIN", 0, 20)
oled.text("SYSTEM ONLINE", 0, 38)
oled.show()
print("\n=========================================")
print(" WASTE MONITOR ACTIVE & READY ")
print("=========================================")
time.sleep(1.5)
# ============================================================
# MAIN APPLICATION LOOP
# ============================================================
while True:
# Idle Waiting Prompt Frame
if oled:
oled.fill(0)
oled.text(" [ STATUS IDLE ] ", 0, 15)
oled.text("PRESS BUTTON TO", 5, 35)
oled.text("SCAN CAPACITIES", 5, 48)
oled.show()
# Smooth clock baseline loop cadence to prevent tracking bounces
time.sleep(0.05)
# Detect pull-up state shift (Button Pressed)
if button.value() == 1:
print("\n--- Gathering Real-Time Environment Metrics ---")
# Read Current Values
gas_value = mq2.read_u16()
distance = get_distance()
# Error fallbacks if ultrasonic is completely blocked or unplugged
if distance == -1:
distance = BIN_HEIGHT
fill_percent = get_fill_percentage(distance)
# Output Data Struct Directly to IDE Console Log
print("Gas Registry Value (16-bit ADC):", gas_value)
print("Target Object Distance :", round(distance, 1), "cm")
print("Computed Mass Capacity :", round(fill_percent, 1), "%")
# Decision Matrix evaluation logic
if fill_percent >= FULL_LEVEL:
status = "BIN FULL!"
print("ALERT NOTIFICATION -> Capacity Threshold Exceeded!")
beep(1.0) # Long tone warning
elif gas_value >= MQ2_THRESHOLD:
status = "BAD SMELL!"
print("ALERT NOTIFICATION -> High Accumulation Odor Spike!")
beep(0.5) # Short warning tone
else:
status = "NORMAL OPER."
print("STATUS -> Environment vectors within normal limits.")
# Push data payload structures directly into display update logic
display_data(gas_value, distance, fill_percent, status)
# Retain measured info visible window for user review before resetting frame
time.sleep(4.5)Loading
ssd1306
ssd1306