DIY IoT สำหรับบ้านเลี้ยงแมว: ทำฝาอาหารล็อกได้ด้วย Servo บน ESP8266

ใครเป็นทาสแมวแล้วเจอปัญหาแบบนี้บ้าง? ลืมเก็บชามอาหารแมวก่อนนอน! โปรเจกต์นี้เกิดมาจากคุณ Becky Stern ที่ต้องการควบคุมเวลาการกินของ "Chaz" แมวแก่ที่ป่วยเป็นเบาหวาน น้องจำเป็นต้องกินอาหารเช้าให้ตรงเวลาก่อนฉีดอินซูลิน แต่ถ้าปล่อยอาหารทิ้งไว้ข้ามคืน น้องจะกินจนอิ่มและไม่ยอมกินมื้อเช้า

ไอเดียนี้เลยเกิดขึ้นมาเพื่อตอบโจทย์สถานการณ์นี้ครับ เราจะมาทำ "ฝาครอบชามอาหารแมวอัตโนมัติ" โดยใช้บอร์ด NodeMCU ESP8266 และ Servo Motor ควบคุมการเปิด-ปิดฝาในช่วงเที่ยงคืนถึง 7:30 น. โดยอิงเวลาจริงจากเซิร์ฟเวอร์ (NTP) บอกเลยว่าสาย DIY ห้ามพลาด!

📌 ข้อแนะนำ: โปรเจกต์นี้เหมาะกับแมวแก่หรือแมวที่ไม่ค่อยซนนะครับ ถ้าเป็นแมววัยรุ่นพลังล้นเหลือ น้องอาจจะพยายามงัดฝาเปิดเองได้

🛠️ อุปกรณ์ที่ต้องใช้ (Supplies)

  • เครื่องพิมพ์ 3 มิติ (3D printer) และเส้นพลาสติก (ผู้เขียนใช้สีทอง PLA)
  • บอร์ดไมโครคอนโทรลเลอร์ NodeMCU ESP8266
  • สาย USB (A to microB) และ อะแดปเตอร์จ่ายไฟ USB
  • Micro Servo Motor
  • ไขควงขนาดเล็ก และ น็อต
  • สายไฟ Hookup wire และ Header pins
  • แผงวงจร Perma-proto board

🚀 ขั้นตอนการทำ (Step-by-Step)

ขั้นตอนที่ 1: พิมพ์ชิ้นส่วน 3D (3D Printed Parts)

ฐานใส่ชามอาหารดัดแปลงมาจากดีไซน์ของ Ardy Lai บน Thingiverse โดยปรับขนาดให้พอดีกับชามแมว และเพิ่มช่องสำหรับยึด Micro Servo Motor พร้อมรูร้อยสายไฟ ส่วนตัวฝาปิด (Lid) ออกแบบง่ายๆ ผ่าน Tinkercad เพื่อให้ยึดกับแกนหมุนของ Servo ได้พอดี

3D Printed Base 3D Printed Lid

ดาวน์โหลดไฟล์ 3D ได้ที่นี่:
- Cat_Food_Bowl_Holder.stl (Shopify CDN)
- เอกสาร PDF เพิ่มเติม

ขั้นตอนที่ 2: ประกอบฝาเข้ากับมอเตอร์ (Attach Lid to Servo)

ใช้สว่านดอกเล็กขยายรูบนหัวแกน Servo (Servo Horn) เล็กน้อย จากนั้นใช้น็อตยึดเข้ากับฝาปิดที่พิมพ์ 3D ไว้ให้แน่นหนา

Attach Lid 1 Attach Lid 2

ขั้นตอนที่ 3: ต่อวงจร NodeMCU ESP8266

เพื่อให้ถอดประกอบง่าย แนะนำให้บัดกรี Header pins ลงบน Perma-proto board การต่อสายไฟมีแค่ 3 เส้นหลักๆ ดังนี้ครับ:

  • 🟡 สายสีเหลือง (Signal): ต่อเข้าขา D1 ของ NodeMCU
  • 🔴 สายสีแดง (Power): ต่อเข้าขา 3V3 หรือ VIN
  • สายสีดำ (Ground): ต่อเข้าขา GND
Circuit Wiring

ขั้นตอนที่ 4: อัปโหลดโค้ด Arduino

ประกอบมอเตอร์เข้ากับฐาน เสียบสายเชื่อมต่อเข้าบอร์ด แล้วต่อ USB เข้าคอมพิวเตอร์ โค้ดนี้จะใช้ NTP ดึงเวลาปัจจุบันจากอินเทอร์เน็ต เพื่อสั่งเปิด-ปิดฝาตามตารางที่ตั้งไว้ (อย่าลืมแก้ชื่อ WiFi กับ Password ในโค้ดด้วยนะ)


#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>

ESP8266WiFiMulti wifiMulti;
WiFiUDP UDP;

IPAddress timeServerIP;
const char* NTPServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;
byte NTPBuffer[NTP_PACKET_SIZE];

