Mari kita rancang dan buat alat penetas telur ayam otomatis menggunakan Arduino dengan fitur lengkap. Proyek ini akan menjadi tantangan yang menarik dan sangat fungsional.
Alat Penetas Telur Ayam Otomatis dengan Arduino (Fitur Lengkap)
Alat penetas telur ini akan fokus pada pengaturan dan pemeliharaan kondisi lingkungan yang optimal untuk penetasan telur ayam, yaitu suhu, kelembaban, dan pemutaran telur.
Fitur Utama:
Kontrol Suhu Akurat: Mempertahankan suhu ideal menggunakan sensor LM35 dan pemanas, dengan kontrol PID dasar.
Kontrol Kelembaban Otomatis: Mengatur kelembaban menggunakan sensor DHT11/DHT22 dan pelembab (mist maker/kipas + air).
Pemutaran Telur Otomatis: Menggerakkan rak telur pada interval waktu tertentu menggunakan servo motor.
Antarmuka LCD 16x2 I2C: Menampilkan suhu, kelembaban, status perangkat, hitungan mundur pemutaran, dan hari inkubasi.
Tombol Kontrol:
Mode: Mengganti mode tampilan atau mode pengaturan (suhu, kelembaban, interval pemutaran).
Naik/Turun: Mengatur nilai target suhu/kelembaban/interval pemutaran.
Reset: Mengatur ulang hitungan hari inkubasi atau pengaturan ke default.
Peringatan Alarm: Menggunakan LED dan Buzzer untuk suhu/kelembaban di luar batas atau kegagalan sensor.
Penyimpanan Pengaturan: Menyimpan nilai target suhu, kelembaban, dan interval pemutaran ke EEPROM agar tidak hilang saat mati listrik.
Komponen yang Dibutuhkan:
Arduino Board (Arduino Uno atau Mega direkomendasikan karena jumlah pin)
Sensor Suhu LM35 (untuk suhu utama)
Sensor Suhu & Kelembaban DHT11 atau DHT22 (untuk kelembaban dan suhu sekunder/verifikasi)
LCD 16x2 dengan Modul I2C
Modul Relay 1-Channel (2 buah): Untuk mengontrol pemanas dan pelembab.
Servo Motor: Untuk memutar rak telur.
Pemanas: Lampu pijar (misalnya 40W-100W) atau elemen pemanas keramik/filamen.
Pelembab:
Ultrasonic Mist Maker (Fogger): Lebih direkomendasikan untuk kelembaban tinggi.
Kipas Kecil + Wadah Air: Alternatif sederhana, kurang presisi.
2x LED (misalnya, hijau untuk OK, merah untuk alarm)
2x Resistor 220 Ohm (untuk LED)
1x Buzzer Piezo
5x Tombol Tekan (Push Button): Mode, Naik, Turun, Reset, Manual Rotate (opsional)
5x Resistor Pull-down (sekitar 10k ohm)
Kotak Penetas: Wadah kedap udara (misalnya, kotak styrofoam atau akrilik) dengan ventilasi terkontrol.
Rak Pemutar Telur: Mekanisme rak yang dapat digerakkan oleh servo.
Power Supply Eksternal: Untuk pemanas dan mungkin Arduino/relay/mist maker jika daya dari USB tidak cukup.
Skema Pengkabelan (Ringkasan):
LCD 16x2 I2C ke Arduino:
SDA ke A4
SCL ke A5
VCC ke 5V
GND ke GND
Sensor Suhu LM35 ke Arduino:
Vcc ke 5V
Vout ke A0
GND ke GND
Sensor DHT11/DHT22 ke Arduino:
VCC ke 5V
DATA ke Digital Pin 13 (dengan resistor pull-up 10k Ohm antara DATA dan VCC jika perlu, meskipun banyak modul sudah built-in)
GND ke GND
Relay Pemanas ke Arduino:
IN ke Digital Pin 7
VCC ke 5V
GND ke GND
Relay Pelembab ke Arduino:
IN ke Digital Pin 8
VCC ke 5V
GND ke GND
Servo Motor ke Arduino:
VCC ke 5V (atau daya eksternal)
GND ke GND
Signal ke Digital Pin 9
LED & Buzzer ke Arduino (via Resistor 220 Ohm):
LED Status/Alarm (Hijau): Anoda (+) ke Digital Pin 10
LED Alarm (Merah): Anoda (+) ke Digital Pin 11
Buzzer: Positif (+) ke Digital Pin 12
Tombol ke Arduino (via Resistor Pull-down 10k Ohm ke GND):
Tombol Mode: Ke Digital Pin 2
Tombol Naik (Up): Ke Digital Pin 3
Tombol Turun (Down): Ke Digital Pin 4
Tombol Reset: Ke Digital Pin 5 (reset hari inkubasi/pengaturan)
Tombol Manual Rotate: Ke Digital Pin 6 (opsional, untuk memutar telur secara manual)
Instalasi Library:
Pastikan Anda sudah menginstal library berikut:
LiquidCrystal_I2C: (Sketch > Include Library > Manage Libraries... cari "LiquidCrystal I2C")
DHT sensor library by Adafruit: (Sketch > Include Library > Manage Libraries... cari "DHT sensor library")
Adafruit Unified Sensor: (diperlukan oleh DHT library, instal juga jika belum)
Servo: (library bawaan Arduino IDE)
EEPROM: (library bawaan Arduino IDE)
Kode Program (Struktur & Bagian Penting):
Karena kodenya akan cukup panjang dan kompleks dengan semua fitur ini, saya akan menyajikannya dalam beberapa bagian utama. Anda perlu menggabungkannya ke dalam satu file .ino
di Arduino IDE.
// --- Bagian 1: Include Library dan Konfigurasi Pin ---
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <Servo.h>
#include <EEPROM.h>
// PIN Definitions
const int LM35_PIN = A0;
const int DHT_PIN = 13; // Digital pin for DHT sensor
const int HEATER_RELAY_PIN = 7; // Relay for heater
const int HUMIDIFIER_RELAY_PIN = 8; // Relay for humidifier
const int SERVO_PIN = 9; // Servo motor for egg turning
const int LED_OK_PIN = 10; // Green LED for normal status
const int LED_ALARM_PIN = 11; // Red LED for alarm
const int BUZZER_PIN = 12; // Buzzer for alarms
const int BUTTON_MODE_PIN = 2;
const int BUTTON_UP_PIN = 3;
const int BUTTON_DOWN_PIN = 4;
const int BUTTON_RESET_PIN = 5; // Reset incubation days / settings
const int BUTTON_MANUAL_ROTATE_PIN = 6; // Manual egg turning
// LCD object initialization (check your I2C address)
LiquidCrystal_I2C lcd(0x27, 16, 2);
// DHT sensor object initialization (change DHT11 to DHT22 if using DHT22)
#define DHTTYPE DHT11 // or DHT22
DHT dht(DHT_PIN, DHTTYPE);
// Servo object initialization
Servo eggServo;
// --- Bagian 2: Variabel Global ---
// Temperature & Humidity Readings
float currentTempC = 0;
float currentHumidity = 0;
// Control Targets (will be stored in EEPROM)
float targetTempC;
float targetHumidity;
unsigned long rotationIntervalHours; // In hours (e.g., 4 hours)
// Default Values
const float DEFAULT_TARGET_TEMP_C = 37.5;
const float DEFAULT_TARGET_HUMIDITY = 55.0; // %RH
const unsigned long DEFAULT_ROTATION_INTERVAL_HOURS = 4; // Every 4 hours
// Alarm Limits (for visual/auditory alarms, not primary control)
const float TEMP_ALARM_HIGH_OFFSET = 0.5; // Trigger alarm if temp > target + offset
const float TEMP_ALARM_LOW_OFFSET = 0.5; // Trigger alarm if temp < target - offset
const float HUMIDITY_ALARM_HIGH_OFFSET = 5.0;
const float HUMIDITY_ALARM_LOW_OFFSET = 5.0;
// Alarm Status
bool alarmActive = false; // Overall alarm status
bool tempHighAlarm = false;
bool tempLowAlarm = false;
bool humidHighAlarm = false;
bool humidLowAlarm = false;
bool sensorErrorAlarm = false;
// EEPROM Addresses
const int EEPROM_TARGET_TEMP_ADDR = 0;
const int EEPROM_TARGET_HUMIDITY_ADDR = 4; // Use 4 bytes for float
const int EEPROM_ROTATION_INTERVAL_ADDR = 8; // Use 4 bytes for unsigned long
const int EEPROM_INCUBATION_DAYS_ADDR = 12; // Use 4 bytes for unsigned long
// Incubation Tracking
unsigned long incubationStartTime = 0; // millis() when incubation started
unsigned long currentIncubationDays = 0;
// Rotation Tracking
unsigned long lastRotationTime = 0;
const int ROTATION_ANGLE_1 = 30; // First position angle
const int ROTATION_ANGLE_2 = 150; // Second position angle
int currentRotationAngle = ROTATION_ANGLE_1;
// Timers for non-blocking operations (using millis())
unsigned long lastTempHumidReadTime = 0;
const long TEMP_HUMID_READ_INTERVAL = 2000; // Read every 2 seconds
unsigned long lastControlLogicTime = 0;
const long CONTROL_LOGIC_INTERVAL = 1000; // Run control logic every 1 second
unsigned long lastLCDUpdateTime = 0;
const long LCD_UPDATE_INTERVAL = 500; // Update LCD every 0.5 seconds for responsiveness
unsigned long lastDayUpdateTime = 0;
const long DAY_UPDATE_INTERVAL = 86400000; // 24 hours in milliseconds
// Button Debounce Timers
unsigned long lastButtonModeTime = 0;
unsigned long lastButtonUpTime = 0;
unsigned long lastButtonDownTime = 0;
unsigned long lastButtonResetTime = 0;
unsigned long lastButtonManualRotateTime = 0;
const long DEBOUNCE_DELAY = 50;
// System States / Modes
enum SystemMode { DISPLAY_NORMAL, SET_TEMP, SET_HUMIDITY, SET_ROTATION, SET_INCUBATION_DAYS };
SystemMode currentSystemMode = DISPLAY_NORMAL;
// Control variables for heating (simple PID-like)
float tempError = 0;
float prevTempError = 0;
float integralTempError = 0;
float derivativeTempError = 0;
const float Kp_temp = 5.0; // Proportional constant
const float Ki_temp = 0.01; // Integral constant
const float Kd_temp = 0.0; // Derivative constant (optional, start with 0)
// Control variables for humidifying
float humidError = 0;
float prevHumidError = 0;
float integralHumidError = 0;
float derivativeHumidError = 0;
const float Kp_humid = 3.0;
const float Ki_humid = 0.05;
const float Kd_humid = 0.0;
// --- Bagian 3: Fungsi Setup ---
void setup() {
// Pin setup
pinMode(HEATER_RELAY_PIN, OUTPUT);
pinMode(HUMIDIFIER_RELAY_PIN, OUTPUT);
pinMode(LED_OK_PIN, OUTPUT);
pinMode(LED_ALARM_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_MODE_PIN, INPUT);
pinMode(BUTTON_UP_PIN, INPUT);
pinMode(BUTTON_DOWN_PIN, INPUT);
pinMode(BUTTON_RESET_PIN, INPUT);
pinMode(BUTTON_MANUAL_ROTATE_PIN, INPUT);
// Ensure relays are OFF (most modules are active LOW)
digitalWrite(HEATER_RELAY_PIN, HIGH);
digitalWrite(HUMIDIFIER_RELAY_PIN, HIGH);
digitalWrite(LED_OK_PIN, LOW);
digitalWrite(LED_ALARM_PIN, LOW);
noTone(BUZZER_PIN);
// Serial communication for debugging
Serial.begin(9600);
Serial.println("Incubator Controller Starting...");
// LCD initialization
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Incubator V1.0");
lcd.setCursor(0, 1);
lcd.print("Loading EEPROM...");
delay(1500);
// DHT sensor initialization
dht.begin();
// Servo attachment
eggServo.attach(SERVO_PIN);
eggServo.write(ROTATION_ANGLE_1); // Set initial position
// Load settings from EEPROM
EEPROM.get(EEPROM_TARGET_TEMP_ADDR, targetTempC);
EEPROM.get(EEPROM_TARGET_HUMIDITY_ADDR, targetHumidity);
EEPROM.get(EEPROM_ROTATION_INTERVAL_ADDR, rotationIntervalHours);
EEPROM.get(EEPROM_INCUBATION_DAYS_ADDR, incubationStartTime);
// Validate loaded settings; set to default if invalid
if (targetTempC < 30.0 || targetTempC > 40.0) targetTempC = DEFAULT_TARGET_TEMP_C;
if (targetHumidity < 40.0 || targetHumidity > 80.0) targetHumidity = DEFAULT_TARGET_HUMIDITY;
if (rotationIntervalHours == 0 || rotationIntervalHours > 24) rotationIntervalHours = DEFAULT_ROTATION_INTERVAL_HOURS; // 0 or too large is invalid
// If incubationStartTime is 0 or very large, assume new cycle
if (incubationStartTime == 0 || incubationStartTime > millis()) {
incubationStartTime = millis(); // Start current time as day 0
EEPROM.put(EEPROM_INCUBATION_DAYS_ADDR, incubationStartTime);
}
lastRotationTime = incubationStartTime; // Assume initial rotation happened at start
Serial.print("Loaded Temp: "); Serial.println(targetTempC);
Serial.print("Loaded Humid: "); Serial.println(targetHumidity);
Serial.print("Loaded Rot Interval: "); Serial.println(rotationIntervalHours);
Serial.print("Incubation Start Time: "); Serial.println(incubationStartTime);
// Perform initial readings and display
readSensors();
updateIncubationDays();
displayLCD();
}
// --- Bagian 4: Fungsi Loop ---
void loop() {
unsigned long currentTime = millis();
// --- Read Sensors ---
if (currentTime - lastTempHumidReadTime >= TEMP_HUMID_READ_INTERVAL) {
lastTempHumidReadTime = currentTime;
readSensors();
}
// --- Control Logic ---
if (currentTime - lastControlLogicTime >= CONTROL_LOGIC_INTERVAL) {
lastControlLogicTime = currentTime;
controlHeater();
controlHumidifier();
autoRotateEggs();
checkAlarms(); // Check and activate alarms based on readings
}
// --- Handle Buttons ---
handleButtons(currentTime);
// --- Update Incubation Days ---
updateIncubationDays();
// --- Update LCD ---
if (currentTime - lastLCDUpdateTime >= LCD_UPDATE_INTERVAL) {
lastLCDUpdateTime = currentTime;
displayLCD();
}
// --- Handle Global Alarm State ---
if (alarmActive) {
digitalWrite(LED_ALARM_PIN, HIGH);
digitalWrite(LED_OK_PIN, LOW);
tone(BUZZER_PIN, (currentTime / 500 % 2 == 0) ? 1000 : 0); // Beep-beep alarm
} else {
digitalWrite(LED_ALARM_PIN, LOW);
digitalWrite(LED_OK_PIN, HIGH); // Green LED on when all OK
noTone(BUZZER_PIN);
}
}
// --- Bagian 5: Fungsi Pembantu Sensor & Kontrol ---
void readSensors() {
// Read LM35 (primary temp)
int analogValue = analogRead(LM35_PIN);
float voltage_mV = (analogValue / 1024.0) * 5000.0; // Assuming 5V AREF
currentTempC = voltage_mV / 10.0;
// Read DHT11/DHT22 (secondary temp & humidity)
float h = dht.readHumidity();
float t = dht.readTemperature();
// Check if any reads failed and exit early (and set sensor error alarm)
if (isnan(h) || isnan(t) || isnan(currentTempC)) {
Serial.println("Failed to read from sensors!");
sensorErrorAlarm = true;
currentTempC = 0; // Indicate error
currentHumidity = 0; // Indicate error
return; // Skip control logic if sensor read failed
} else {
sensorErrorAlarm = false;
currentHumidity = h;
// You might use LM35 for primary temp due to its faster response,
// but DHT's temp can be used for verification or backup.
// For simplicity, we'll primarily use LM35 for temp.
}
Serial.print("Temp: "); Serial.print(currentTempC); Serial.print("C Humidity: "); Serial.print(currentHumidity); Serial.println("%");
}
void controlHeater() {
// Simple PID-like control for heater
tempError = targetTempC - currentTempC;
integralTempError += tempError * (CONTROL_LOGIC_INTERVAL / 1000.0); // Convert interval to seconds
derivativeTempError = (tempError - prevTempError) / (CONTROL_LOGIC_INTERVAL / 1000.0);
prevTempError = tempError;
float output = (Kp_temp * tempError) + (Ki_temp * integralTempError) + (Kd_temp * derivativeTempError);
// Apply hysteresis or simple threshold control
if (currentTempC < targetTempC - 0.2) { // Turn ON heater if temp is below target - hysteresis
digitalWrite(HEATER_RELAY_PIN, LOW); // Active LOW
// Serial.println("Heater ON");
} else if (currentTempC > targetTempC + 0.2) { // Turn OFF heater if temp is above target + hysteresis
digitalWrite(HEATER_RELAY_PIN, HIGH); // Active HIGH
// Serial.println("Heater OFF");
}
}
void controlHumidifier() {
// Simple PID-like control for humidifier
humidError = targetHumidity - currentHumidity;
integralHumidError += humidError * (CONTROL_LOGIC_INTERVAL / 1000.0);
derivativeHumidError = (humidError - prevHumidError) / (CONTROL_LOGIC_INTERVAL / 1000.0);
prevHumidError = humidError;
float output = (Kp_humid * humidError) + (Ki_humid * integralHumidError) + (Kd_humid * derivativeHumidError);
// Apply hysteresis or simple threshold control
if (currentHumidity < targetHumidity - 2.0) { // Turn ON humidifier if humidity is below target - hysteresis
digitalWrite(HUMIDIFIER_RELAY_PIN, LOW); // Active LOW
// Serial.println("Humidifier ON");
} else if (currentHumidity > targetHumidity + 2.0) { // Turn OFF humidifier if humidity is above target + hysteresis
digitalWrite(HUMIDIFIER_RELAY_PIN, HIGH); // Active HIGH
// Serial.println("Humidifier OFF");
}
}
void autoRotateEggs() {
// Rotate every 'rotationIntervalHours'
if (millis() - lastRotationTime >= (unsigned long)rotationIntervalHours * 3600000UL) { // Convert hours to ms
Serial.print("Rotating eggs... Current angle: "); Serial.println(currentRotationAngle);
if (currentRotationAngle == ROTATION_ANGLE_1) {
eggServo.write(ROTATION_ANGLE_2);
currentRotationAngle = ROTATION_ANGLE_2;
} else {
eggServo.write(ROTATION_ANGLE_1);
currentRotationAngle = ROTATION_ANGLE_1;
}
lastRotationTime = millis(); // Reset rotation timer
Serial.println("Rotation Complete.");
}
}
void updateIncubationDays() {
// Calculate current incubation days
currentIncubationDays = (millis() - incubationStartTime) / DAY_UPDATE_INTERVAL;
if (millis() - lastDayUpdateTime >= DAY_UPDATE_INTERVAL) {
lastDayUpdateTime = millis();
// Optionally save currentIncubationDays to EEPROM if you want to be very precise
// EEPROM.put(EEPROM_INCUBATION_DAYS_ADDR, incubationStartTime);
}
}
void checkAlarms() {
tempHighAlarm = (currentTempC > targetTempC + TEMP_ALARM_HIGH_OFFSET);
tempLowAlarm = (currentTempC < targetTempC - TEMP_ALARM_LOW_OFFSET);
humidHighAlarm = (currentHumidity > targetHumidity + HUMIDITY_ALARM_HIGH_OFFSET);
humidLowAlarm = (currentHumidity < targetHumidity - HUMIDITY_ALARM_LOW_OFFSET);
if (tempHighAlarm || tempLowAlarm || humidHighAlarm || humidLowAlarm || sensorErrorAlarm) {
alarmActive = true;
} else {
alarmActive = false;
}
}
void resetAlarmState() {
alarmActive = false;
tempHighAlarm = false;
tempLowAlarm = false;
humidHighAlarm = false;
humidLowAlarm = false;
sensorErrorAlarm = false;
digitalWrite(LED_ALARM_PIN, LOW);
noTone(BUZZER_PIN);
Serial.println("Alarm state reset.");
}
// --- Bagian 6: Fungsi Tampilan LCD ---
void displayLCD() {
lcd.clear();
if (currentSystemMode == DISPLAY_NORMAL) {
// Line 0: Temperature & Humidity
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(currentTempC, 1);
lcd.print((char)223); lcd.print("C");
lcd.print(" H:");
lcd.print(currentHumidity, 0); // Humidity usually shown without decimals
lcd.print("%");
// Line 1: Day & Rotation Countdown
lcd.setCursor(0, 1);
lcd.print("Day:");
lcd.print(currentIncubationDays);
lcd.print(" Rot:");
unsigned long timeUntilNextRotation = ((unsigned long)rotationIntervalHours * 3600000UL) - (millis() - lastRotationTime);
long minutesUntilRotation = timeUntilNextRotation / 60000;
long hoursUntilRotation = minutesUntilRotation / 60;
minutesUntilRotation %= 60;
if (minutesUntilRotation < 0) minutesUntilRotation = 0; // Avoid negative values
if (hoursUntilRotation < 0) hoursUntilRotation = 0;
if (hoursUntilRotation < 10) lcd.print("0");
lcd.print(hoursUntilRotation);
lcd.print("h");
if (minutesUntilRotation < 10) lcd.print("0");
lcd.print(minutesUntilRotation);
lcd.print("m");
} else if (currentSystemMode == SET_TEMP) {
lcd.setCursor(0, 0);
lcd.print("SET TEMP");
lcd.setCursor(0, 1);
lcd.print("Target:");
lcd.print(targetTempC, 1);
lcd.print((char)223); lcd.print("C");
} else if (currentSystemMode == SET_HUMIDITY) {
lcd.setCursor(0, 0);
lcd.print("SET HUMIDITY");
lcd.setCursor(0, 1);
lcd.print("Target:");
lcd.print(targetHumidity, 0);
lcd.print("%");
} else if (currentSystemMode == SET_ROTATION) {
lcd.setCursor(0, 0);
lcd.print("SET ROTATION");
lcd.setCursor(0, 1);
lcd.print("Interval:");
lcd.print(rotationIntervalHours);
lcd.print(" Hrs");
} else if (currentSystemMode == SET_INCUBATION_DAYS) {
// This mode is mainly for "resetting" the incubation days,
// not directly setting a specific day number via Up/Down.
lcd.setCursor(0, 0);
lcd.print("RESET INC. DAY");
lcd.setCursor(0, 1);
lcd.print("Press RESET button");
}
}
// --- Bagian 7: Fungsi Penanganan Tombol ---
void handleButtons(unsigned long currentTime) {
// Mode Button
if (digitalRead(BUTTON_MODE_PIN) == HIGH && (currentTime - lastButtonModeTime > DEBOUNCE_DELAY)) {
lastButtonModeTime = currentTime;
resetAlarmState(); // Reset alarm when switching modes
// Cycle through modes
if (currentSystemMode == DISPLAY_NORMAL) currentSystemMode = SET_TEMP;
else if (currentSystemMode == SET_TEMP) currentSystemMode = SET_HUMIDITY;
else if (currentSystemMode == SET_HUMIDITY) currentSystemMode = SET_ROTATION;
else if (currentSystemMode == SET_ROTATION) currentSystemMode = SET_INCUBATION_DAYS;
else if (currentSystemMode == SET_INCUBATION_DAYS) currentSystemMode = DISPLAY_NORMAL;
Serial.print("System Mode changed to: "); Serial.println(currentSystemMode);
lastLCDUpdateTime = 0; // Force immediate LCD update
}
// UP Button (only active in setting modes)
if (currentSystemMode == SET_TEMP || currentSystemMode == SET_HUMIDITY || currentSystemMode == SET_ROTATION) {
if (digitalRead(BUTTON_UP_PIN) == HIGH && (currentTime - lastButtonUpTime > DEBOUNCE_DELAY)) {
lastButtonUpTime = currentTime;
if (currentSystemMode == SET_TEMP) {
targetTempC += 0.1;
if (targetTempC > 39.0) targetTempC = 39.0; // Max temp
EEPROM.put(EEPROM_TARGET_TEMP_ADDR, targetTempC);
} else if (currentSystemMode == SET_HUMIDITY) {
targetHumidity += 1.0;
if (targetHumidity > 75.0) targetHumidity = 75.0; // Max humidity
EEPROM.put(EEPROM_TARGET_HUMIDITY_ADDR, targetHumidity);
} else if (currentSystemMode == SET_ROTATION) {
rotationIntervalHours += 1;
if (rotationIntervalHours > 12) rotationIntervalHours = 12; // Max 12 hours interval
EEPROM.put(EEPROM_ROTATION_INTERVAL_ADDR, rotationIntervalHours);
}
lastLCDUpdateTime = 0; // Force immediate LCD update
Serial.print("Setting increased: ");
if (currentSystemMode == SET_TEMP) Serial.println(targetTempC);
else if (currentSystemMode == SET_HUMIDITY) Serial.println(targetHumidity);
else if (currentSystemMode == SET_ROTATION) Serial.println(rotationIntervalHours);
}
// DOWN Button (only active in setting modes)
if (digitalRead(BUTTON_DOWN_PIN) == HIGH && (currentTime - lastButtonDownTime > DEBOUNCE_DELAY)) {
lastButtonDownTime = currentTime;
if (currentSystemMode == SET_TEMP) {
targetTempC -= 0.1;
if (targetTempC < 35.0) targetTempC = 35.0; // Min temp
EEPROM.put(EEPROM_TARGET_TEMP_ADDR, targetTempC);
} else if (currentSystemMode == SET_HUMIDITY) {
targetHumidity -= 1.0;
if (targetHumidity < 40.0) targetHumidity = 40.0; // Min humidity
EEPROM.put(EEPROM_TARGET_HUMIDITY_ADDR, targetHumidity);
} else if (currentSystemMode == SET_ROTATION) {
rotationIntervalHours -= 1;
if (rotationIntervalHours < 1) rotationIntervalHours = 1; // Min 1 hour interval
EEPROM.put(EEPROM_ROTATION_INTERVAL_ADDR, rotationIntervalHours);
}
lastLCDUpdateTime = 0; // Force immediate LCD update
Serial.print("Setting decreased: ");
if (currentSystemMode == SET_TEMP) Serial.println(targetTempC);
else if (currentSystemMode == SET_HUMIDITY) Serial.println(targetHumidity);
else if (currentSystemMode == SET_ROTATION) Serial.println(rotationIntervalHours);
}
}
// Reset Button (resets incubation days or setting to default)
if (digitalRead(BUTTON_RESET_PIN) == HIGH && (currentTime - lastButtonResetTime > DEBOUNCE_DELAY)) {
lastButtonResetTime = currentTime;
resetAlarmState();
if (currentSystemMode == SET_INCUBATION_DAYS) {
incubationStartTime = millis(); // Reset incubation start to current time
EEPROM.put(EEPROM_INCUBATION_DAYS_ADDR, incubationStartTime);
lastRotationTime = incubationStartTime; // Reset rotation timer as well
Serial.println("Incubation days reset!");
} else { // Reset all settings to default
targetTempC = DEFAULT_TARGET_TEMP_C;
targetHumidity = DEFAULT_TARGET_HUMIDITY;
rotationIntervalHours = DEFAULT_ROTATION_INTERVAL_HOURS;
EEPROM.put(EEPROM_TARGET_TEMP_ADDR, targetTempC);
EEPROM.put(EEPROM_TARGET_HUMIDITY_ADDR, targetHumidity);
EEPROM.put(EEPROM_ROTATION_INTERVAL_ADDR, rotationIntervalHours);
Serial.println("All settings reset to defaults!");
}
lastLCDUpdateTime = 0; // Force immediate LCD update
}
// Manual Rotate Button
if (digitalRead(BUTTON_MANUAL_ROTATE_PIN) == HIGH && (currentTime - lastButtonManualRotateTime > DEBOUNCE_DELAY)) {
lastButtonManualRotateTime = currentTime;
resetAlarmState();
autoRotateEggs(); // Call rotation function immediately
Serial.println("Manual rotation triggered.");
lastLCDUpdateTime = 0; // Force immediate LCD update
}
}
Cara Menggunakan & Catatan Penting:
Pembangunan Fisik Inkubator:
Penting: Sebelum merakit elektronik, siapkan kotak inkubator yang baik. Pastikan kedap udara, memiliki ventilasi yang bisa diatur, dan cukup ruang untuk telur, pemanas, pelembab, sensor, dan mekanisme pemutar.
Keamanan: Pastikan semua kabel AC (ke pemanas/pelembab) terlindungi dengan baik dan tidak bisa dijangkau. Gunakan power supply yang sesuai dan pastikan grounding.
Penempatan Sensor: Letakkan sensor LM35 dan DHT dekat dengan telur, tapi tidak menyentuh langsung dan jauh dari pemanas/pelembab agar pembacaan akurat.
Kabel dan Power Supply:
Periksa kembali semua pengkabelan. Kesalahan kabel dapat merusak komponen atau membahayakan.
Daya Servo dan Relay: Servo motor dan relay seringkali menarik arus yang lumayan. Jika Anda menggunakan banyak komponen atau servo besar, pertimbangkan untuk memberi daya Arduino melalui adaptor DC (bukan hanya USB) dan bahkan memberi daya servo/relay dari power supply eksternal terpisah (dengan GND yang sama dengan Arduino) untuk stabilitas.
Instalasi Library: Pastikan semua library yang disebutkan di awal sudah terinstal di Arduino IDE Anda.
Alamat I2C LCD: Verifikasi alamat I2C LCD Anda (
0x27
adalah yang paling umum, tetapi bisa0x3F
atau lainnya). Gunakan I2C Scanner jika tidak yakin.Pengujian Awal:
Unggah kode ke Arduino.
Amati Serial Monitor untuk debugging dan memastikan sensor terbaca dengan benar.
Uji setiap tombol dan amati respons di LCD dan Serial Monitor.
Pastikan relay 'klik' dan LED menyala/mati sesuai logika.
Uji servo, pastikan bergerak ke sudut yang benar.
Kalibrasi:
Sensor LM35: Lakukan kalibrasi offset seperti yang dijelaskan sebelumnya untuk memastikan akurasi suhu utama. Anda bisa menambahkan
CALIBRATION_OFFSET_C
pada perhitungancurrentTempC
.Sensor DHT: Meskipun tidak ada kalibrasi langsung di kode, Anda bisa membandingkan pembacaan DHT dengan higrometer referensi untuk memastikan akurasi kelembaban.
Penyesuaian Konstanta PID:
Nilai
Kp
,Ki
,Kd
untuk pemanas dan pelembab (di bagian 2) mungkin perlu disesuaikan dengan ukuran inkubator dan kekuatan pemanas/pelembab Anda. Ini adalah proses "tuning":Mulai dengan
Ki
danKd
sebagai 0.Tingkatkan
Kp
secara bertahap sampai suhu/kelembaban mendekati target, tetapi jangan sampai terlalu berosilasi.Kemudian, sesuaikan
Ki
untuk menghilangkan error jangka panjang (offset).Kd
biasanya digunakan untuk mengurangi overshoot dan meningkatkan stabilitas (jarang diperlukan untuk kontrol suhu sederhana).
Proses ini memerlukan eksperimen.
Penyimpanan EEPROM:
Nilai target dan interval akan disimpan otomatis saat Anda mengubahnya menggunakan tombol UP/DOWN.
Untuk mereset hari inkubasi, masuk ke mode
SET_INCUBATION_DAYS
lalu tekan tombolRESET
.
Dengan semua fitur ini, Anda memiliki alat penetas telur yang canggih dan dapat diandalkan! Ingatlah untuk selalu memprioritaskan keamanan listrik, terutama saat berurusan dengan komponen yang terhubung ke listrik AC.
Komentar
Posting Komentar