Build a Dual-Axis Solar Tracker: ESP32, LDR Sensors, and Servo-Driven Panel Positioning
This site's solar power guide covers panels, charge controllers, and battery chemistry for a fixed-mount system. A tracker takes it a step further: instead of a panel bolted at a fixed angle, this build actively follows the sun across the sky on two axes, meaningfully increasing energy capture versus a stationary panel — real-world gains vary by latitude and season, but dual-axis tracking commonly adds 20-40% more daily energy collection compared to a fixed panel at a compromise angle. This project builds a small-scale tracker suitable for a hobby panel (think phone-charging or small battery-bank scale, not a rooftop array) using an ESP32, light-dependent resistors for sun-seeking, and two servos for pan and tilt — a good weekend electromechanical build that combines this site's ESP32, motor control, and solar power content into one working system.
How It Works
Four LDRs (light-dependent resistors) are mounted in a cross pattern around a central divider — typically a small opaque fin or cardboard baffle between each pair — so that when the sun is off-center, one side's LDRs are shaded relative to the other and read a different light level. The ESP32 reads all four LDR voltages through its ADC, compares light levels across the pan axis (left vs. right pair) and tilt axis (top vs. bottom pair), and nudges the corresponding servo in the direction of the brighter reading until the readings balance — meaning the panel is now pointed roughly at the sun. This is a simple proportional control loop, not GPS or ephemeris-based sun tracking, which keeps the electronics and code approachable while still delivering real tracking performance on clear days.
ComponentRole ESP32 dev boardReads LDR sensors via ADC, drives servos, and can optionally log tracking data or expose a web dashboard over WiFi 4x LDR photoresistorsLight sensing, one per quadrant (up/down/left/right) around a central shading divider 2x standard hobby servos (or continuous-rotation for wider range)Pan (azimuth) and tilt (elevation) axis actuators Small solar panel (5-10W hobby panel)The payload the tracker points — swap for a larger panel and beefier servos/gearing for a bigger build 3D-printed or built pan-tilt bracketMechanical mount linking the two servos to the panel frame Weatherproof enclosure for the ESP32 and wiringOutdoor use requires sealing the electronics away from rain and condensationBuilding the Sensor Head
Mount the four LDRs flush on a small platform, arranged in a plus pattern, with an opaque divider — a few centimeters of thin plastic, 3D-printed fin, or even folded cardboard — rising between each adjacent pair, tall enough to cast a meaningful shadow on the off-sun side when the sun angle isn't centered. This sensor head can either ride on the tracker itself (so it tracks along with the panel, useful for fine centering) or sit fixed alongside the panel — the fixed approach is simpler to build and works fine for a first version, since the goal is just detecting which direction has more light, not precision alignment.
Wiring
Each LDR forms a voltage divider with a fixed resistor (a common starting value is 10kΩ, adjust based on your LDR's resistance range and ambient light levels) feeding into one of the ESP32's ADC-capable GPIO pins. Servos connect to PWM-capable GPIO pins and need their own adequately rated 5V supply rather than drawing current through the ESP32's onboard regulator — two servos under load can draw enough current to brown out the ESP32 if powered from the same weak source, a failure mode covered in more depth in this site's guide on driving motors with Arduino and ESP32.
PinConnection ADC1_CH0-CH3 (e.g. GPIO 36, 39, 34, 35)Four LDR voltage divider outputs GPIO 18 (PWM)Pan servo signal GPIO 19 (PWM)Tilt servo signal 5V external supplyServo power (separate from ESP32 3.3V logic supply, common ground required)Control Logic
The core loop reads all four LDRs, computes a left-right difference and an up-down difference, and moves each servo a small step toward the brighter side if the difference exceeds a dead-band threshold (a small tolerance window that prevents the servo from constantly jittering back and forth chasing tiny, meaningless fluctuations from passing clouds or leaf shadows). A basic structure:
read ldr_top, ldr_bottom, ldr_left, ldr_right diff_vertical = ldr_top - ldr_bottom diff_horizontal = ldr_left - ldr_right if abs(diff_vertical) > DEADBAND: move tilt_servo toward brighter side, one step if abs(diff_horizontal) > DEADBAND: move pan_servo toward brighter side, one step delay(CHECK_INTERVAL) // check every 10-30 seconds is plenty; the sun moves slowlyRunning this loop every few seconds rather than continuously avoids servo wear and unnecessary power draw — the sun's position changes slowly enough that checking every 10-30 seconds tracks it perfectly well while extending servo and mechanism lifespan considerably compared to a tight, constant-correction loop.
Mechanical Notes
- Standard hobby servos have a limited rotation range (commonly 180°) — for full-day azimuth tracking from sunrise to sunset, you may need a continuous-rotation servo with position feedback, a geared DC motor with a rotary encoder, or accept a reduced tracking window and let the panel reset to a starting position overnight.
- Wind loading on a panel-sized surface is real — size the mounting bracket and servo torque with a safety margin, and consider a wind-triggered "stow flat" behavior (detected via a simple accelerometer or just a scheduled overnight reset) for outdoor installations.
- 3D-printed brackets work well for small hobby panels but check your printer's material choice against outdoor UV and temperature exposure — this site's guide on filament and material selection covers which plastics hold up outdoors versus which degrade in sunlight.
Extending the Build
Once the basic LDR-driven tracker works, natural upgrades include logging tracking angle and panel output voltage/current over WiFi to a dashboard (pairing well with this site's ESP32 web control panel guide), switching to a hybrid approach that combines LDR fine-tracking with a coarse ephemeris-based sun position calculation for cloudy-day reliability, or scaling the mechanism up with geared motors and a heavier-duty frame for a larger panel. The sensor, control loop, and wiring principles here scale directly to a bigger build — only the actuator torque and frame rigidity need to grow with panel size.
Related Guides
- How to Control Motors with Arduino and ESP32: Stepper, DC, and Servo Drivers
- Solar Power for Maker Projects: Panels, Charge Controllers, and Battery Chemistry
- MQTT and Node-RED on Raspberry Pi: Visual Automation for ESP32 Sensor Networks
- Relays and Solid-State Relays for Makers: Switching AC and DC Loads Safely
- ESPHome and Home Assistant Beginner Guide: Build Your First WiFi Sensor
- Build a Meshtastic Off-Grid Mesh Messaging Node with ESP32 and LoRa
- Build an ESP32 Audio Spectrum Analyzer / VU Meter: FFT, I2S Audio, and Addressable LED Bar Graphs
- Build a 3D-Printed Desktop Robotic Arm: Servos, Inverse Kinematics, and Python Control