</>CoderDIY
← Back to list
Article

Build a Solar Panel Sun Tracker with Arduino

Author: CoderDIY··Đọc bằng tiếng Việt
☀️

A fixed-mount solar panel only hits peak efficiency at one moment of the day — early morning and late afternoon, when light hits at a steep angle, output drops sharply. A solar tracker rotates the panel toward the strongest light all day long, which can boost harvested energy by 20-30% over a fixed panel of the same rating. This project uses an Arduino, two light-dependent resistors (LDRs), and a servo to build a single-axis demo — enough to understand the principle before scaling up to a full two-axis system.

How it works

  1. Two LDR sensors sit on either side of a small divider, so that when light comes in at an angle, one side falls in shadow while the other gets direct light.
  2. The Arduino reads both LDR light levels on its analog pins.
  3. If the difference between the two sides crosses a threshold, the Arduino commands the servo to rotate a bit toward the LDR receiving more light.
  4. When the difference drops back near zero (the panel is now pointed straight at the strongest light source), the servo stops — the cycle repeats continuously as the sun moves through the day.
<rect x="10" y="20" width="140" height="60" rx="10" class="box" />
<text x="80" y="45" text-anchor="middle" class="label">Read 2 LDRs</text>
<text x="80" y="62" text-anchor="middle" class="label">(left/right)</text>

<rect x="170" y="20" width="140" height="60" rx="10" class="box" />
<text x="240" y="45" text-anchor="middle" class="label">Compute diff</text>
<text x="240" y="62" text-anchor="middle" class="label">(left − right)</text>

<rect x="330" y="20" width="140" height="60" rx="10" class="box" />
<text x="400" y="45" text-anchor="middle" class="label">Check threshold</text>
<text x="400" y="62" text-anchor="middle" class="label">(dead zone)</text>

<rect x="490" y="20" width="140" height="60" rx="10" class="box" />
<text x="560" y="45" text-anchor="middle" class="label">Rotate servo</text>
<text x="560" y="62" text-anchor="middle" class="label">(one small step)</text>

<line x1="150" y1="50" x2="170" y2="50" class="arrow" />
<line x1="310" y1="50" x2="330" y2="50" class="arrow" />
<line x1="470" y1="50" x2="490" y2="50" class="arrow" />

<path d="M 560 80 L 560 190 L 80 190 L 80 80" class="arrow" fill="none" />
<text x="320" y="210" text-anchor="middle" class="sublabel">Repeats every few seconds all day</text>
Sun-tracking loop: read LDRs, compare the difference, rotate the servo a small step until balanced.

Parts list

  • Arduino Uno or Nano
  • 2 light-dependent resistors (LDRs) + 2× 10kΩ resistors (voltage divider)
  • SG90 servo, or a higher-torque servo if the panel is heavier
  • A small solar panel (5V, for demoing or trickle-charging a backup battery)
  • A small divider between the two LDRs (cardboard or 3D-printed) to cast an uneven shadow when light hits at an angle
  • A mechanical rotating mount linking the servo to the panel (3D-printed or hand-built)
<rect x="30" y="40" width="170" height="220" rx="10" class="box" />
<text x="115" y="155" text-anchor="middle" class="label">Arduino Uno</text>

<rect x="440" y="30" width="170" height="90" rx="10" class="box" />
<text x="525" y="80" text-anchor="middle" class="label">Left LDR → A0</text>

<rect x="440" y="140" width="170" height="90" rx="10" class="box" />
<text x="525" y="190" text-anchor="middle" class="label">Right LDR → A1</text>

<line x1="200" y1="70" x2="440" y2="70" class="wire" />
<circle cx="200" cy="70" r="4" class="pin" />
<circle cx="440" cy="70" r="4" class="pin" />

<line x1="200" y1="180" x2="440" y2="180" class="wire" />
<circle cx="200" cy="180" r="4" class="pin" />
<circle cx="440" cy="180" r="4" class="pin" />

<line x1="200" y1="230" x2="330" y2="230" class="wire" />
<text x="270" y="250" text-anchor="middle" class="sublabel">Pin 9 → Servo (signal)</text>
<circle cx="200" cy="230" r="4" class="pin" />
Both LDRs form a voltage divider with 10kΩ resistors into A0/A1; the servo is driven from a PWM pin (D9).

Sample code

#include <Servo.h>

Servo panelServo;

const int LDR_LEFT = A0;
const int LDR_RIGHT = A1;
const int SERVO_PIN = 9;

int servoAngle = 90; // starting midpoint, 0-180 degrees
const int STEP = 1;          // step size per correction
const int DEAD_ZONE = 40;    // difference threshold, avoids constant jitter
const int READ_DELAY = 3000; // re-read every 3s, gives the servo time to settle

void setup() {
  Serial.begin(9600);
  panelServo.attach(SERVO_PIN);
  panelServo.write(servoAngle);
}

void loop() {
  int left = analogRead(LDR_LEFT);
  int right = analogRead(LDR_RIGHT);
  int diff = left - right;

  Serial.print("Left: "); Serial.print(left);
  Serial.print(" | Right: "); Serial.print(right);
  Serial.print(" | Diff: "); Serial.println(diff);

  if (abs(diff) > DEAD_ZONE) {
    if (diff > 0 && servoAngle < 180) {
      servoAngle += STEP; // left side brighter, rotate toward it
    } else if (diff < 0 && servoAngle > 0) {
      servoAngle -= STEP; // right side brighter, rotate toward it
    }
    panelServo.write(servoAngle);
  }

  delay(READ_DELAY);
}

Common pitfalls

  • No divider between the two LDRs — there’s no uneven shadow, so the panel never “decides” which way to turn because both sensors read nearly the same value.
  • Missing dead zone (DEAD_ZONE) causes the servo to jitter constantly around the balance point, draining the servo and wearing out the mechanics fast — always leave a tolerance band before issuing a rotation command.
  • Reading and rotating too fast makes the servo react to a passing cloud instead of the actual light trend over the day — space out readings by a few seconds, or average several samples.
  • A small SG90 servo lacks torque if the panel and mount are heavy — use a higher-torque servo or a geared DC motor with a driver instead.

Extensions

Add a second axis (tilt for solar elevation, in addition to azimuth) for a full two-axis tracker, attach a current/voltage sensor (INA219) to directly measure harvested power and compare it against a fixed mount, or use an ESP32 to log data in real time to a dashboard like the one in self-hosted sensor dashboard with Grafana.

Tags:#arduino#solar#sensors

Comments