Arduino Project Tutorial

Two-Way Crossroads
Traffic Light

A complete guide to building a four-phase traffic light controller for a road junction using an Arduino Uno.

Live Simulation

LIVE SIGNAL PREVIEW — running sequence
N/S
N/S
E/W
E/W
PHASE 1 5 N/S GO
E/W STOP
PHASE 2 2 N/S SLOW
E/W STOP
PHASE 3 5 N/S STOP
E/W GO
PHASE 4 2 N/S STOP
E/W SLOW

Components Required

Everything you need is beginner-friendly and inexpensive. A standard traffic light uses a red, amber and green LED per direction — six LEDs in total for a two-way junction.

×1
Arduino UnoRev3 or compatible
×2
Red LEDs5mm, standard
×2
Amber / Yellow LEDs5mm, standard
×2
Green LEDs5mm, standard
×6
Resistors220Ω (red-red-brown)
×1
BreadboardHalf or full size
×1
USB CableType A to B
×12+
Jumper WiresMale to male
💡
Why 220Ω? Arduino digital pins output 5 V. A typical LED drops ~2 V and needs ~20 mA. V = IR → (5 − 2) / 0.020 = 150Ω minimum. 220Ω gives a safe margin and still produces a clearly visible light.

Pin Assignments

We use six digital output pins — one per LED. Pins 2–7 are ideal as they are well clear of the serial (0, 1) and SPI (10–13) pins.

DirectionColourArduino PinResistor
North / SouthRedPin 2220 Ω
North / SouthAmberPin 3220 Ω
North / SouthGreenPin 4220 Ω
East / WestRedPin 5220 Ω
East / WestAmberPin 6220 Ω
East / WestGreenPin 7220 Ω

GND rail on breadboard → Arduino GND. Each LED cathode (short leg) → GND rail.

Circuit Diagram

ARDUINO UNO D2 D3 D4 D5 D6 D7 GND NORTH / SOUTH RED AMB GRN 220Ω 220Ω 220Ω EAST / WEST RED AMB GRN 220Ω 220Ω 220Ω GND rail signal wire ground resistor
⚠️
Always include the resistors. Without a current-limiting resistor the LED will draw too much current, potentially damaging both the LED and the Arduino's output driver (max 40 mA per pin).

Traffic Light Sequence

A standard UK-style four-phase cycle ensures both road directions can never be green simultaneously.

Phase N/S Signal E/W Signal Duration Purpose
1 GREEN RED 5 s North–South traffic flows
2 AMBER RED 2 s N/S prepares to stop
3 RED GREEN 5 s East–West traffic flows
4 RED AMBER 2 s E/W prepares to stop
🇬🇧
UK vs US style: In the UK, traffic lights also show Red+Amber together before Green (warning drivers to get ready). The simulation above uses a simplified international style — add a RED+AMBER phase of 1–2 s before each Green if you want to replicate full UK sequencing.

Arduino Code

Upload this sketch to your Uno. The logic is deliberately readable — each phase is a clearly labelled block of digitalWrite calls followed by a delay.

crossroads_traffic_light.ino
// ═══════════════════════════════════════════════════
//  Two-Way Crossroads Traffic Light Controller
//  Arduino Uno — 6 LEDs (2 × Red, Amber, Green)
//  No Worries IT — Arduino Tutorial Series
// ═══════════════════════════════════════════════════

// ── Pin definitions ──────────────────────────────
const int NS_RED    = 2;  // North–South red
const int NS_AMBER  = 3;  // North–South amber
const int NS_GREEN  = 4;  // North–South green
const int EW_RED    = 5;  // East–West red
const int EW_AMBER  = 6;  // East–West amber
const int EW_GREEN  = 7;  // East–West green

// ── Timing (milliseconds) ─────────────────────────
const unsigned long GREEN_TIME = 5000;  // 5 seconds green
const unsigned long AMBER_TIME = 2000;  // 2 seconds amber

