Arduino cursus/Verkeerslichten

Uit Lab
Naar navigatie springen Naar zoeken springen

Verkeerslichten

We beschrijven hier de verkeerslichtenregeling voor een eenvoudig kruispunt van twee gelijkwaardige wegen, NS (noord-zuid) en WE (west-oost). We beginnen met een eenvoudige tijd-gebaseerde regeling.

  • de eerste versie gebruikt de delay-functie;
  • de tweede versie gebruikt timers, in plaats van delays. Dit maakt het mogelijk om andere taken tegelijk uit te voeren: dit hebben we nodig voor de uitbreiding met het voetgangerslicht.
    • deze timer-versie is een voorbeeld van een eindige automaat, met 4 toestanden.
  • vervolgens maken we een regeling voor een voetgangerslicht. Dit wordt geactiveerd door een drukknop.
  • We voorzien het voetgangerslicht van een tikker; hiervoor gebruiken we de tikker die elders beschreven is.
  • Daarna combineren we de regeling voor het kruispunt en de regeling voor het voetgangerslicht.

Eenvoudige regeling (met delay)

We beginnen met een eenvoudige regeling:

  • kruispunt van twee wegen: NS (north-south) en WE (west-east)
  • regeling gebaseerd op tijd; geen verkeersafhankelijke regeling

Het regeling wordt dan:

void loop() {
  nsGreen();
  delay(10000);
  nsYellow();
  delay(2000);
  weGreen();
  delay(10000);
  weYellow();
  delay(2000);
}

Het volledige programma:

const unsigned long greenPeriod = 10000L;
const unsigned long yellowPeriod = 2000L;

int nsRedPin = 13;
int nsYellowPin = 12;
int nsGreenPin = 11;

int weRedPin = 10;
int weYellowPin = 9;
int weGreenPin = 8;

void allOff() {
  digitalWrite(nsRedPin, LOW);
  digitalWrite(nsYellowPin, LOW);
  digitalWrite(nsGreenPin, LOW);

  digitalWrite(weRedPin, LOW);
  digitalWrite(weYellowPin, LOW);
  digitalWrite(weGreenPin, LOW);
}

void nsGreen() {
  allOff();
  digitalWrite(nsGreenPin, HIGH);
  digitalWrite(weRedPin, HIGH);
}

void weGreen() {
  allOff();
  digitalWrite(nsRedPin, HIGH);
  digitalWrite(weGreenPin, HIGH);
}

void weYellow() {
  allOff();
  digitalWrite(nsRedPin, HIGH);
  digitalWrite(weYellowPin, HIGH);
}

void nsYellow() {
  allOff();
  digitalWrite(nsYellowPin, HIGH);
  digitalWrite(weRedPin, HIGH);
}

void setup() {
  pinMode(nsRedPin, OUTPUT);
  pinMode(nsYellowPin, OUTPUT);
  pinMode(nsGreenPin, OUTPUT);

  pinMode(weRedPin, OUTPUT);
  pinMode(weYellowPin, OUTPUT);
  pinMode(weGreenPin, OUTPUT);

  allOff();
}

void loop() {
  nsGreen();
  delay(greenPeriod);
  nsYellow();
  delay(yellowPeriod);
  weGreen();
  delay(greenPeriod);
  weYellow();
  delay(yellowPeriod);
}

Eenvoudige regeling (met timer)

We kunnen het bovenstaande programma omzetten in een versie met een timer. We beschouwen de regeling dan als een eindige automaat, met 4 toestanden: nsGreenState, nsYellowState, weGreenState, en weYellowState.

Elke toestandsovergang heeft dan een conditie van de vorm state == X && now - timerStart >= timerPeriod.

unsigned long timerStart;
unsigned long yellowPeriod = 2000L;
unsigned long greenPeriod = 10000L;

enum TrafficState = {allRedState, nsGreenState, nsYellowState, weGreenState, weYellowState};

TrafficState state;

void loop() {
  unsigned long now = millis();
  if (state == weYellowState && now - timerStart >= yellowPeriod) {
    nsGreen();
    state = nsGreenState;
    timerStart = now;
  }
  if (state == nsGreenState && now - timerStart >= greenPeriod) {
    nsYellow();
    state = nsYellowState;
    timerStart = now;
  }
  if (state == nsYellowState && now - timerStart >= yellowPeriod) {
    weGreen();
    state = weGreenState;
    timerStart = now;
  }
  if (state == weGreenState && now - timerStart >= greenPeriod) {
    weYellow();
    state = weYellowState;
    timerStart = now;
  }
}

