This is the project I built because the commercial cat feeder I bought stopped working after a year. The hardware inside it: a $5 stepper, a $2 driver, a $4 microcontroller, plastic. The same hardware open-sourced is reliable for years because you can fix it. Stepper-driven feeders are also more accurate than the servo-flap versions; you tell it "turn 360°", you get the same portion every time.
How it works
I2C] -->|time| ESP32 ESP32[[ESP32]] --> Sched{Schedule
match?} Sched -->|yes| Driver[A4988 stepper driver] Driver --> Stepper[NEMA17 stepper
200 steps/rev] Stepper --> Auger[Auger inside hopper] Auger --> Bowl[Cat bowl] Web[Phone] -->|HTTP /feed-now| ESP32 Sched -->|publish| MQTT[Optional MQTT log]
The schedule lives in flash. Each scheduled time, the ESP32 spins the stepper one full revolution, dispensing roughly one tablespoon of food.
Bill of materials
- ESP32 dev board — $7
- NEMA17 stepper motor (1.8°, 1.7A) — $10
- A4988 or DRV8825 stepper driver — $3
- DS3231 RTC + battery — $3
- 12V / 2A power supply — $6
- 3D-printed hopper + auger (or repurpose a coffee jar with a 3D-printed dispenser) — $5
- Project box, wires, jumpers — $5
Total around $39. The 3D-printed parts are the variable — Thingiverse has multiple feeder designs ready to print, or you can buy one for ~$15 from suppliers.
Wiring
A4988 ESP32 / Stepper / 12V
VMOT --- 12V supply (+)
GND --- 12V GND (and ESP32 GND, common)
VDD --- 3.3V from ESP32
GND --- GND
STEP --- GPIO 26
DIR --- GPIO 27
EN --- GPIO 25 (active LOW)
MS1/2/3 - configure microstepping (all LOW = full step)
A1, A2 -- coil A of stepper
B1, B2 -- coil B of stepper
DS3231 ESP32
SDA --- GPIO 21
SCL --- GPIO 22
VCC --- 3.3V
GND --- GNDThe stepper driver needs a small heatsink and a 100 µF cap close to VMOT. Without these, the chip can overheat or brown out the stepper.
Firmware design
The main loop checks the RTC time every second. When the current time matches a scheduled feed time, it enables the stepper, drives 200 steps (one full revolution), and disables. Disabling matters — leaving the stepper energized between feeds wastes 1A continuously and heats up the driver.
The web UI shows the next feed time and has a "feed now" button. Pressing it queues an extra feed for the next loop iteration. The UI also lets you edit the daily schedule, persisted to NVS.
Calibration
Different food sizes (kibble vs pellets) feed differently. After building, run a few rotations and weigh the output. If 1 rotation gives 8 g and you want 10 g per meal, set steps_per_feed = 250. The firmware exposes this as a config parameter, no recompile needed.
Key code: main loop
This is the heart of the firmware, taken from the working sketch. The complete file (with config template, library list, and the rest of the helpers) is around 80 lines and is included in the downloadable project package — request it via the form below.
void loop() {
DateTime now = rtc.now();
// Scheduled feed: match exactly within current minute, only once per minute
for (int i = 0; i < N_SLOTS; i++) {
if (now.hour() == schedule[i].hour && now.minute() == schedule[i].minute) {
if (lastFedHour != now.hour() || lastFedMin != now.minute()) {
lastFedHour = now.hour(); lastFedMin = now.minute();
doFeed(1);
}
}
}
if (feedRequested) {
feedRequested = false;
doFeed(1);
}
delay(1000);
}Get the complete project package
The article above shows the core firmware and the principles behind it. The complete project package — assembled, tested, and ready to flash — is available by email request. We send it manually, and we read every request.
- Complete Arduino sketch (.ino) with full error handling
- List of required libraries with version numbers
- Printable wiring diagram (PDF)
- Bill of materials with current part numbers
- Build guide and troubleshooting tips
- Configuration template (WiFi, MQTT, etc.)
Share your thoughts
Worked with this in production and have a story to share, or disagree with a tradeoff? Email us at support@mybytenest.com — we read everything.