// ─────────────────────────────────────────────────
void setup() {
  // Set all six pins as outputs
  pinMode(NS_RED,   OUTPUT);
  pinMode(NS_AMBER, OUTPUT);
  pinMode(NS_GREEN, OUTPUT);
  pinMode(EW_RED,   OUTPUT);
  pinMode(EW_AMBER, OUTPUT);
  pinMode(EW_GREEN, OUTPUT);

  // Safe starting state: both directions RED
  allRed();
  delay(1000);
}

// ─────────────────────────────────────────────────
void loop() {

  // ── PHASE 1: N/S GREEN, E/W RED ─────────────────
  setLights(HIGH, LOW,  LOW,   // NS:  red=ON,  amb=OFF, grn=OFF
            LOW,  LOW,  HIGH); // EW:  red=OFF, amb=OFF, grn=ON
  // Wait — swap: N/S gets green
  setLights(LOW,  LOW,  HIGH,
            HIGH, LOW,  LOW);
  delay(GREEN_TIME);

  // ── PHASE 2: N/S AMBER, E/W RED ─────────────────
  setLights(LOW,  HIGH, LOW,
            HIGH, LOW,  LOW);
  delay(AMBER_TIME);

  // ── PHASE 3: N/S RED, E/W GREEN ─────────────────
  setLights(HIGH, LOW,  LOW,
            LOW,  LOW,  HIGH);
  delay(GREEN_TIME);

  // ── PHASE 4: N/S RED, E/W AMBER ─────────────────
  setLights(HIGH, LOW,  LOW,
            LOW,  HIGH, LOW);
  delay(AMBER_TIME);

  // Loop back to Phase 1
}

// ─────────────────────────────────────────────────
// Helper: set all six LEDs in one call
// Parameters: NS_red, NS_amb, NS_grn, EW_red, EW_amb, EW_grn
void setLights(int nsr, int nsa, int nsg,
               int ewr, int ewa, int ewg) {
  digitalWrite(NS_RED,   nsr);
  digitalWrite(NS_AMBER, nsa);
  digitalWrite(NS_GREEN, nsg);
  digitalWrite(EW_RED,   ewr);
  digitalWrite(EW_AMBER, ewa);
  digitalWrite(EW_GREEN, ewg);
}

// Helper: put both directions to red (safe state)
void allRed() {
  setLights(HIGH, LOW, LOW,
            HIGH, LOW, LOW);
}

Code Walk-Through

1 — Pin Constants

Using named constants (NS_RED, EW_GREEN, etc.) instead of bare numbers makes the code self-documenting. If you rewire to different pins, you only change one line per LED.

2 — setup()

A

Every pin is declared as OUTPUT with pinMode(). Without this the pin floats in a high-impedance input state and the LED won't light reliably.

B

allRed() is called immediately. This guarantees a known safe state when the board powers on or resets, before the main loop begins.

3 — setLights() helper

Rather than writing six digitalWrite calls in every phase, setLights() wraps them. This keeps each phase block to a single readable line and prevents accidentally leaving a light in the wrong state.

4 — loop()

The four phases run sequentially inside loop(), which Arduino repeats forever. delay() pauses execution for the given number of milliseconds. This is a simple blocking approach — ideal for a standalone controller with no other tasks.

🚀
Going further? Replace delay() with millis()-based non-blocking timing to let the Arduino do other things (e.g. read a button for a pedestrian crossing) while the lights are running. Look up the "Blink Without Delay" pattern in the Arduino documentation.

Ideas to Extend the Project

1

Pedestrian crossing button — wire a push-button to an interrupt pin. When pressed, the current green phase finishes, then amber runs, then a "walk" LED illuminates while all traffic lights show red.

2

Traffic density adaptation — use IR or ultrasonic sensors to detect waiting vehicles and dynamically extend or shorten the green phase on the busier road.

3

Four-junction model — coordinate multiple Uno boards or use an Arduino Mega's extra pins to control a full 4-way junction with pedestrian phases on all crossings.

4

Serial monitor display — add Serial.begin(9600) and Serial.println() calls to each phase so you can watch the current state in the Arduino IDE's serial monitor — great for debugging.