Merk op dat de volgorde van de overgangen (if-statements) in het programma geen gevolgen heeft voor de werking.

Voetgangerslicht

We maken eerst een voetgangerslicht; dit combineren we in een volgende stap met de regeling voor het kruispunt - waarbij het voetgangerslicht alleen groen mag zijn tegelijk met groen licht voor WE.

  • het voetgangerslicht wordt geactiveerd met een knop;
  • het voetgangerslicht mag alleen op groen gezet worden als er nog voldoende groen-tijd voor de parallelle weg is (en dus rood voor de kruisende weg).
  • naast het licht geeft een tikker de toestand van het voetgangerslicht aan.
    • de tikfrequentie is 70 tikken/minuut voor rood, en 180 tikken/minuut voor groen
    • zie:
  • het voetgangerslicht heeft alleen rood en groen
    • (verfijning) ;ater kunnen we als waarschuwing voor de groen-rood overgang het groene licht een korte tijd laten knipperen.
  • als het licht voor de voetgangers op rood gaat moeten de voetgangers op de weg nog voldoende tijd hebben om de weg vrij te maken.

Voor de timer van het voetgangerslicht gebruiken we een variabele pedPeriod; deze passen we aan bij de verschillende overgangen.

Door het gebruik van deze variabele kunnen we bijvoorbeeld een periode eenvoudig inkorten of verlengen, tijdens deze periode. We kunnen een timer ook stopzetten. (Vgl. ook de manier waarop we de periode gebruiken bij de tikker.)

Basisprogramma voor het voetgangerslicht:

void loop() {
  if buttonPushed() {
    if (state == nsGreen && restTime >= pedPeriod) {
      
    } else { }
  } else { }
}

Ook voor het voetgangerslicht werken we weer met toestanden:

  • pedRed
  • pedGreen
  • pedRest
  • pedWait

Het indrukken van de knop heeft alleen effect op het moment dat het licht rood is (of gedoofd...).

unsigned long pedGreenPeriod = 2000;
unsigned long pedYellowPeriod = 2000; // tijd om over te steken
unsigned long pedTotalPeriod = pedGreenPeriod + pedYellowPeriod;

unsigned long tikkerTimerStart = 0;
unsigned long tikkerPeriod = 1000000L;

unsigned long greenTikkerPeriod = 300L;
unsigned long redTikkerPeriod = 1000L;

const int buzzerPin = 7;
const int buttonPin = 6;
const int pedRedPin = 5;
const int pedYellowPin = 4;
const int pedGreenPin = 3;

enum PedState {pedRedWait, pedRed, pedGreen, pedYellow};
PedState state = pedRed;

void pedRedLight() {
  digitalWrite(
}

void setUp() {
  pinMode(buzzerPin, OUTPUT);
  pinMode(buttonPin, OUTPUT);
  pinMode(pedRedPin, OUTPUT);
  pinMode(pedYellowPin, OUTPUT);
  pinMode(pedGreenPin, OUTPUT);

  state = pedRed;
  pedRedLight();
}

void loop() {
  unsigned long now = millis();

  int button = digitalRead(buttonPin);
  if (state == pedRed && prevButton == LOW && button == HIGH) {
    state = pedRedWait;
    tikkerPeriod = redTikkerPeriod;
    pedRedLight();
  }
  prevButton = button;

  if (state == pedRedWait && restTime >= pedTotalPeriod) {
    state = pedGreen;
    tikkerPeriod = greenTikkerPeriod;
    pedGreenLight();
    perTimerStart = now;
    
  }
  if (state == pedGreen && now - pedTimerStart >= pedGreenPeriod) {
    state = pedYellow;
    pedYellowLight();
    tikkerPeriod = yellowTikkerPeriod;
    pedTimerStart = now;
  }
  if (state == pedYellow && now - pedTimerStart >= pedYellowPeriod) {
    state = pedRed;
    pedRedLight();
    pedTimerStart = now;
  }

  if (millis() - tikkerTimerStart >= tikkerPeriod) {
    digitalWrite(buzzerPin, HIGH);
    delay(2);
    digitalWrite(buzzerPin, LOW);
    tikkerTimerStart = tikkerTimerStart + tikkerPeriod;  
  }
}

Complete programma: verkeerslichten met voetgangerslicht

We geven hieronder het complete programma voor de verkeerslichten met voetgangerslicht.