GPT SOLUTION
Your plan, written as logic, pseudocode, and Arduino code.
01 — Think it through.
Initialize: start at 0°, make one full sweep, and remember the brightest reading and its angle. Go back to that angle.
Watch: stay there while the light is good enough. If the reading drops by more than our buffer, search nearby.
Search: randomly choose a direction and move a few degrees at a time. If the light increases, keep going.
Reverse: if it dims before improving, return to the starting position and try the other direction. If it improves and then dims, return to the best angle we found and stay there.
Reset: if the next step would leave the allowed range without finding good enough light, do a full sweep. Also rescan if the light is lost or neither direction helps.
BUFFER = 100 · GOOD = 900 · LOST = 100
Compare fading against the remembered reading, not just the previous sample. That way, several small drops can add up to a search.
These thresholds are starting guesses. Check room light and phone-flashlight readings in Serial, then adjust them. “Lost” must suit the room’s background light; it may never fall below 100. Use the servo limits you already tested.
02 — Write pseudocode.
CONSTANTS:
angle range = 0 to 180 (use tested limits)
local step = 3 degrees
buffer = 100
good light = 900
lost light = 100
INIT:
initialize Serial, LDR, and servo
fullSweep()
RUN, again and again:
checkLight()
wait briefly
FUNCTION checkLight():
light = readLight()
if light < lost light:
fullSweep()
else if light >= good light OR light > referenceLight:
referenceLight = light
else if light < referenceLight - buffer:
searchNearby()
FUNCTION fullSweep():
bestLight = -1
bestAngle = minimum angle
move to minimum angle and let the servo settle
for each angle from minimum to maximum:
moveTo(angle)
light = readLight()
if light > bestLight:
remember this light and this angle as best
moveTo(bestAngle)
let the servo settle
referenceLight = readLight()
FUNCTION searchNearby():
choose a random direction
remember current angle and light as best
foundImprovement = false
switchedDirection = false
repeat:
calculate the next angle in our chosen direction
if it would leave the allowed range:
fullSweep()
return
moveTo(nextAngle)
light = readLight()
if light < lost light:
fullSweep()
return
if light >= good light:
referenceLight = light
return
if light > bestLight:
remember this light and this angle as best
foundImprovement = true
else if light < bestLight - buffer:
moveTo(bestAngle) and let the servo settle
if foundImprovement:
referenceLight = readLight()
return // We found and passed a peak.
if switchedDirection:
fullSweep()
return // Neither direction helped.
reverse direction
switchedDirection = true
FUNCTION moveTo(angle):
send the angle to the servo
remember the commanded angle
wait for settling
FUNCTION readLight():
read the analog pin
print the angle and reading to Serial
return the reading03 — Add the Arduino code.
INCLUDE → DECLARE → INIT → RUN → LOGIC.
loop() says what happens. The functions handle one job each: decide, scan, search nearby, move, or read.
// INCLUDE
#include <Servo.h>
Servo myServo;
// DECLARE
const int SERVO_PIN = 9;
const int LDR_PIN = A0;
const int MIN_ANGLE = 0; // Use your tested servo limits.
const int MAX_ANGLE = 180;
const int SEARCH_STEP = 3; // Degrees per local search step.
const int SETTLE_TIME = 100; // Wait before measuring, in ms.
const int LIGHT_BUFFER = 100;
const int GOOD_LIGHT = 900;
const int LOST_LIGHT = 100;
int currentAngle = MIN_ANGLE;
int referenceLight = 0;
// INIT
void setup() {
Serial.begin(9600);
pinMode(LDR_PIN, INPUT);
myServo.attach(SERVO_PIN);
Serial.println("--- Light Follower ---");
fullSweep();
}
// RUN
void loop() {
checkLight();
delay(200);
}
// LOGIC
// Decide whether to stay, search nearby, or start over.
void checkLight() {
int light = readLight();
if (light < LOST_LIGHT) {
fullSweep();
} else if (light >= GOOD_LIGHT || light > referenceLight) {
referenceLight = light;
} else if (light < referenceLight - LIGHT_BUFFER) {
searchNearby();
}
}
// Scan the full range and return to its brightest position.
void fullSweep() {
Serial.println("Full sweep");
int bestLight = -1;
int bestAngle = MIN_ANGLE;
moveTo(MIN_ANGLE);
delay(500); // Allow a large return movement to finish.
for (int angle = MIN_ANGLE; angle <= MAX_ANGLE; angle++) {
moveTo(angle);
int light = readLight();
if (light > bestLight) {
bestLight = light;
bestAngle = angle;
}
}
moveTo(bestAngle);
delay(500);
referenceLight = readLight();
}
// Try a direction. Reverse if it gets worse before improving.
void searchNearby() {
Serial.println("Local search");
bool movingForward = random(2) == 1;
bool switchedDirection = false;
bool foundImprovement = false;
int bestAngle = currentAngle;
int bestLight = readLight();
while (true) {
int nextAngle = currentAngle;
if (movingForward) {
nextAngle += SEARCH_STEP;
} else {
nextAngle -= SEARCH_STEP;
}
if (nextAngle < MIN_ANGLE || nextAngle > MAX_ANGLE) {
fullSweep();
return;
}
moveTo(nextAngle);
int light = readLight();
if (light < LOST_LIGHT) {
fullSweep();
return;
}
if (light >= GOOD_LIGHT) {
referenceLight = light;
return;
}
if (light > bestLight) {
bestLight = light;
bestAngle = currentAngle;
foundImprovement = true;
} else if (light < bestLight - LIGHT_BUFFER) {
moveTo(bestAngle);
delay(500);
if (foundImprovement) {
referenceLight = readLight();
return; // We passed a peak. Stay at the best position.
}
if (switchedDirection) {
fullSweep();
return; // Neither direction helped.
}
movingForward = !movingForward;
switchedDirection = true;
}
}
}
// Move, remember our commanded angle, and let the reading settle.
void moveTo(int angle) {
myServo.write(angle);
currentAngle = angle;
delay(SETTLE_TIME);
}
// Read and log one light measurement.
int readLight() {
int light = analogRead(LDR_PIN);
Serial.print("Angle: ");
Serial.print(currentAngle);
Serial.print(" Light: ");
Serial.println(light);
return light;
}
Assumes the LDR is toward 5V and the fixed divider resistor is toward GND: brighter means a higher A0 reading. Servo signal is D9; use the servo power arrangement already tested, with a common GND. Open Serial Monitor at 9600 baud.
Read the flags: movingForward chooses the direction. ! flips true to false or false to true. foundImprovement remembers whether this search got brighter. switchedDirection prevents repeatedly trying the same two directions.
Test it slowly: scans and searches finish before loop() continues. Move the phone slowly and watch the readings. A scan takes time; this beginner version uses delays so the movement can settle before each reading.
A short opaque tube around the LDR helps make the reading depend on direction. Serial’s angle is the command we sent, not position feedback from the servo.