// --- Libraries ---
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <IRremote.h>
#include <RTClib.h>
// --- LCD Setup ---
LiquidCrystal_I2C lcd(0x27, 20, 4);
// --- RTC Setup ---
RTC_DS1307 rtc;
// --- IR Receiver Pin ---
#define IR_RECEIVE_PIN 11
// --- Photodiode Pins ---
const int pdTop = A0;
const int pdBottom = A1;
const int pdLeft = A2;
const int pdRight = A3;
// --- Motor Pins ---
const int enPin = 7; // Enable for vertical
const int dirPin = 6; // Direction for vertical
const int stepPin = 5; // Step for vertical
const int enPin2 = 4; // Enable for horizontal
const int dirPin2 = 3; // Direction for horizontal
const int stepPin2 = 2;// Step for horizontal
// --- Mode Flags ---
bool manualMode = false;
bool useRTC = false;
void setup() {
Serial.begin(9600);
// LCD Init
lcd.begin(20, 4);
lcd.backlight();
// IR Init
IrReceiver.begin(IR_RECEIVE_PIN);
// RTC Init
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
// Motor Pins
pinMode(enPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(enPin2, OUTPUT);
pinMode(dirPin2, OUTPUT);
pinMode(stepPin2, OUTPUT);
digitalWrite(enPin, LOW);
digitalWrite(enPin2, LOW);
lcd.setCursor(0, 0);
lcd.print("Mode: AUTO");
}
void loop() {
// Handle IR Input
if (IrReceiver.decode()) {
unsigned long code = IrReceiver.decodedIRData.command;
IrReceiver.resume();
switch (code) {
case 0xA8: // OK button toggles mode
manualMode = !manualMode;
lcd.setCursor(0, 0);
lcd.print("Mode: ");
lcd.print(manualMode ? "MANUAL" : "AUTO ");
break;
case 0x18: // 2 - Up
if (manualMode) moveMotor(stepPin, dirPin, 5, true);
break;
case 0x4A: // 8 - Down
if (manualMode) moveMotor(stepPin, dirPin, 5, false);
break;
case 0x10: // 4 - Left
if (manualMode) moveMotor(stepPin2, dirPin2, 5, true);
break;
case 0x5A: // 6 - Right
if (manualMode) moveMotor(stepPin2, dirPin2, 5, false);
break;
}
}
if (!manualMode) {
// Read photodiodes (0–1023 scale)
int topVal = analogRead(pdTop);
int bottomVal = analogRead(pdBottom);
int leftVal = analogRead(pdLeft);
int rightVal = analogRead(pdRight);
const int lightThreshold = 150;
bool isLowLight = (topVal < lightThreshold && bottomVal < lightThreshold &&
leftVal < lightThreshold && rightVal < lightThreshold);
Serial.print("Photodiodes: T="); Serial.print(topVal);
Serial.print(" B="); Serial.print(bottomVal);
Serial.print(" L="); Serial.print(leftVal);
Serial.print(" R="); Serial.println(rightVal);
if (isLowLight) {
useRTC = true;
DateTime now = rtc.now();
lcd.setCursor(0, 1);
lcd.print("RTC ");
lcd.print(now.hour());
lcd.print(":");
lcd.print(now.minute());
if (now.hour() >= 6 && now.hour() < 12) {
moveMotor(stepPin2, dirPin2, 1, true); // East
} else if (now.hour() >= 12 && now.hour() < 18) {
moveMotor(stepPin2, dirPin2, 1, false); // West
}
} else {
useRTC = false;
lcd.setCursor(0, 1);
lcd.print("PhotoTrack ");
if (topVal - bottomVal > 100) {
moveMotor(stepPin, dirPin, 1, true); // Up
} else if (bottomVal - topVal > 100) {
moveMotor(stepPin, dirPin, 1, false); // Down
}
if (leftVal - rightVal > 100) {
moveMotor(stepPin2, dirPin2, 1, true); // Left
} else if (rightVal - leftVal > 100) {
moveMotor(stepPin2, dirPin2, 1, false); // Right
}
}
}
delay(500);
}
void moveMotor(int stepPin, int dirPin, int steps, bool dir) {
digitalWrite(dirPin, dir);
for (int i = 0; i < steps; i++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(500);
digitalWrite(stepPin, LOW);
delayMicroseconds(500);
}
}
UP
LEFT
RIGHT
DOWN
X - AXIS
(HORIZONTAL)
Y - AXIS
(VERTICAL)