Chat
Ask me anything
Ithy Logo

Revolutionizing Urban Flow: Building a Smart 4-Way Traffic System with Pedestrian Safety

An in-depth guide to coding an Arduino-based traffic controller using IR sensors for dynamic vehicle management and dedicated pedestrian features.

arduino-4way-traffic-ir-pedestrian-9o8fboyw

Creating an intelligent traffic light system for a four-way intersection involves managing vehicle flow efficiently while prioritizing pedestrian safety. This project leverages an Arduino microcontroller, four Infrared (IR) sensors for vehicle detection on each road, and pedestrian interaction mechanisms (push buttons and dedicated signals). The goal is to develop a system that dynamically adapts to traffic conditions and pedestrian needs, moving beyond simple timed cycles.

Key Project Highlights

  • Dynamic Traffic Control: IR sensors detect vehicles, allowing the system to adjust green light durations or prioritize busier roads.
  • Comprehensive Pedestrian Safety: Dedicated push buttons and signal lights for pedestrians on all four approaches, ensuring safe crossing times.
  • Modular Arduino Programming: Structured code for managing multiple traffic lights, sensors, and pedestrian states, promoting clarity and scalability.

System Architecture and Components

The core of this system is an Arduino board (an Arduino Mega is recommended due to the number of I/O pins required for a full 4-way system with individual pedestrian controls). Each of the four roads is equipped with standard Red, Yellow, and Green LEDs for vehicles, an IR sensor to detect approaching vehicles, a push button for pedestrians to request crossing, and separate Red and Green LEDs for pedestrian signals.

Diagram of a traffic control system with sensors

Conceptual diagram of a sensor-based traffic management system.

Essential Hardware

  • Arduino Board (Uno or Mega, Mega recommended for more pins)
  • LEDs:
    • 12x Vehicle Traffic LEDs (4 Red, 4 Yellow, 4 Green)
    • 8x Pedestrian Signal LEDs (4 Red, 4 Green)
  • 4x IR Proximity Sensors (for vehicle detection)
  • 4x Push Buttons (for pedestrian crossing requests)
  • Resistors:
    • 20x 220Ω resistors (for all LEDs)
    • 4x 10kΩ resistors (for push buttons, if not using internal pull-ups)
  • Breadboard(s)
  • Jumper Wires
  • 5V Power Supply (can be from Arduino if load is not excessive)

Circuit Connections: Pin Configuration Table

Properly wiring the components to the Arduino is crucial. The following table outlines a suggested pin configuration. Note that IR sensors typically have VCC, GND, and OUT pins. The OUT pin connects to the Arduino. Push buttons are connected to an input pin and GND, often using an internal or external pull-up resistor.

Component Group Road Vehicle Red LED Vehicle Yellow LED Vehicle Green LED Pedestrian Red LED Pedestrian Green LED IR Sensor (Analog/Digital Pin) Pedestrian Button (Digital Pin)
North 1 Pin 2 Pin 3 Pin 4 Pin 22 Pin 23 Pin A0 Pin 30
East 2 Pin 5 Pin 6 Pin 7 Pin 24 Pin 25 Pin A1 Pin 31
South 3 Pin 8 Pin 9 Pin 10 Pin 26 Pin 27 Pin A2 Pin 32
West 4 Pin 11 Pin 12 Pin 13 Pin 28 Pin 29 Pin A3 Pin 33

Note: Ensure LEDs are connected with current-limiting resistors (e.g., 220Ω). Button pins are configured with `INPUT_PULLUP`, so connect the other terminal of the button to GND. IR sensor output pins are connected to the specified Arduino pins; their VCC and GND must also be connected. Pin numbers are examples and can be adjusted in the code.


Operational Logic and System Flow

The system operates on a cycle, granting green lights to different roads. IR sensors check for vehicles to potentially extend green times. Pedestrian buttons, when pressed, signal a request to cross. The system will then, at an appropriate point in the traffic cycle (e.g., after the current green phase completes with a yellow light), turn all vehicle lights red and activate the pedestrian "WALK" signal for the requesting road.

