Máy cho vật nuôi ăn tự động theo lịch qua IoT
Trung cấp1/8/2026- Tác giả: IoTlabs Maker

Máy cho vật nuôi ăn tự động theo lịch qua IoT

Xây dựng máy cho vật nuôi ăn tự động dùng ESP32 + servo SG90 làm cơ cấu xả thức ăn, kết hợp module RTC DS3231 để giữ lịch cho ăn chính xác theo giờ ngay cả khi mất WiFi.

esp32servortc-ds3231chan-nuoismart-farmtu-dong-hoaiot

Xây dựng máy cho vật nuôi ăn tự động dùng ESP32 + servo SG90 làm cơ cấu xả thức ăn, kết hợp module RTC DS3231 để giữ lịch cho ăn chính xác theo giờ ngay cả khi mất WiFi.

Hướng dẫn chi tiết

ESP32 + servo SG90 + RTC DS3231 tạo máy cho ăn tự động theo lịch cố định, giữ đúng giờ ngay cả khi mất WiFi nhờ đồng hồ thời gian thực có pin dự phòng.

1. Giới thiệu

Cho vật nuôi ăn đúng giờ mỗi ngày là việc lặp lại nhàm chán nhưng lại rất quan trọng, đặc biệt khi chủ đi vắng hoặc nuôi số lượng lớn. Dự án này dùng ESP32 điều khiển servo SG90 làm cơ cấu xả thức ăn (quay cửa phiễu để thức ăn rơi xuống theo trọng lực) kết hợp với module đồng hồ thời gian thực DS3231 (RTC) để giữ lịch cho ăn chính xác theo giờ ngay cả khi ESP32 mất kết nối WiFi hoặc bị mất điện tạm thời — DS3231 có pin CR2032 dự phòng nên vẫn giữ đúng giờ.

Ưu điểm của việc dùng RTC thay vì chỉ dựa vào NTP qua WiFi: hệ thống vẫn cho ăn đúng lịch dù mất mạng, phù hợp với môi trường trang trại/chuồng trại có kết nối WiFi không ổn định.

2. Linh kiện cần có

Linh kiệnSố lượngGiá tham khảo
ESP32 DevKit V1 (30 chân)1~90.000 - 120.000đ
SG90 – Servo Motor Mini 9g1~25.000 - 35.000đ
DS3231 Real-Time Clock Module (kèm pin CR2032)1~25.000 - 40.000đ
Phễu/hộp đựng thức ăn + cơ cấu cửa xả gắn servo (tự chế hoặc in 3D)1 bộtuỳ vật liệu
Dây jumper, nguồn 5V/USB cho ESP321 bộ~20.000 - 30.000đ

3. Sơ đồ kết nối

Servo SG90ESP32
VCC (đỏ)VIN (5V)
GND (nâu)GND
Signal (vàng)GPIO13
DS3231 RTCESP32
VCC3V3
GNDGND
SCLGPIO22 (I2C_SCL)
SDAGPIO21 (I2C_SDA)

Lưu ý: servo SG90 có dòng khởi động (stall current) khoảng 500-700mA, phải cấp nguồn VCC từ chân VIN (5V) của ESP32 chứ không dùng 3V3, tránh sụt áp làm ESP32 tự reset khi servo bắt đầu quay. DS3231 dùng bus I2C nên chỉ cần 2 dây tín hiệu SCL/SDA, dùng đúng cặp chân I2C mặc định của ESP32 (GPIO22/GPIO21) để không phải cấu hình lại Wire.

4. Code ví dụ #1 – Kiểm tra DS3231 và đọc giờ hiện tại qua Serial

#include <Wire.h>
#include <RTClib.h>

RTC_DS3231 rtc;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22); // SDA, SCL

  if (!rtc.begin()) {
    Serial.println("Khong tim thay DS3231!");
    while (1) delay(1000);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC mat gio, dat lai theo thoi gian compile...");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
  DateTime now = rtc.now();
  Serial.printf("%02d:%02d:%02d %02d/%02d/%04d\n",
                now.hour(), now.minute(), now.second(),
                now.day(), now.month(), now.year());
  delay(1000);
}

