// Arduino Racing Traffic Light Sketch
// Drag Racing Semaphore System
#include <IRremote.hpp>
// Pin definitions
const int WHITE_LED = D1;
const int RED_LED = D2;
const int GREEN_LED = D3;
const int YELLOW_LED_1 = D4;
const int YELLOW_LED_2 = D5;
const int YELLOW_LED_3 = D6;
const int PROXIMITY_SENSOR = D7;
const int BUZZER = D8;
const int IR_RECEIVER = D9;
// IR Remote button codes (NEC protocol - wokwi-ir-remote)
const uint8_t IR_BUTTON_1 = 48;
const uint8_t IR_BUTTON_2 = 24;
const uint8_t IR_BUTTON_3 = 122;
const uint8_t IR_BUTTON_4 = 16;
const uint8_t IR_BUTTON_5 = 56;
const uint8_t IR_BUTTON_6 = 90;
const uint8_t IR_BUTTON_7 = 66;
const uint8_t IR_BUTTON_8 = 74;
const uint8_t IR_BUTTON_9 = 82;
const uint8_t IR_BUTTON_POWER = 162;
// Proximity sensor state
bool proximitySensorEnabled = true;
// State definitions
enum State {
WAITING,
RED_BLINKING,
YELLOW_SEQUENCE,
RANDOM_DELAY_STATE,
GREEN_LIGHT,
DELAY_STATE
};
State currentState = WAITING;
unsigned long previousMillis = 0;
unsigned long stateStartTime = 0;
int redBlinkDuration = 0;
int randomDelayDuration = 0;
int yellowStep = 0;
bool ledState = false;
void setup() {
// Initialize Serial communication
Serial.begin(9600);
Serial.println("=== Arduino Racing Traffic Light System ===");
Serial.println("Initializing...");
// Initialize all LED pins as outputs
pinMode(WHITE_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(YELLOW_LED_1, OUTPUT);
pinMode(YELLOW_LED_2, OUTPUT);
pinMode(YELLOW_LED_3, OUTPUT);
pinMode(BUZZER, OUTPUT);
// Initialize proximity sensor as input
pinMode(PROXIMITY_SENSOR, INPUT);
// Turn off all LEDs
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(YELLOW_LED_1, LOW);
digitalWrite(YELLOW_LED_2, LOW);
digitalWrite(YELLOW_LED_3, LOW);
digitalWrite(BUZZER, LOW);
// Turn on white LED to indicate proximity sensor is enabled
digitalWrite(WHITE_LED, HIGH);
// Initialize random seed
randomSeed(analogRead(A0));
// Initialize IR receiver
IrReceiver.begin(IR_RECEIVER, ENABLE_LED_FEEDBACK);
Serial.println("IR Receiver initialized on pin D9");
Serial.println("Press 1-9 on IR remote to set countdown time and start race");
// Start in waiting mode
currentState = WAITING;
previousMillis = millis();
Serial.println("System initialized successfully");
Serial.println("Entering WAITING mode...");
Serial.println("---");
}
void loop() {
unsigned long currentMillis = millis();
switch (currentState) {
case WAITING:
handleWaitingMode(currentMillis);
break;
case RED_BLINKING:
handleRedBlinking(currentMillis);
break;
case YELLOW_SEQUENCE:
handleYellowSequence(currentMillis);
break;
case RANDOM_DELAY_STATE:
handleRandomDelayState(currentMillis);
break;
case GREEN_LIGHT:
handleGreenLight(currentMillis);
break;
case DELAY_STATE:
handleDelayState(currentMillis);
break;
}
}
// Helper function to convert IR command to seconds (1-9)
int getSecondsFromIRCommand(uint8_t command) {
switch (command) {
case IR_BUTTON_1: return 1;
case IR_BUTTON_2: return 2;
case IR_BUTTON_3: return 3;
case IR_BUTTON_4: return 4;
case IR_BUTTON_5: return 5;
case IR_BUTTON_6: return 6;
case IR_BUTTON_7: return 7;
case IR_BUTTON_8: return 8;
case IR_BUTTON_9: return 9;
default: return 0; // Unknown button
}
}
void handleWaitingMode(unsigned long currentMillis) {
// Slow blinking green LED (500ms interval)
if (currentMillis - previousMillis >= 500) {
previousMillis = currentMillis;
ledState = !ledState;
digitalWrite(GREEN_LED, ledState ? HIGH : LOW);
Serial.print("GREEN LED: ");
Serial.print(ledState ? "ON" : "OFF");
Serial.println(" - Reason: Waiting mode slow blink");
}
// Check for IR remote signal
if (IrReceiver.decode()) {
uint8_t command = IrReceiver.decodedIRData.command;
int irSeconds = getSecondsFromIRCommand(command);
Serial.println("\n*** IR REMOTE DECODE ***");
if (irSeconds > 0) {
Serial.println("\n*** IR REMOTE TRIGGERED ***");
Serial.print("Button pressed: ");
Serial.println(irSeconds);
// Turn off green LED
digitalWrite(GREEN_LED, LOW);
Serial.println("GREEN LED: OFF - Reason: IR command received, starting race sequence");
// Set red blink duration based on IR button (1-9 seconds)
redBlinkDuration = irSeconds * 1000;
Serial.print("Red blink duration: ");
Serial.print(redBlinkDuration);
Serial.println(" ms");
// Transition to red blinking state
currentState = RED_BLINKING;
stateStartTime = currentMillis;
previousMillis = currentMillis;
ledState = false;
Serial.println("State: RED_BLINKING");
Serial.println("---");
} else if (command == IR_BUTTON_POWER) {
// Toggle proximity sensor enabled state
proximitySensorEnabled = !proximitySensorEnabled;
// Update white LED to reflect proximity sensor state
digitalWrite(WHITE_LED, proximitySensorEnabled ? HIGH : LOW);
Serial.println("\n*** POWER BUTTON PRESSED ***");
Serial.print("Proximity sensor: ");
Serial.println(proximitySensorEnabled ? "ENABLED" : "DISABLED");
Serial.print("WHITE LED: ");
Serial.println(proximitySensorEnabled ? "ON" : "OFF");
Serial.println("---");
}
IrReceiver.resume(); // Enable receiving of the next value
}
// Check for proximity sensor trigger (only if enabled)
if (proximitySensorEnabled && digitalRead(PROXIMITY_SENSOR) == HIGH) {
Serial.println("\n*** PROXIMITY SENSOR TRIGGERED ***");
// Turn off green LED
digitalWrite(GREEN_LED, LOW);
Serial.println("GREEN LED: OFF - Reason: Proximity detected, starting race sequence");
// Generate random duration for red blinking (3-6 seconds)
redBlinkDuration = random(3000, 6001);
Serial.print("Red blink duration: ");
Serial.print(redBlinkDuration);
Serial.println(" ms");
// Transition to red blinking state
currentState = RED_BLINKING;
stateStartTime = currentMillis;
previousMillis = currentMillis;
ledState = false;
Serial.println("State: RED_BLINKING");
Serial.println("---");
}
}
void handleRedBlinking(unsigned long currentMillis) {
// Blink red LED with 250ms interval
if (currentMillis - previousMillis >= 250) {
previousMillis = currentMillis;
ledState = !ledState;
digitalWrite(RED_LED, ledState ? HIGH : LOW);
Serial.print("RED LED: ");
Serial.print(ledState ? "ON" : "OFF");
Serial.println(" - Reason: Pre-race countdown blinking");
}
// Check if red blinking duration has elapsed
if (currentMillis - stateStartTime >= redBlinkDuration) {
// Turn off red LED
digitalWrite(RED_LED, LOW);
Serial.println("RED LED: OFF - Reason: Red blinking complete, starting yellow sequence");
// Transition to yellow sequence
currentState = YELLOW_SEQUENCE;
stateStartTime = currentMillis;
yellowStep = 0;
Serial.println("\nState: YELLOW_SEQUENCE");
Serial.println("---");
}
}
void handleYellowSequence(unsigned long currentMillis) {
unsigned long elapsed = currentMillis - stateStartTime;
// Sequential yellow LED activation (1 second each)
if (yellowStep == 0 && elapsed >= 0) {
digitalWrite(YELLOW_LED_1, HIGH);
tone(BUZZER, 600, 200); // First beep: 800Hz for 200ms
Serial.println("YELLOW LED 1: ON - Reason: First stage of countdown (3 seconds to go)");
Serial.println("BUZZER: Beep 800Hz - Reason: First countdown tone");
yellowStep = 1;
}
else if (yellowStep == 1 && elapsed >= 1000) {
digitalWrite(YELLOW_LED_2, HIGH);
tone(BUZZER, 600, 200); // Second beep: 600Hz for 200ms
Serial.println("YELLOW LED 2: ON - Reason: Second stage of countdown (2 seconds to go)");
Serial.println("BUZZER: Beep 600Hz - Reason: Second countdown tone");
yellowStep = 2;
}
else if (yellowStep == 2 && elapsed >= 2000) {
digitalWrite(YELLOW_LED_3, HIGH);
tone(BUZZER, 600, 200); // Third beep: 400Hz for 200ms
Serial.println("YELLOW LED 3: ON - Reason: Third stage of countdown (1 second to go)");
Serial.println("BUZZER: Beep 400Hz - Reason: Third countdown tone");
yellowStep = 3;
}
else if (yellowStep == 3 && elapsed >= 3000) {
Serial.println("\n*** ALL YELLOW LEDS ON! ***");
// Generate random delay between 0.5 and 1.5 seconds (500-1500 ms)
randomDelayDuration = random(500, 1501);
Serial.print("Random delay before green light: ");
Serial.print(randomDelayDuration);
Serial.println(" ms");
// Transition to random delay state
currentState = RANDOM_DELAY_STATE;
stateStartTime = currentMillis;
Serial.println("\nState: RANDOM_DELAY_STATE");
Serial.println("---");
}
}
void handleRandomDelayState(unsigned long currentMillis) {
// Wait for random delay duration
if (currentMillis - stateStartTime >= randomDelayDuration) {
Serial.println("\n*** RACE START! ***");
// Turn on green LED
digitalWrite(GREEN_LED, HIGH);
Serial.println("GREEN LED: ON - Reason: GO! Race started!");
// Race start sound: 3 short beeps
tone(BUZZER, 800, 200); // First beep: 800Hz for 200ms
delay(250);
tone(BUZZER, 800, 200); // Second beep: 800Hz for 200ms
delay(250);
tone(BUZZER, 800, 200); // Third beep: 800Hz for 200ms
Serial.println("BUZZER: 3 short beeps at 800Hz - Reason: Race start signal!");
// Transition to green light state
currentState = GREEN_LIGHT;
stateStartTime = currentMillis;
Serial.println("\nState: GREEN_LIGHT");
Serial.println("---");
}
}
void handleGreenLight(unsigned long currentMillis) {
// Turn off all yellow LEDs
digitalWrite(YELLOW_LED_1, LOW);
Serial.println("YELLOW LED 1: OFF - Reason: Countdown complete, preparing for race start");
digitalWrite(YELLOW_LED_2, LOW);
Serial.println("YELLOW LED 2: OFF - Reason: Countdown complete, preparing for race start");
digitalWrite(YELLOW_LED_3, LOW);
Serial.println("YELLOW LED 3: OFF - Reason: Countdown complete, preparing for race start");
// Wait for 5 seconds with green LED on
if (currentMillis - stateStartTime >= 2000) {
// Turn off green LED
digitalWrite(GREEN_LED, LOW);
Serial.println("\nGREEN LED: OFF - Reason: Race time complete (5 seconds elapsed)");
// Transition to delay state before returning to waiting
currentState = DELAY_STATE;
stateStartTime = currentMillis;
Serial.println("State: DELAY_STATE");
Serial.println("---");
}
}
void handleDelayState(unsigned long currentMillis) {
// Small delay to ensure clean transition
if (currentMillis - stateStartTime >= 100) {
// Return to waiting mode
currentState = WAITING;
previousMillis = currentMillis;
ledState = false;
Serial.println("\nReturning to WAITING mode...");
Serial.println("System ready for next race");
Serial.println("===================================\n");
}
}
Loading
xiao-esp32-s3
xiao-esp32-s3