Pedestrian traffic signals

Example of pedestrian walk and don't walk signals.

Vehicle Detection

IR sensors are placed to detect vehicles waiting at each approach. A detection (typically a LOW signal from the sensor) can be used to inform the Arduino. The system might extend the green light duration for a road if vehicles are continuously detected or prioritize a road with waiting vehicles.

Pedestrian Crossing Sequence

  1. A pedestrian presses the button on one of the four roads.
  2. The system registers this request.
  3. Once the current vehicle green light cycle for the active road is complete (Green -> Yellow -> Red), the system initiates the pedestrian phase.
  4. All vehicle traffic lights turn RED.
  5. The pedestrian signal for the requesting road turns GREEN ("WALK"). Other pedestrian signals remain RED ("DON'T WALK").
  6. After a predefined safe crossing time, the pedestrian signal turns RED ("DON'T WALK"), possibly after a flashing warning phase.
  7. The system resumes normal vehicle traffic light cycles.

System Interaction Mindmap

This mindmap illustrates the key components of the 4-way smart traffic light system and their relationships, providing a high-level overview of its architecture.

mindmap root["4-Way Smart Traffic Light System"] id1["Hardware Components"] id1a["Arduino (Mega/Uno)"] id1b["LEDs (Vehicle & Pedestrian)"] id1c["IR Sensors (x4)"] id1d["Push Buttons (x4)"] id1e["Resistors"] id1f["Power Supply"] id2["Software Logic (Arduino Code)"] id2a["Pin Definitions & Setup"] id2b["Main Loop Control"] id2c["State Machine (Traffic Phases)"] id2d["Vehicle Detection Logic (IR)"] id2e["Pedestrian Request Handling"] id2f["Timing Control (millis())"] id2g["Safety Interlocks"] id3["System Features"] id3a["4-Way Vehicle Control"] id3b["Dynamic Green Time (via IR)"] id3c["Pedestrian Crossing Management"] id3d["Visual Feedback (LEDs)"] id4["Operational Flow"] id4a["Initialization"] id4b["Vehicle Cycle (Green-Yellow-Red)"] id4c["Pedestrian Cycle (Request-Walk-Don't Walk)"] id4d["Sensor Data Processing"] id4e["Road Prioritization"]

Arduino Implementation: The Code

The following Arduino code provides a comprehensive structure for the 4-way traffic light controller with IR sensors and pedestrian features. It uses non-blocking delays (`millis()`) for responsive operation. Pin assignments match the table provided earlier. The IR sensors are assumed to pull their output LOW when an object is detected.

// Define a structure to hold pin numbers for each road's lights and sensors
struct TrafficLightPins {
  int red;      // Vehicle Red LED pin
  int yellow;   // Vehicle Yellow LED pin
  int green;    // Vehicle Green LED pin
  int pedRed;   // Pedestrian Red LED pin
  int pedGreen; // Pedestrian Green LED pin
  int irSensor; // IR Sensor pin
  int pedButton;// Pedestrian Button pin
};

// Array of structures, one for each of the 4 roads (North, East, South, West)
TrafficLightPins roads[4] = {
  // North (Road 0)
  {2, 3, 4, 22, 23, A0, 30},
  // East (Road 1)
  {5, 6, 7, 24, 25, A1, 31},
  // South (Road 2)
  {8, 9, 10, 26, 27, A2, 32},
  // West (Road 3)
  {11, 12, 13, 28, 29, A3, 33}
};

// Timing constants (in milliseconds)
const unsigned long minGreenTime = 10000;  // Minimum green time for vehicles (10s)
const unsigned long yellowTime = 3000;     // Yellow light time (3s)
const unsigned long pedGreenTime = 7000;   // Pedestrian green crossing time (7s)
const unsigned long allRedClearanceTime = 2000; // Brief all-red after yellow/before ped (2s)

