💡 划重点

  • 主控选用ESP32,利用其Wi‑Fi与定时器资源,实现远程喂食与离线定时双保障。
  • 步进电机驱动螺旋送料机构,出粮精准不卡粮;舵机负责防潮挡板开合,双重密封。
  • 通过MQTT将每次喂食记录、余量告警、设备状态上报至手机,主人随时掌握喵星人饮食。
  • 硬件成本控制在90元以内,结构件可3D打印或使用食品级亚克力拼接,组装门槛低。

需求洞察

目标用户:多猫家庭、经常加班或短期出差的白领养猫人,以及对宠物健康数据有管理需求的年轻群体。

真实痛点

  1. 加班、堵车、周末外出无法准时投喂,猫咪暴饮暴食或长时间断粮易诱发肠胃、胰腺问题。
  2. 传统机械喂食器出粮量不准,干粮受潮变质,清理麻烦。
  3. 想远程知道“猫咪吃没吃、吃了多少”,但市面智能喂食器价格多在300‑500元,超出预算。

为什么值得做

将物联网与精确机电控制结合,用<90元实现基础智能喂食闭环。既能解决刚性看护需求,又为程序爱好者和学生提供实战项目,兼具情感价值与学习价值。方案开放可扩展,后期可加入摄像头、AI识别多猫分食等,生命周期长。

方案设计

整体分为四层,均围绕ESP32主控展开:

感知层

控制层

执行层

日志/联网层

物料清单

物料名称 数量 用途 估算单价(元) 小计(元)
ESP32‑WROOM‑32D开发板 1 主控,Wi‑Fi+蓝牙 18 18
28BYJ‑48步进电机+ULN2003驱动板 1 螺旋出粮动力 8 8
SG90微型舵机 1 出粮口挡板开合 5 5
槽型光电传感器 1 计数落粮颗粒 3 3
红外接近传感器模块 1 检测猫咪靠近 4 4
干簧管+小磁铁 1套 桶盖开关检测 2 2
5V/2A电源适配器+DC口母座 1 系统供电 10 10
储粮桶(3L密封米桶改造) 1 主体结构 12 12
螺旋杆+亚克力管(定做) 1套 送料通道 8 8
杜邦线、热缩管、螺丝、铜柱 若干 接线与固定 5 5
食品级硅胶软管(出粮口) 1段 导流 3 3
合计 78

合计78元,剩余12元用作结构打印或补充线材,满足90元内硬约束。所有物料可从电商平台单件包邮购得,无需批量采购。

接线与结构

接线说明(GPIO完全按给定微调)

微调理由:原给定引脚适用于步进和舵机,增加了3个传感器输入并选用闲置的ADC1通道,避免与Wi‑Fi共用的ADC2冲突,保证Wi‑Fi稳定。

结构装配

储粮桶底部打孔,垂直安装亚克力管作为螺旋套筒,步进电机通过联轴器与螺旋杆连接。出料口侧方开窗,前方固定舵机及半圆挡板。光电传感器横跨出料口,红外朝食盆方向安装。主控板与驱动板固定在桶外侧防水盒内。整个电路仅一根电源线外露,整洁安全。

核心代码

以下提供Arduino骨架,基于PlatformIO/Arduino IDE均可编译。已包含Wi‑Fi连接、MQTT、步进电机控制、舵机防潮、掉粮计数及定时喂食核心逻辑。


#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <EEPROM.h>

// 步进电机引脚
#define IN1 25
#define IN2 26
#define IN3 27
#define IN4 14
// 舵机
#define SERVO_PIN 13
// 传感器
#define PHOTO_PIN 32
#define IR_PIN 33
#define REED_PIN 34

// WiFi与MQTT
const char* ssid = "yourSSID";
const char* password = "yourPASS";
const char* mqtt_server = "broker.emqx.io";
WiFiClient espClient;

// 步进电机步序
const int step_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}
};

int step_phase = 0;
Ticker feedTicker;
bool feeding_flag = false;
int grain_count = 0;

// 舵机角度
void setDoor(bool open) {
  if(open) {
    // 打开挡板角度,需实测调整
    for(int angle=0; angle<=90; angle++) {
      int pulse = map(angle,0,180,500,2400);
      digitalWrite(SERVO_PIN,HIGH);
      delayMicroseconds(pulse);
      digitalWrite(SERVO_PIN,LOW);
      delay(20);
    }
  } else {
    for(int angle=90; angle>=0; angle--) {
      int pulse = map(angle,0,180,500,2400);
      digitalWrite(SERVO_PIN,HIGH);
      delayMicroseconds(pulse);
      digitalWrite(SERVO_PIN,LOW);
      delay(20);
    }
  }
}

