Arduino cursus/Verkeerslichten

Uit Lab
< Arduino cursus
Versie door Eelco (overleg | bijdragen) op 19 nov 2017 om 10:26 (Nieuwe pagina aangemaakt met '== Verkeerslichten == We beschrijven hier de verkeerslichtenregeling voor een eenvoudig kruispunt van twee gelijkwaardige wegen, NS (noord-zuid) en WE (west-oost)....')
(wijz) ← Oudere versie | Huidige versie (wijz) | Nieuwere versie → (wijz)
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.

Toevoeging: voetgangerslicht

We maken eerst een voetgangerslicht, voor een overgang in de weg WE; dit combineren we in een volgende stap met de regeling voor het kruispunt.

  • het voetgangerslicht mag alleen op groen gezet worden als de WE-lichten nog tenminste pedPeriod groen zijn.
  • het voetgangerslicht wordt geactiveerd met een knop;
  • naast het licht geeft een tikker de toestand van het voetgangerslicht aan.
  • (verfijning) het licht voor de voetgangers gaat eerder op rood dan de totale tijd voor het oversteken. (We kunnen het licht ook laten knipperen: de "yellow"period.)

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
  • pedYellow
  • 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;
unsigned long pedTotalPeriod = pedGreenPeriod + pedYellowPeriod;

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

unsigned long greenTikkerPeriod = 300L;
unsigned long yellowTikkerPeriod = 100L;
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;  
  }
}