// State tracking variables
unsigned long lastChangeTime = 0;       // Stores time of the last major state change
int currentRoad = 0;                    // Index of the road currently having (or about to have) green light for vehicles
bool pedestrianWaiting[4] = {false, false, false, false}; // Flags if a pedestrian is waiting at road i
bool pedestrianCrossingActive = false;  // True if a pedestrian crossing sequence is active
int roadForPedestrian = -1;             // Index of the road where pedestrian crossing is happening

// Enum for main system states to manage traffic flow
enum SystemState { VEHICLE_GREEN, VEHICLE_YELLOW, ALL_RED_TRANSITION, PEDESTRIAN_CROSSING_START, PEDESTRIAN_WALK, PEDESTRIAN_DONT_WALK_CLEARANCE };
SystemState currentSystemState = VEHICLE_GREEN;

void setup() {
  Serial.begin(9600); // Initialize serial communication for debugging

  // Initialize all pins for LEDs as OUTPUTs and sensors/buttons as INPUT_PULLUPs
  for (int i = 0; i < 4; i++) {
    pinMode(roads[i].red, OUTPUT);
    pinMode(roads[i].yellow, OUTPUT);
    pinMode(roads[i].green, OUTPUT);
    pinMode(roads[i].pedRed, OUTPUT);
    pinMode(roads[i].pedGreen, OUTPUT);

    pinMode(roads[i].irSensor, INPUT_PULLUP); // IR sensor: LOW means vehicle detected
    pinMode(roads[i].pedButton, INPUT_PULLUP);   // Pedestrian button: LOW means pressed

    // Initial light states: All vehicle red, all pedestrian red
    digitalWrite(roads[i].red, HIGH);
    digitalWrite(roads[i].yellow, LOW);
    digitalWrite(roads[i].green, LOW);
    digitalWrite(roads[i].pedRed, HIGH);
    digitalWrite(roads[i].pedGreen, LOW);
  }

  // Start with currentRoad (e.g., North) Green
  digitalWrite(roads[currentRoad].red, LOW);
  digitalWrite(roads[currentRoad].green, HIGH);
  lastChangeTime = millis();
  currentSystemState = VEHICLE_GREEN;
  Serial.println("System Initialized. Road " + String(currentRoad) + " GREEN.");
}

// Function to turn all vehicle lights RED and pedestrian lights to DON'T WALK (RED)
void setAllVehiclesRedAllPedRed() {
  for (int i = 0; i < 4; i++) {
    digitalWrite(roads[i].red, HIGH);
    digitalWrite(roads[i].yellow, LOW);
    digitalWrite(roads[i].green, LOW);
    digitalWrite(roads[i].pedRed, HIGH);
    digitalWrite(roads[i].pedGreen, LOW);
  }
}

// Function to set lights for a road going green
void setVehicleGreen(int roadIndex) {
  setAllVehiclesRedAllPedRed(); // First, ensure all others are red
  digitalWrite(roads[roadIndex].red, LOW);
  digitalWrite(roads[roadIndex].green, HIGH);
  digitalWrite(roads[roadIndex].pedRed, HIGH); // Pedestrians on this road see DON'T WALK
  digitalWrite(roads[roadIndex].pedGreen, LOW);
  Serial.println("Road " + String(roadIndex) + " VEHICLE GREEN.");
}

// Function to set lights for a road going yellow
void setVehicleYellow(int roadIndex) {
  digitalWrite(roads[roadIndex].green, LOW);
  digitalWrite(roads[roadIndex].yellow, HIGH);
  Serial.println("Road " + String(roadIndex) + " VEHICLE YELLOW.");
}

// Function to start pedestrian crossing on a specific road
void startPedestrianWalk(int pedRoadIndex) {
  setAllVehiclesRedAllPedRed(); // All vehicle lights red
  // Pedestrian lights: WALK (Green ON) for the specific road, DON'T WALK for others
  for (int i = 0; i < 4; i++) {
    if (i == pedRoadIndex) {
      digitalWrite(roads[i].pedRed, LOW);
      digitalWrite(roads[i].pedGreen, HIGH);
    } else {
      digitalWrite(roads[i].pedRed, HIGH);
      digitalWrite(roads[i].pedGreen, LOW);
    }
  }
  Serial.println("Road " + String(pedRoadIndex) + " PEDESTRIAN WALK.");
}