// 步进电机转一圈(2048步)
void stepMotor(int rounds) {
  for(int r=0; r<rounds; r++) {
    for(int i=0; i<2048; i++) {
      for(int pin=0; pin<4; pin++) {
        digitalWrite(IN1+pin, step_seq[step_phase][pin]);
      }
      step_phase = (step_phase+1)%8;
      delay(2);
    }
  }
}

// 喂食执行
void executeFeeding(int gram) {
  feeding_flag = true;
  setDoor(true);
  // 每圈约出粮3g,根据实际校准
  int rounds = gram / 3;
  stepMotor(rounds);
  // 计数值清零,等待传感器新计数
  grain_count = 0;
  delay(500);
  setDoor(false);
  feeding_flag = false;
  // 上报MQTT
  String msg = "{\"event\":\"fed\",\"gram\":"+String(gram)+"}";
  client.publish("catfeeder/event", msg.c_str());
}

// 定时喂食回调
void onTimerFeed() {
  // 示例:默认早上8点、晚上20点各一次,每次出粮20g
  executeFeeding(20);
}

// MQTT回调处理远程指令
void callback(char* topic, byte* payload, unsigned int length) {
  String msg;
  for(int i=0;i<length;i++) msg += (char)payload[i];
  if(String(topic)=="catfeeder/cmd") {
    if(msg.indexOf("feed")>=0) {
      executeFeeding(20);
    } else if(msg.indexOf("stop")>=0) {
      // 紧急停止
      feeding_flag = false;
      setDoor(false);
    }
  }
}

void reconnect() {
  while(!client.connected()) {
    if(client.connect("ESP32CatFeeder")) {
      client.subscribe("catfeeder/cmd");
    } else {
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  // 引脚初始化
  pinMode(SERVO_PIN,OUTPUT);
  pinMode(IR_PIN,INPUT);

  WiFi.begin(ssid, password);
  while(WiFi.status()!=WL_CONNECTED) delay(500);
  client.setCallback(callback);

  // 设置定时喂食,每天8:00和20:00,需结合NTP实现,此处用Ticker模拟周期
  // 实际应使用ESP32 RTC定时器唤醒,这里简化演示
  feedTicker.attach(43200, onTimerFeed); // 12小时周期,仅演示
}

void loop() {
  if(!client.connected()) reconnect();
  client.loop();

  // 落粮计数
  if(digitalRead(PHOTO_PIN)==LOW && feeding_flag) {
    grain_count++;
    delay(20); // 消抖
  }
  // 红外检测猫咪靠近,可触发拍照或计数
  if(digitalRead(IR_PIN)==LOW) {
    // 可扩展
  }
  // 桶盖状态上报
  static bool last_reed = HIGH;
  bool now_reed = digitalRead(REED_PIN);
  if(last_reed != now_reed) {
    String status = now_reed?"closed":"open";
    client.publish("catfeeder/event", ("{\"lid\":\""+status+"\"}").c_str());
    last_reed = now_reed;
  }
}

调试步骤

  1. 电源检测:仅给ESP32供电,观察电源指示灯,串口打印Wi‑Fi连接成功标志,确保无短路。
  2. 电机空载测试:断开螺旋杆联轴,烧录代码,通过MQTT发送{"feed":1},观察步进电机是否按2048步/圈正转,是否可正反转校准。
  3. 舵机行程标定:手动修改代码中0‑90°对应脉冲,观察挡板能否完全遮闭出粮口且无卡阻,记录最佳角度。
  4. 传感器验证:遮蔽槽型光电,串口输出计数中断;手靠近红外,观察输出电平变化;打开桶盖,MQTT能收到lid:open消息。
  5. 出粮量校准:装满干粮,执行一次喂食20g指令,称量实际落粮克数,反算每圈克数,修改gram/3中的系数,重复3次取均值。
  6. 长时间运行:设置每日2次定时喂食,连续运行48小时,检查MQTT记录是否遗漏、电机是否丢步、结构是否松脱。

设计图

猫咪自动喂食器结构flow
1
感知输入(光电计数/红外/干簧管)
2
控制处理(ESP32 定时&MQTT)
3
执行反馈(步进电机出粮/舵机防潮)
4
数据上报(MQTT 喂食事件)

感知输入 --> 控制处理 --> 执行反馈

执行反馈 --> 感知输入 (计数反馈)

控制处理 --> 数据上报