Build a light-seeking sunflower

A servo turns a printed sunflower from side to side, measures the light in every direction with a photoresistor and then points the flower at the brightest spot.
  • Level:Beginner
  • Duration: 50 min
  • Ages 10+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a light-seeking sunflower – EEMENTOR STEM™ lesson

Young sunflowers turn to follow the sun during the day. Solar panels on tracking stands do the same, so they make more electricity. In this lesson you build a flower that looks for the light: a servo turns it slowly from one side to the other while a photoresistor measures how bright it is in each direction. Then it turns back to the brightest direction and waits. When the light changes, it looks around again.

What you'll learn

  • How to scan with a servo and take a measurement at every step
  • How to find the biggest value in a set of readings
  • How to average several readings to get a steadier value
  • How to react when a value changes by more than a set amount

What you need

  • UNO R3 board and USB cable (UNO R3 Starter Kit)
  • Servo motor (UNO R3 Starter Kit)
  • Photoresistor module (45-in-1 Sensor Kit)
  • 3 female-to-male jumper wires, or female-to-female and male-to-male wires plugged together
  • A torch or a phone light to test with
  • The printed parts from the 3D printing box below (servo stand, sunflower head and petals), or the cardboard version described there
  • Breadboard and jumper wires (UNO R3 Starter Kit)

Wiring

Breadboard wiring diagram: Build a light-seeking sunflower
Breadboard view. Check each connection against the wiring table below.
From To
Photoresistor module S UNO pin A0
Photoresistor module + and − 5V and GND
Servo orange / yellow wire UNO pin 9
Servo red wire 5V
Servo brown / black wire GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The sketch

#include <Servo.h>

const int LIGHT_PIN = A0;
const int SERVO_PIN = 9;
const int STEP = 5;                          // degrees between measurements
const unsigned long RESCAN_EVERY = 60000;    // look around again every minute...
const int BIG_CHANGE = 60;                   // ...or sooner if the light changes this much
const bool BRIGHTER_IS_HIGHER = false;       // see "Check your sensor"

Servo head;
int bestAngle = 90;
int bestLight = 0;
unsigned long lastScan = 0;

// Average of 8 readings, turned so that a bigger number always means more light
int readLight() {
  long sum = 0;
  for (int i = 0; i < 8; i++) {
    sum += analogRead(LIGHT_PIN);
    delay(2);
  }
  int value = sum / 8;
  return BRIGHTER_IS_HIGHER ? value : 1023 - value;
}

void scan() {
  Serial.println("Looking for the light...");
  bestLight = -1;
  for (int angle = 10; angle <= 170; angle += STEP) {
    head.write(angle);
    delay(angle == 10 ? 500 : 80);           // wait for the servo to arrive
    int light = readLight();
    if (light > bestLight) {
      bestLight = light;
      bestAngle = angle;
    }
  }
  head.write(bestAngle);
  lastScan = millis();
  Serial.print("Brightest at ");
  Serial.print(bestAngle);
  Serial.print(" degrees, light level ");
  Serial.println(bestLight);
}

void setup() {
  Serial.begin(9600);
  head.attach(SERVO_PIN);
  head.write(90);
  delay(1000);
  scan();
}

void loop() {
  int light = readLight();
  if (abs(light - bestLight) > BIG_CHANGE || millis() - lastScan > RESCAN_EVERY) {
    scan();
  }
  delay(200);
}

Check your sensor

  1. Open the Serial Monitor at 9600 baud and wait for "Brightest at … degrees".
  2. Shine a torch at the flower from one side. Within a second it should look around and stop facing the torch.
  3. If it turns away from the torch instead, change BRIGHTER_IS_HIGHER to true and upload again. Photoresistor modules are wired in two different ways, and this one setting covers both.

How it works

scan() is a classic "find the biggest" loop. It starts with bestLight = -1, so the first reading always wins, and then keeps a new reading only if it is brighter than the best one so far, together with the angle where it was measured.

In loop() the flower measures the light where it is pointing. If it is very different from the brightest value it found (because a cloud came or a lamp was switched on), or if a minute has passed, it scans again. Waiting between scans saves the servo from constant buzzing, just as a real solar tracker only moves every few minutes.

Try this next

  • Make the scan faster or more precise by changing STEP. What is the trade-off?
  • Put the flower on a windowsill for a day and log the best angle every 10 minutes. Can you see the sun moving?
  • Add a second servo for up and down, like the radar stand, and track in two directions.

Troubleshooting

  • The flower turns away from the light: change BRIGHTER_IS_HIGHER, see above.
  • It scans again and again: the light is flickering (some LED lamps do) or BIG_CHANGE is too small. Try 120.
  • The wires stop the head turning: route them behind the stand and leave a loose loop.
  • The board restarts when the servo moves: servos draw bursts of current. Use a good USB port or a powered hub, and check that the servo's red wire is on 5V.
  • A printed part is too tight or too loose: printers differ by a few tenths of a millimetre. Sand or file a tight hole, and fix a loose part with a drop of hot glue or a strip of tape.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

45-in-1 Sensor Kit | Compatible with Arduino IDE and ESP32 $37.00

Shop the kit