💡 划重点
- 主控用 ESP32,兼顾定时、WiFi 与 MQTT 远程控制。
- 执行层采用 28BYJ-48 步进电机驱动螺旋出粮,SG90 舵机做防卡拨片。
- 支持本地定时出粮,也支持 MQTT 下发手动加餐指令。
- 整机物料估算 85 元,控制在 90 元目标内。
- 结构以料斗、螺旋轴、出粮口、接粮碗为核心,适合家庭宠物场景。
需求洞察
目标用户是白天上班、偶尔加班或短途出行的养猫家庭。真实痛点不是“完全没人喂”,而是喂食时间不稳定:早上匆忙忘记加粮,晚上回家过晚,猫因饥饿频繁叫唤,甚至一次吃太多导致呕吐。市售自动喂食器动辄两三百元,功能复杂但核心需求其实很集中:按时出粮、份量可控、手机能补喂、断电后不撒粮。
这个项目值得做,是因为它把“定时”和“远程补喂”两个高频需求做轻量化。ESP32 自带 WiFi,MQTT 协议开销小,家庭路由器下即可稳定使用;步进电机比普通直流电机更适合定量出粮,转固定步数对应固定螺旋圈数,份量更容易复现。成本压到 90 元内,适合作为硬件入门到家居实用的完整项目。
方案设计
感知层:红外光电传感器安装在出粮口下方,用于检测是否有粮通过或是否堵塞;保留一个可选的轻触按键,用于手动出粮和配网复位。感知层不追求复杂称重,先解决“有没有出粮”和“是否卡粮”的基础判断。
控制层:ESP32 负责定时任务、MQTT 消息解析、步进电机脉冲输出和舵机角度控制。定时采用 millis() 维护出粮间隔,后续可接入 NTP 做每日固定时刻;MQTT 主题分为 catfeeder/cmd 和 catfeeder/status,手机端或 Home Assistant 可订阅状态。
执行层:28BYJ-48 步进电机通过 ULN2003 驱动板带动螺旋轴,转固定步数完成一份出粮;SG90 舵机安装在料斗内侧,每轮出粮前后拨动一次,降低猫粮架空和卡粮概率。步进负责“量”,舵机负责“顺”。
日志/联网层:ESP32 连接家庭 WiFi,通过 MQTT 上报在线状态、出粮完成、堵塞告警等短消息;串口同时输出调试日志。断网时本地定时仍可运行,恢复后自动重连,不把核心喂食能力绑死在云端。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 小计 |
|---|---|---|---|---|
| ESP32 开发板 | 1 | 主控、WiFi、MQTT | 25 元 | 25 元 |
| 28BYJ-48 步进电机 + ULN2003 | 1 | 螺旋轴定量出粮 | 13 元 | 13 元 |
| SG90 舵机 | 1 | 防卡拨片 | 7 元 | 7 元 |
| 5V 2A 电源 | 1 | 电机与舵机供电 | 15 元 | 15 元 |
| 红外光电传感器 | 1 | 出粮检测/堵塞判断 | 3 元 | 3 元 |
| 杜邦线、端子、热缩管 | 1 套 | 接线与绝缘 | 6 元 | 6 元 |
| 亚克力/3D 打印结构件 | 1 套 | 料斗、支架、出粮口 | 12 元 | 12 元 |
| 螺丝、扎带 | 1 套 | 固定与装配 | 4 元 | 4 元 |
| 合计 | 85 元 |
接线与结构
步进驱动 IN1—IN4 接 ESP32 的 GPIO25、GPIO26、GPIO27、GPIO14;ULN2003 的 VCC 接 5V,GND 与 ESP32 共地。SG90 信号线接 GPIO13,电源接 5V 2A,地与主控共地。红外传感器输出接 GPIO34,仅作输入检测;按键可接 GPIO32 到 GND,使用内部上拉。MQTT 与 WiFi 均使用 ESP32 内置无线功能,无需额外接线。
这里保留给定接线,仅增加红外与按键。GPIO13 驱动舵机不占用步进四相;GPIO14 在启动瞬间可能有短暂电平变化,但 ULN2003 输入阻抗较高,实际不影响。建议舵机与步进共用 5V 电源时加 470μF 电容,避免同时动作造成 ESP32 复位。结构上,料斗底部接螺旋套管,步进电机固定在套管一端,出粮口朝下并对准接粮碗;舵机拨片位于料斗下料口附近,每轮转动约 45° 后复位。
核心代码
#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
const char* SSID = "你的WiFi";
const char* PASS = "你的密码";
const char* MQTT_HOST = "broker.emqx.io";
const uint8_t IN[4] = {25, 26, 27, 14};
const uint8_t SERVO_PIN = 13;
const uint8_t IR_PIN = 34;
WiFiClient espClient;
PubSubClient mqtt(espClient);
Servo gate;
bool feedReq = false;
unsigned long lastFeed = 0;
const unsigned long INTERVAL = 6UL * 60UL * 60UL * 1000UL;
const uint8_t seq[8][4] = {
{1,0,0,0},{1,1,0,0},{0,1,0,0},{0,1,1,0},
{0,0,1,0},{0,0,1,1},{0,0,0,1},{1,0,0,1}
};
void stepMotor(int steps) {
for (int i = 0; i < steps; i++) {
for (int s = 0; s < 8; s++) {
for (int p = 0; p < 4; p++) digitalWrite(IN[p], seq[s][p]);
delayMicroseconds(1600);
}
}
}
void feed() {
gate.write(35);
delay(300);
stepMotor(2048);
gate.write(90);
delay(300);
mqtt.publish("catfeeder/status", "fed");
Serial.println("出粮完成");
}
void callback(char* topic, byte* payload, unsigned int len) {
if (String(topic) == "catfeeder/cmd" && len > 0 && payload[0] == '1') feedReq = true;
}
void connectMQTT() {
while (!mqtt.connected()) {
if (mqtt.connect("esp32-cat-feeder")) {
mqtt.subscribe("catfeeder/cmd");
mqtt.publish("catfeeder/status", "online");
} else delay(2000);
}
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < 4; i++) pinMode(IN[i], OUTPUT);
pinMode(IR_PIN, INPUT);
gate.attach(SERVO_PIN);
gate.write(90);
WiFi.begin(SSID, PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
mqtt.setCallback(callback);
connectMQTT();
lastFeed = millis();
}
void loop() {
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
if (feedReq) { feedReq = false; feed(); lastFeed = millis(); }
if (millis() - lastFeed >= INTERVAL) { feed(); lastFeed = millis(); }
delay(10);
}
调试步骤
- 先只接 ESP32 与 ULN2003,烧录代码,观察步进电机是否按固定方向转动;若反向,调换 IN1/IN3 或 IN2/IN4。
- 空载测试螺旋轴,确认 2048 步对应一份粮,记录实际克数,再调整步数。
- 接舵机并测试 35°—90° 拨动,确认不会顶住料斗内壁;舵机抖动时先检查 5V 电源和共地。
- 接入红外传感器,遮挡出粮口观察串口状态,设置堵塞告警阈值。
- 配置 WiFi 与 MQTT,向
catfeeder/cmd发送1,确认手动出粮与状态上报正常。 - 装粮连续运行 3 天,重点观察夜间自动出粮、断网重连和料斗架空情况。