Build a lighthouse with a fading LED beacon

Print a lighthouse, put a white LED in its lantern room and program the light patterns that real lighthouses use, from a slow rotating beam to groups of flashes.
  • 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 lighthouse with a fading LED beacon – EEMENTOR STEM™ lesson

Every lighthouse has its own pattern of light, called its character, so sailors can tell at night which lighthouse they are looking at. Some flash once every five seconds, some flash in groups, and old ones had a turning lens that swept a beam across the sea. In this lesson you print a small lighthouse, light it with a white LED and program four real lighthouse characters. A button switches between them, and a red harbour light blinks next to it.

What you'll learn

  • How to fade an LED smoothly with analogWrite() (PWM)
  • How to make repeating patterns with the remainder operator %
  • How to keep several things going at once with millis()
  • How to print a part that fits an electronic component

What you need

  • UNO R3 board and USB cable (UNO R3 Starter Kit)
  • White LED and red LED (UNO R3 Starter Kit)
  • 2 resistors, 220 Ω (UNO R3 Starter Kit)
  • 1 push button (UNO R3 Starter Kit)
  • 2 female-to-female and 2 male-to-male jumper wires, to reach the LED in the lantern (UNO R3 Starter Kit)
  • The printed parts from the 3D printing box below (lighthouse tower), or the cardboard version described there
  • Breadboard and jumper wires (UNO R3 Starter Kit)

Wiring

Breadboard wiring diagram: Build a lighthouse with a fading LED beacon
Breadboard view. Check each connection against the wiring table below.
From To
UNO pin 9 220 Ω resistor, then the white LED's long leg (through the jumper wires up the tower)
White LED short leg GND
UNO pin 6 220 Ω resistor, then the red LED's long leg
Red LED short leg GND
Push button, one leg UNO pin 2
Push button, the diagonally opposite leg GND

The beacon must be on pin 9, because only the pins marked with a ~ on the UNO can fade an LED.

The sketch

const int BEAM_PIN = 9;       // white LED in the lantern (a PWM pin, marked ~)
const int HARBOUR_PIN = 6;    // red LED: the harbour light
const int BUTTON_PIN = 2;

const byte MODES = 4;
const char* const NAMES[MODES] = {
  "Rotating beam: sweeps past every 6 s",
  "Single flash every 5 s",
  "Group of 3 flashes every 10 s",
  "Occulting: on, with a short dark gap every 4 s"
};
byte mode = 0;
unsigned long modeStart = 0;
bool lastButton = HIGH;
unsigned long lastPress = 0;

// Brightness of the beam (0-255), t milliseconds after the mode started
int beamLevel(unsigned long t) {
  if (mode == 0) {
    long phase = t % 6000;
    long fromPeak = abs(phase - 3000);     // 0 when the beam points straight at you
    if (fromPeak > 1200) return 6;         // a faint glow while it points away
    long x = 1200 - fromPeak;              // 0 ... 1200
    return 6 + (int)(x * x / 5800);        // a soft curve up to full brightness
  }
  if (mode == 1) {
    return (t % 5000 < 400) ? 255 : 0;
  }
  if (mode == 2) {
    unsigned long p = t % 10000;
    for (int i = 0; i < 3; i++) {
      if (p >= i * 1000UL && p < i * 1000UL + 350) return 255;
    }
    return 0;
  }
  return (t % 4000 < 3000) ? 255 : 0;      // occulting: mostly on
}

void setup() {
  Serial.begin(9600);
  pinMode(BEAM_PIN, OUTPUT);
  pinMode(HARBOUR_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.println(NAMES[mode]);
}

void loop() {
  bool button = digitalRead(BUTTON_PIN);
  if (button == LOW && lastButton == HIGH && millis() - lastPress > 200) {
    lastPress = millis();
    mode = (mode + 1) % MODES;
    modeStart = millis();
    Serial.println(NAMES[mode]);
  }
  lastButton = button;

  analogWrite(BEAM_PIN, beamLevel(millis() - modeStart));
  digitalWrite(HARBOUR_PIN, millis() % 2000 < 1000);   // red: 1 s on, 1 s off
}

How it works

analogWrite() switches pin 9 on and off about 500 times a second. The number from 0 to 255 sets how much of each cycle the pin is on, so 255 is full brightness and 6 is a faint glow. Your eye sees a steady, dimmer light. This trick is called pulse-width modulation (PWM).

Every pattern repeats, so the sketch uses the remainder operator %. t % 5000 counts from 0 to 4999 and starts again, so t % 5000 < 400 is true for the first 400 ms of every 5 seconds: one flash. The rotating beam measures how far it is from the middle of its 6-second cycle and turns that distance into a brightness that rises and falls smoothly.

Because nothing in loop() waits with delay(), the button, the beacon and the harbour light all keep working at the same time.

Try this next

  • Look up a lighthouse near you (or a famous one, such as Fastnet or Kõpu) and program its real character.
  • Add a "storm" mode that flashes faster and makes the harbour light shine all the time.
  • Paint or print the lantern room in a different colour so the windows stand out.

Troubleshooting

  • The beacon is only on or off, never in between: it must be on pin 9 (or another pin marked ~).
  • The LED doesn't light in the tower: the long leg must connect to the resistor. Swap the two jumper wires at the breadboard.
  • The button changes two modes at once: make the 200 ms in millis() - lastPress > 200 bigger.
  • 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.

UNO R3 Starter Kit | Arduino IDE Compatible | Free Tutorials $56.00

Shop the kit