// Read IR sensor: returns true if vehicle present (sensor output is LOW)
bool isVehicleDetected(int roadIndex) {
  return digitalRead(roads[roadIndex].irSensor) == LOW;
}

// Check pedestrian buttons and update waiting flags
void checkPedestrianButtons() {
  for (int i = 0; i < 4; i++) {
    if (digitalRead(roads[i].pedButton) == LOW && !pedestrianWaiting[i]) {
      pedestrianWaiting[i] = true; // Pedestrian requested crossing
      Serial.println("Pedestrian button pressed for road " + String(i));
    }
  }
}

// Select the next road for green light or a road for pedestrian crossing
// Priority: 1. Pedestrians waiting, 2. Vehicles detected on other roads, 3. Normal cycle.
int determineNextAction(int currentVehicleRoad, int& outPedestrianRoadIndex) {
  outPedestrianRoadIndex = -1; // Reset
  // Check for pedestrian requests first (any road)
  for (int i = 0; i < 4; i++) {
    if (pedestrianWaiting[i]) {
      outPedestrianRoadIndex = i; // Found a pedestrian waiting
      pedestrianWaiting[i] = false; // Clear the request flag
      return PEDESTRIAN_CROSSING_START; // Signal to start pedestrian sequence
    }
  }

  // If no pedestrians, check for vehicles on other roads (simple cycle for now)
  // A more advanced logic could check IR sensors of (currentVehicleRoad + 1), (currentVehicleRoad + 2) etc.
  int nextRoad = (currentVehicleRoad + 1) % 4;
  // For simplicity, we'll just cycle. IR sensor use is primarily for green time extension here.
  return VEHICLE_GREEN; // Signal to go to next vehicle green
}


void loop() {
  unsigned long currentTime = millis();
  checkPedestrianButtons(); // Continuously check pedestrian buttons

  switch (currentSystemState) {
    case VEHICLE_GREEN:
      // Green light is active for 'currentRoad'
      // IR sensor could extend green time here (not implemented in this simplified state timing)
      if (currentTime - lastChangeTime >= minGreenTime) {
        setVehicleYellow(currentRoad);
        currentSystemState = VEHICLE_YELLOW;
        lastChangeTime = currentTime;
      }
      break;

    case VEHICLE_YELLOW:
      if (currentTime - lastChangeTime >= yellowTime) {
        setAllVehiclesRedAllPedRed(); // All vehicles red
        currentSystemState = ALL_RED_TRANSITION;
        lastChangeTime = currentTime;
        Serial.println("All Red Transition after Yellow for Road " + String(currentRoad));
      }
      break;

    case ALL_RED_TRANSITION:
      if (currentTime - lastChangeTime >= allRedClearanceTime) {
        // Decide next action: pedestrian or next vehicle
        int nextActionState = determineNextAction(currentRoad, roadForPedestrian);
        if (nextActionState == PEDESTRIAN_CROSSING_START && roadForPedestrian != -1) {
          pedestrianCrossingActive = true;
          currentSystemState = PEDESTRIAN_WALK;
          startPedestrianWalk(roadForPedestrian);
        } else {
          // No pedestrian, or error, proceed to next vehicle
          pedestrianCrossingActive = false;
          currentRoad = (currentRoad + 1) % 4; // Cycle to next road
          setVehicleGreen(currentRoad);
          currentSystemState = VEHICLE_GREEN;
        }
        lastChangeTime = currentTime;
      }
      break;

    case PEDESTRIAN_WALK:
      if (currentTime - lastChangeTime >= pedGreenTime) {
        // Transition to "Don't Walk" (solid red for pedestrians)
        digitalWrite(roads[roadForPedestrian].pedGreen, LOW);
        digitalWrite(roads[roadForPedestrian].pedRed, HIGH);
        currentSystemState = PEDESTRIAN_DONT_WALK_CLEARANCE;
        lastChangeTime = currentTime;
        Serial.println("Road " + String(roadForPedestrian) + " PEDESTRIAN DON'T WALK (Clearance).");
      }
      break;

    case PEDESTRIAN_DONT_WALK_CLEARANCE:
      // This state is for pedestrian clearance time, typically a flashing "Don't Walk" or just a fixed duration.
      // Here, it's a fixed duration with solid "Don't Walk" (Red).
      if (currentTime - lastChangeTime >= allRedClearanceTime) { // Using allRedClearanceTime as ped clearance
        pedestrianCrossingActive = false;
        roadForPedestrian = -1; // Reset
        // After pedestrian crossing, decide next vehicle road.
        // Could be the road that just had pedestrians, or the next in sequence.
        // For simplicity, we cycle from the last 'currentRoad'.
        currentRoad = (currentRoad + 1) % 4;
        setVehicleGreen(currentRoad);
        currentSystemState = VEHICLE_GREEN;
        lastChangeTime = currentTime;
        Serial.println("Pedestrian cycle complete. Resuming vehicle traffic.");
      }
      break;
  }
}