5. Code ví dụ #2 – Điều khiển servo xả thức ăn thủ công qua lệnh Serial

#include <ESP32Servo.h>

#define SERVO_PIN 13
Servo feederServo;

void setup() {
  Serial.begin(115200);
  ESP32PWM::allocateTimer(0);
  feederServo.setPeriodHertz(50);
  feederServo.attach(SERVO_PIN, 500, 2400);
  feederServo.write(0); // vi tri dong
  Serial.println("Go 'feed' de xa thuc an thu cong");
}

void loop() {
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();
    if (cmd == "feed") {
      feederServo.write(90);  // mo cua
      delay(1200);
      feederServo.write(0);   // dong cua
      Serial.println("Da xa thuc an!");
    }
  }
}

6. Code ví dụ #3 – Ứng dụng thực tế: máy cho ăn tự động theo lịch RTC

/*
  May cho vat nuoi an tu dong theo lich qua IoT
  Board: ESP32 DevKit V1 (30 pins)
  Co cau chap hanh: Servo SG90 (co cau xa thuc an - quay cua phieu)
  Dong ho thoi gian thuc: DS3231 RTC module (I2C) - giu lich cho an ngay ca khi mat WiFi

  Wiring (khop voi diagram tren IoTLabs Maker):
    Servo SG90  SIGNAL -> GPIO13     VCC -> VIN(5V)   GND -> GND
    DS3231      SDA -> GPIO21 (I2C_SDA)   SCL -> GPIO22 (I2C_SCL)
                VCC -> 3V3   GND -> GND

  Hanh vi:
    - Doc RTC moi giay, so sanh voi bang lich cho an (gio:phut co dinh)
    - Khi khop 1 muc lich va chua chay trong phut do -> quay servo xa thuc an (mo -> dong)
    - Neu RTC mat lien lac (I2C loi) -> bao "rtc_error", khong doan lich, cho retry
*/

#include <Wire.h>
#include <RTClib.h>
#include <ESP32Servo.h>

#define SERVO_PIN 13

Servo feederServo;
RTC_DS3231 rtc;

bool rtcOk = false;
unsigned long lastCheck = 0;
const unsigned long CHECK_INTERVAL_MS = 1000;

// Lich cho an co dinh: {gio, phut}. Them/bot theo nhu cau thuc te.
struct FeedSlot { uint8_t hour; uint8_t minute; bool firedToday; };
FeedSlot feedSlots[] = {
  {7, 0, false},
  {12, 0, false},
  {18, 0, false},
};
const int FEED_SLOT_COUNT = sizeof(feedSlots) / sizeof(feedSlots[0]);
int lastResetDay = -1;

const int SERVO_CLOSED_ANGLE = 0;
const int SERVO_OPEN_ANGLE   = 90;
const unsigned long DISPENSE_OPEN_MS = 1200; // thoi gian mo cua de thuc an roi xuong

void dispenseFood() {
  Serial.println(F("{\"event\":\"dispense_start\"}"));
  feederServo.write(SERVO_OPEN_ANGLE);
  delay(DISPENSE_OPEN_MS);
  feederServo.write(SERVO_CLOSED_ANGLE);
  Serial.println(F("{\"event\":\"dispense_done\"}"));
}

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.println();
  Serial.println(F("=== May cho an tu dong IoTLabs - Boot OK ==="));

  ESP32PWM::allocateTimer(0);
  feederServo.setPeriodHertz(50);
  feederServo.attach(SERVO_PIN, 500, 2400);
  feederServo.write(SERVO_CLOSED_ANGLE);

  Wire.begin(21, 22);
  rtcOk = rtc.begin();
  if (!rtcOk) {
    Serial.println(F("{\"status\":\"rtc_error\",\"note\":\"khong tim thay DS3231, kiem tra day I2C\"}"));
  } else if (rtc.lostPower()) {
    // Lan dau cap nguon / het pin CR2032 -> set tam theo thoi gian compile,
    // nguoi dung nen chinh lai qua NTP/app that khi co WiFi.
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    Serial.println(F("{\"status\":\"rtc_time_reset\"}"));
  }

  Serial.print(F("Lich cho an: "));
  for (int i = 0; i < FEED_SLOT_COUNT; i++) {
    Serial.print(feedSlots[i].hour);
    Serial.print(':');
    Serial.print(feedSlots[i].minute);
    Serial.print(F("  "));
  }
  Serial.println();
}

