Dumpster Fire 3000
Vision-based waste sorting robot with LLM classification and async servo actuation
Winner of Most Useless lol
Summary
Dumpster Fire 3000 is a smart waste-sorting robot that classifies discarded items as recyclable, compost, or waste, then routes them into the correct compartment using a servo-driven mechanism. The system combines computer vision, LLM-based classification, Raspberry Pi actuation, a FastAPI backend, a Postgres database, and a React web app with a gamified Plinko experience.
The project started from a simple observation: people often throw items into the wrong bin, even when recycling and compost options are available. We wanted to make waste disposal easier, faster, and more engaging by turning each drop into an interactive moment.
Inspiration
Our inspiration came from a problem we kept seeing in everyday life: people often do not sort their trash correctly. Sometimes they are in a rush, sometimes they are unsure where an item belongs, and sometimes there is simply no incentive to care.
Even when the right bins are available, trash still ends up in the wrong place. At the same time, gamified experiences are incredibly effective at capturing attention and motivating behavior. We wanted to use that idea to make proper waste disposal feel fun, interactive, and rewarding.
That led us to build Dumpster Fire 3000: a smart waste-sorting system that makes throwing something away faster, easier, and a little more exciting.
What It Does
When a user drops an item into the bin, Dumpster Fire 3000 detects the drop, captures an image, classifies the item, and physically routes it into the correct compartment.
The system supports three disposal categories:
- –Recyclable
- –Compost
- –Waste
A laptop handles vision and classification. Using OpenCV, it watches for a sustained brightness change in the camera feed, which signals that a hand or object has entered the bin. Once triggered, the laptop captures a frame and sends it to Google Gemini using a strict JSON schema with:
- –
predicted_class - –
disposal_category - –
estimated_usd_value
After classification, the laptop sends a sorting command to a Raspberry Pi over WebSockets. The Pi maps the predicted disposal category to a predefined servo choreography, driving three servos through an Adafruit PCA9685 I2C servo controller.
On the web side, users can sign in, view their drops, and see a Plinko animation triggered by the physical sorting event. The goal is to turn “correct bin” into something visible, rewarding, and competitive.
System Design
Dumpster Fire 3000 is split across four main components:
Laptop Orchestrator
The laptop runs the main vision and classification loop.
It uses:
- –OpenCV for camera capture
- –An EWMA lighting monitor to detect object drops
- –Google Gemini for structured item classification
- –A WebSocket client to send sorting commands to the Raspberry Pi
- –Optional HTTP ingest to send drop events to the backend
The orchestrator connects to the Pi over WebSockets and sends an execute_sort command after classification. It can also post the captured image and classification result to the backend through POST /internal/drops using a shared Bearer secret.
Raspberry Pi Sorter
The Raspberry Pi runs an async WebSocket server, usually on port 8765.
It exposes commands such as:
- –
get_distance - –
execute_sort
The Pi controls three hobby servos through an Adafruit PCA9685 I2C driver at address 0x40. Each label maps to a predefined servo choreography that physically redirects the item into the correct compartment.
The Pi daemon initializes safe default servo angles, listens for JSON-RPC-style messages, executes the correct motion, and returns status messages or errors to keep the laptop and hardware synchronized.
Backend
The backend is built with FastAPI and stores data in Postgres, hosted through Supabase.
It handles:
- –Authenticated user data
- –Drop ingestion from the physical device
- –Classification metadata
- –Leaderboard and score data
- –Plinko event routing
When a physical drop is ingested, the backend can estimate value again with Gemini and push a live drop event to the frontend through /ws/plinko.
Frontend
The frontend is a React + Vite single-page app.
Users can sign in with Auth0, view their sorting activity, and watch the Plinko animation respond to real physical drops. The frontend derives the Plinko WebSocket URL from the API base URL, so the same client can work across local development and deployment environments.
How We Built It
We built the first prototype with trash, cardboard, and a dream.
Since we could not 3D print parts, we used what we had: cardboard boxes, old trash bins, leftover screws, clamps, tape, and whatever hardware we could salvage. We first modeled the system in SolidWorks to understand the physical layout, then started constructing the mechanism from available materials.
We made holes by repeatedly stabbing cardboard with a pocket knife, mounted servos with improvised fasteners, and even used a screwdriver head as part of the mechanism when we did not have the right part. We tested the sorter with many real items, including the Chinese takeout container we had eaten from a few hours earlier.
On the electronics side, three servos connect to a 16-channel PCA9685 board, controlled from Python with adafruit-circuitpython-servokit. The Pi initializes safe default positions and serves a small shared protocol over WebSockets with message types such as:
- –
ready - –
get_distance - –
execute_sort - –
sort_result - –
error
The laptop orchestrator runs a Python loop that captures frames, detects drops, sends images to Gemini, parses the structured disposal label, and sends a sorting command to the Pi. For bench demos, the same code can run local servo test scripts instead of communicating with the Pi.
We also added environment variables so the system could run in different setups:
- –
WS_URL - –
GEMINI_API_KEY - –
PROXIMITY_POLL - –
DROP_API_URL
This made the code portable across the lab, the hackathon table, and CI with a mock Pi WebSocket.
For the web app, the React frontend communicates with the FastAPI backend, while Postgres stores users, drops, and leaderboard data. We used Alembic migrations for database changes and wrote pytest end-to-end tests that spin up a fake Pi and stub HTTP ingest, allowing us to test the full “classify → sort → notify web” path without carrying the hardware everywhere.
Challenges
The hardware was the hardest part.
Our first servos were underpowered, and we burned through multiple mini servos while trying to move the lid. That forced us to rethink the mechanism, reduce load on the motors, and test carefully so we did not keep destroying components.
The structure was also difficult because we did not have the normal tools or materials for a reliable mechanical build. The cardboard chassis flexed, causing the main ramp to sag. Instead of fighting that completely, we adapted the design into a drop-and-push mechanism. Since we did not have proper fasteners, we used a lot of masking tape, clamps, improvised supports, and scavenged parts.
We also ran into Raspberry Pi connectivity issues, wiring constraints, and the general chaos of debugging hardware and software at the same time.
On the software side, drop detection required a lot of tuning. The EWMA lighting trigger needed the right alpha, delta threshold, and hold time. If it was too sensitive, the system classified empty frames. If it was too conservative, it missed real drops.
We also had to debug across several moving pieces:
- –Pi WebSocket server
- –Laptop camera pipeline
- –Gemini classification
- –FastAPI backend
- –Auth0 frontend sessions
- –Bearer-token device ingest
- –Plinko WebSocket events
At first, we tried building a CNN trash classifier, but it was not accurate enough for the timeline. We switched to Google Gemini for vision classification because it gave us stronger results with structured JSON outputs. On the web side, we tried different database options before moving to Supabase Postgres, which gave us a clearer relational model for users, drops, and leaderboards.
Accomplishments
We are proud that Dumpster Fire 3000 worked end to end.
The system closes the full loop:
- –A user drops an item into the bin.
- –The laptop detects the drop with OpenCV.
- –Gemini classifies the item.
- –The laptop sends a sort command over WebSockets.
- –The Raspberry Pi executes servo motion.
- –The backend ingests the drop.
- –The frontend animates Plinko and updates the user experience.
We are especially proud that we built a documented and testable system under real hardware constraints. The project includes shared protocol types, mock-Pi end-to-end tests, deployment notes, and enough structure for someone else to reproduce the stack without guessing.
We also learned how much improvisation matters in robotics. Even with cardboard, tape, salvaged screws, and a screwdriver head, we were able to build a working physical system that connected vision, actuation, cloud infrastructure, and UI.
What We Learned
We learned that mechanical design matters just as much as software. If we used servos again, we would choose stronger motors earlier and design around torque requirements from the start.
We also learned that 3D printing would have made the mechanism much more repeatable. During the hackathon, we later realized other teams were using 3D printers, even though we thought they were not allowed. Next time, we would use printed mounts and guided chutes instead of relying on cardboard and tape.
On the software side, we learned how useful it is to split responsibilities across machines. Running vision and classification on the laptop while using the Raspberry Pi for actuation kept the hardware responsive and avoided forcing heavy ML workloads onto the Pi.
We also learned that LLM vision with a strict JSON contract can be a practical replacement for a brittle custom CNN on a short hackathon timeline, as long as parse failures and logging are handled carefully.
Most importantly, we learned that robotics projects are full of integration problems. The hardest part was not any single subsystem. It was getting the camera, classifier, Pi, servos, backend, database, authentication, and frontend to work together reliably.
What's Next
If we had more time, we would improve both sensing and mechanical reliability.
Future improvements include:
- –Adding ultrasonic or ToF sensing on the Pi for calibrated proximity detection
- –Replacing lighting-based drop detection with a more reliable sensor trigger
- –Adding mechanical dampening or gear reduction to reduce servo strain
- –3D-printing guided chutes, mounts, and repeatable servo brackets
- –Expanding end-to-end tests to include Auth0 and browser flows
- –Refining Plinko fairness and multi-user session behavior
- –Adding queueing for simultaneous drops
- –Exploring edge classification for lower latency and offline demos
Longer term, we would like to keep the same WebSocket contract while making the classifier swappable. That would let the Pi firmware and sorting protocol stay stable while experimenting with Gemini, local models, or edge inference.
Built With
- –Python
- –OpenCV
- –Google Gemini
- –Raspberry Pi
- –Adafruit PCA9685
- –Servos
- –FastAPI
- –React
- –Vite
- –Auth0
- –Postgres
- –Supabase
- –WebSockets
- –Alembic
- –Pytest
- –Cardboard
- –Clamps
- –Tape
- –Screwdrivers
- –Trash
- –Beer