Code Explanation:

  • Structures and Arrays: TrafficLightPins roads[4] organizes all pin numbers for each road, making the code cleaner and easier to manage.
  • Timing Constants: Durations for green, yellow, and pedestrian walk times are defined as constants for easy adjustment.
  • State Variables: currentSystemState, currentRoad, pedestrianWaiting[], pedestrianCrossingActive, and roadForPedestrian track the system's status.
  • setup(): Initializes serial communication for debugging and configures all pins. It sets initial light states (typically all red for vehicles, then one road green).
  • Helper Functions:
    • setAllVehiclesRedAllPedRed(): Turns all vehicle lights red and pedestrian lights to "Don't Walk".
    • setVehicleGreen(roadIndex) / setVehicleYellow(roadIndex): Control lights for a specific road.
    • startPedestrianWalk(pedRoadIndex): Manages lights for pedestrian crossing.
    • isVehicleDetected(roadIndex): Reads the IR sensor for a given road. (Note: The current main loop's timing for green is fixed; IR detection is primarily for future extension to dynamic green times).
    • checkPedestrianButtons(): Scans all pedestrian buttons.
    • determineNextAction(): Decides whether the next phase is for a pedestrian or the next vehicle road.
  • loop(): This is the heart of the program. It's a state machine driven by currentSystemState and uses millis() for non-blocking time management. It transitions through states like VEHICLE_GREEN, VEHICLE_YELLOW, ALL_RED_TRANSITION (to safely switch or allow pedestrians), and various pedestrian crossing states.
  • IR Sensor Usage: The isVehicleDetected() function is provided. In this version of the code, vehicle detection is mainly for future enhancements like extending green times. The primary logic focuses on timed cycles and pedestrian interrupts. To fully utilize IR sensors for dynamic timing, the VEHICLE_GREEN state would need to check isVehicleDetected(currentRoad) and potentially extend minGreenTime or adjust lastChangeTime.

Visualizing System Attributes

A smart traffic system can be evaluated on several attributes. The radar chart below offers a conceptual comparison between a basic timed system, one with IR sensors, and a comprehensive system including advanced pedestrian priority and adaptive controls.

This chart visualizes how adding features like IR sensors and sophisticated pedestrian handling can improve overall system performance, though potentially increasing complexity and cost.


Further Insights: Video Demonstration

For a practical demonstration of a 4-way traffic light system built with Arduino, the following video provides valuable insights into its construction and operation. While it may not cover all specific features of the code provided here (like individual pedestrian lights per road), it serves as an excellent visual aid for the general concept.

Demonstration of a 4-Way Traffic Light Control System using Arduino.


Frequently Asked Questions (FAQ)

Why use an Arduino Mega instead of an Uno for this project?
How do IR (Infrared) sensors detect vehicles?
What is the advantage of using `millis()` over `delay()` for timing?
How can the green light time be made dynamic based on IR sensor input?

Recommended Further Exploration


References


Last updated May 18, 2025
Ask Ithy AI
Download Article
Delete Article