void loop() {
  unsigned long now = millis();
  if (now - lastCheck < CHECK_INTERVAL_MS) {
    return;
  }
  lastCheck = now;

  if (!rtcOk) {
    // Retry dinh ky thay vi while() vo han - cho phep he thong tiep tuc bao cao trang thai
    rtcOk = rtc.begin();
    Serial.println(F("{\"status\":\"rtc_error\",\"retrying\":true}"));
    return;
  }

  DateTime nowDt = rtc.now();

  if (nowDt.day() != lastResetDay) {
    for (int i = 0; i < FEED_SLOT_COUNT; i++) {
      feedSlots[i].firedToday = false;
    }
    lastResetDay = nowDt.day();
  }

  for (int i = 0; i < FEED_SLOT_COUNT; i++) {
    if (!feedSlots[i].firedToday &&
        nowDt.hour() == feedSlots[i].hour &&
        nowDt.minute() == feedSlots[i].minute) {
      feedSlots[i].firedToday = true;
      dispenseFood();
    }
  }

  Serial.print(F("{\"time\":\""));
  if (nowDt.hour() < 10) Serial.print('0');
  Serial.print(nowDt.hour());
  Serial.print(':');
  if (nowDt.minute() < 10) Serial.print('0');
  Serial.print(nowDt.minute());
  Serial.print(':');
  if (nowDt.second() < 10) Serial.print('0');
  Serial.print(nowDt.second());
  Serial.println(F("\",\"status\":\"ok\"}"));
}

7. Lỗi thường gặp

LỗiNguyên nhânCách sửa
ESP32 tự reset khi servo bắt đầu quaySụt áp do dòng khởi động servo kéo qua nguồn USB yếu, hoặc cấp VCC servo từ 3V3Cấp servo từ chân VIN (5V), dùng nguồn 5V/1A+ riêng nếu cần
rtc.begin() luôn trả về falseSai chân SDA/SCL trong Wire.begin(), hoặc dây I2C lỏng/đứtKiểm tra Wire.begin(21, 22) đúng thứ tự (SDA, SCL) khớp với dây nối GPIO21/GPIO22
Máy cho ăn 2 lần liên tiếp trong cùng 1 phút lịchThiếu cờ firedToday hoặc reset cờ sai thời điểmDùng mảng firedToday reset mỗi ngày mới như code ví dụ #3, không reset theo phút
Sau khi mất điện, giờ RTC bị sai hoàn toànHết pin CR2032 dự phòng trên module DS3231Thay pin CR2032 mới; kiểm tra rtc.lostPower() để phát hiện tình trạng này

8. Tổng kết

Máy cho vật nuôi ăn tự động này giải quyết bài toán cho ăn đúng giờ mà không cần người trực, đặc biệt hữu ích khi đi vắng dài ngày. Việc dùng RTC DS3231 thay vì chỉ dựa vào NTP qua WiFi giúp hệ thống vẫn hoạt động chính xác dù mất kết nối mạng. Có thể mở rộng thêm bằng cách thêm cảm biến trọng lượng (load cell) để xác nhận thức ăn đã rơi đủ, hoặc gửi thông báo qua Telegram/MQTT mỗi khi cho ăn thành công để chủ nuôi theo dõi từ xa.