Servo myservo;
int pos = 0;

void setup() {
  myservo.attach(5);  // D1

  Serial.println("opening the lid");
  for (pos = 95; pos >= 0; pos -= 1) {
    myservo.write(pos);
    delay(15);
  }
    
  Serial.begin(115200);
  delay(10);
  Serial.println("\r\n");

  startWiFi();
  startUDP();

  if(!WiFi.hostByName(NTPServerName, timeServerIP)) {
    Serial.println("DNS lookup failed. Rebooting.");
    Serial.flush();
    ESP.reset();
  }
  sendNTPpacket(timeServerIP);  
}

unsigned long intervalNTP = 60000;
unsigned long prevNTP = 0;
unsigned long lastNTPResponse = millis();
uint32_t timeUNIX = 0;
unsigned long prevActualTime = 0;

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - prevNTP > intervalNTP) {
    prevNTP = currentMillis;
    sendNTPpacket(timeServerIP);
  }

  uint32_t time = getTime();
  if (time) {
    timeUNIX = time;
    lastNTPResponse = currentMillis;
  } else if ((currentMillis - lastNTPResponse) > 3600000) {
    ESP.reset();
  }

  uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse)/1000;
  uint32_t easternTime = timeUNIX - 18000 + (currentMillis - lastNTPResponse)/1000;
  
  if (actualTime != prevActualTime && timeUNIX != 0) {
    prevActualTime = actualTime;
  } 

  // 7:30am Open
  if(getHours(easternTime) == 7 && getMinutes(easternTime) == 30 && getSeconds(easternTime) == 0){
    for (pos = 95; pos >= 0; pos -= 1) {
      myservo.write(pos);
      delay(15);
    }    
  }

  // Midnight Close
  if(getHours(easternTime) == 0 && getMinutes(easternTime) == 0 && getSeconds(easternTime) == 0){
    for (pos = 0; pos <= 95; pos += 1) {
      myservo.write(pos);
      delay(15);
    }    
  }   
}

void startWiFi() {
  // แก้ไข SSID และ Password ตรงนี้
  wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   

  Serial.println("Connecting");
  while (wifiMulti.run() != WL_CONNECTED) {
    delay(250);
    Serial.print('.');
  }
}

void startUDP() {
  UDP.begin(123);
}

uint32_t getTime() {
  if (UDP.parsePacket() == 0) { return 0; }
  UDP.read(NTPBuffer, NTP_PACKET_SIZE);
  uint32_t NTPTime = (NTPBuffer[40] << 24) | (NTPBuffer[41] << 16) | (NTPBuffer[42] << 8) | NTPBuffer[43];
  const uint32_t seventyYears = 2208988800UL;
  uint32_t UNIXTime = NTPTime - seventyYears;
  return UNIXTime;
}

void sendNTPpacket(IPAddress& address) {
  memset(NTPBuffer, 0, NTP_PACKET_SIZE);
  NTPBuffer[0] = 0b11100011;
  UDP.beginPacket(address, 123);
  UDP.write(NTPBuffer, NTP_PACKET_SIZE);
  UDP.endPacket();
}

inline int getSeconds(uint32_t UNIXTime) { return UNIXTime % 60; }
inline int getMinutes(uint32_t UNIXTime) { return UNIXTime / 60 % 60; }
inline int getHours(uint32_t UNIXTime) { return UNIXTime / 3600 % 24; }
    

ขั้นตอนที่ 5: เริ่มใช้งานจริงได้เลย!

จัดสายไฟเก็บเข้าในช่องฐานให้เรียบร้อย เสียบปลั๊กจ่ายไฟให้ระบบ โปรแกรมถูกเขียนมาให้เริ่มต้นด้วยสถานะ "เปิดฝา" ก่อนเสมอ และจะเปลี่ยนสถานะก็ต่อเมื่อถึงเวลาที่ตั้งไว้ในโค้ด (เที่ยงคืนปิด, 7 โมงครึ่งเปิด)

Use it 1 Use it 2

สนใจอุปกรณ์ IoT หรือพูดคุยแลกเปลี่ยนไอเดีย?

คำเตือน: เนื้อหานี้เป็นการสรุปและเรียบเรียงจากบทความต้นฉบับภาษาอังกฤษ ข้อมูลฉบับภาษาไทยอาจมีความคลาดเคลื่อนบางประการจากการตีความหรือย่อเนื้อหา

อ้างอิง: บทความนี้แปลและเรียบเรียงโดย Globalbyteshop Blog
ต้นฉบับโดย Becky Stern จาก Instructables: Cat Food Bowl Access Control (ESP8266 + Servo Motor + 3D Printing)

แท็ก


Blog posts

© 2026 บริษัท โกลบอลโทรนิค อินเตอร์เทรด จํากัด, ขับเคลื่อนโดย Shopify

    • PayPal

    เข้าสู่ระบบ

    ลืมรหัสผ่านใช่ไหม?

    ยังไม่มีบัญชีใช่ไหม?
    สร้างบัญชี