State machine en verkeerslichten

ik zat te denken om voor mijn volgend project een verkeerslichten project te beginnen.

Eerst maar een "simpel" beginnen met alleen een verkeerslicht en als dat goed werkt een voetgangers licht te maken die met een button werkt.

Nu vroeg ik me af of ik als state machine het beste zoiets als dit als enum kan gebruiken

enum traffic_light { 
   car_red; 
   car_yellow; 
   car_green 
} 

of meer zoiets als :

Enum traffic_light { 
   color:  string 
    time :  int 
    next_color: string 
} 

Vooral omdat ik het later misschien wil uitbreiden naar meerdere verkeerslichten, lichten voor voetgangers, fietsers en een regensensor

Welke is dan een betere beginposition ?

IK heb geprobeerd maar krijg het niet gecompileerd

uint32_t previousMillis;
uint32_t currentMillis = millis();

enum traffic_colors {
  RED,
  GREEN,
  YELLOW,
}

enum traffic_light {
  COLOR color,
  int interval,
  traffic_light next_color(),
};

traffic_light states[1] = {
  { traffic_color: RED, 300, next_color(){ if (currentMillis - previousMillis >= interval){ previousMillis = currentMillis;
return states[2]
}
}
}
}



void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}
C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-4060-1i5rdeq.jw7u\sketch_sep20a\sketch_sep20a.ino:11:9: error: expected '}' before 'color'
   COLOR color,
         ^~~~~
C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-4060-1i5rdeq.jw7u\sketch_sep20a\sketch_sep20a.ino:10:20: note: to match this '{'
 enum traffic_light {
                    ^
C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-4060-1i5rdeq.jw7u\sketch_sep20a\sketch_sep20a.ino:11:9: error: two or more data types in declaration of 'color'
   COLOR color,
         ^~~~~
C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-4060-1i5rdeq.jw7u\sketch_sep20a\sketch_sep20a.ino:12:3: error: expected unqualified-id before 'int'
   int interval,
   ^~~
C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-4060-1i5rdeq.jw7u\sketch_sep20a\sketch_sep20a.ino:14:1: error: expected declaration before '}' token
 };
 ^
exit status 1

Compilation error: expected '}' before 'color'

Simpel gezegd:
arrays, structs en enums zijn uw vrienden.

Ik stel voor dat je eerst ervoor zorgt dat de autoformat in de IDE een redelijk resultaat geeft. Ik denk dat je een hele hoop } op de verkeerde plek hebt staan en mogelijk wat ; mist.

Verder is een enum een type zoals een int; je kunt geen enum maken met verschillende types.

En als laatste kun je geen if buiten functied functies gebruiken.

hmm,

I dacht begrepen te hebben dat next_color een functie moet zijn om van een state-machine te spreken.

Maar als ik dit lees :

C:\Users\rwobb\AppData\Local\Temp\.arduinoIDE-unsaved2025820-19672-1xnx5s1.ya21\sketch_sep20a\sketch_sep20a.ino:19:16: error: 'next_color' cannot be used as a function
     next_color(){
                ^

dan doe ik iets heel verkeerd of heb ik iets heel erg verkeerd begrepen.

Code :

enum traffic_light {
  color,
  interval,
  next_color,
};

Nee, dat is niet zo.

Ik denk dat je verschillende ideeën met elkaar verward.

De eerst enum mist een puntkomma, de tweede enum moet waarschijnlijk een struct of class zijn.

De meest gebruikelijke manier om een state machine te implementeren is het gebruik van een switch/case. Je kunt dan een enum gebruiken om de verschillende states namen te geven.

Ter informatie, de finite state machine waar over gepraat werd in je andere topic (Traffic light. Multiple timers ?) is niet zozeer voor het aansturen van één verkeerslicht maar meer om te bepalen welke verkeerslichten welke kleur moeten tonen onder welke omstandigheden.

Zoals ik daar al heb gezegd is het het beste om eerst een tekening te maken hoe de situatie (bv kruising) eruit ziet. Hieronder een vrij complex voorbeeld.

Als het verkeerslicht voor west naar zuid (7) op groen staat moet je FSM ervoor zorgen dat je op hetzelfde moment het verkeer van noord naar zuid (2) en oost naar zuid (4) op rood staan en dat voetgangerslichten C en D ook rood zijn.
De stoplichten zuid naar noord (5) en zuid naar west (6) kunnen op dat moment ook op groen of het stoplicht oost naar west/noord (3) kan dan ook op groen; je moet er dan wel voor zorgen dat de juiste voetgangerslichten op rood staan.

De FSM neemt ook de tijden voor zijn rekening en het schakelen van groen naar oranje naar rood van één of meerdere verkeerslichten / voetgangerslichten.

PS
De straat komende vanuit het oosten is een eenrichtingsstraat.

Daar wil ik ook aan het toewerken maar eerst even goed snappen hoe dit precies werkt dus wil ik het in kleine stappen hakken.

Denk dat ik het met een switch/case moet doen omdat ik dit niet aan het compileren krijg.

uint32_t previousMillis;
uint32_t currentMillis = millis();

enum traffic_colors {
  RED,
  GREEN,
  YELLOW,
}

struct traffic_light {
  traffic_colors color;
  int interval;
  traffic_light next_color(){};
};

traffic_light states[1] = {
  { traffic_color: RED, 
    300, 
    traffic_light next_color(){ 
      if (currentMillis - previousMillis >= interval){
         previousMillis = currentMillis;
         return states[2] ;
      };
    }
  }
};

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:13:17: error: 'traffic_light traffic_light::next_color()' cannot be overloaded with 'traffic_light traffic_light::next_color()'
   traffic_light next_color(){};
                 ^~~~~~~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:13:15: note: previous declaration 'traffic_light traffic_light::next_color()'
   traffic_light next_color(){};
               ^~~~~~~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino: In member function 'traffic_light traffic_light::next_color()':
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:13:30: warning: no return statement in function returning non-void [-Wreturn-type]
   traffic_light next_color(){};
                              ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino: At global scope:
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:14:2: error: multiple types in one declaration
 };
  ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:19:19: error: expected primary-expression before 'next_color'
     traffic_light next_color(){
                   ^~~~~~~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:19:19: error: expected '}' before 'next_color'
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:17:3: note: to match this '{'
   { traffic_color: RED,
   ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:19:19: error: expected '}' before 'next_color'
     traffic_light next_color(){
                   ^~~~~~~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:16:27: note: to match this '{'
 traffic_light states[1] = {
                           ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:19:19: error: 'traffic_light' has no non-static data member named 'traffic_color'
     traffic_light next_color(){
                   ^~~~~~~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:25:3: error: expected declaration before '}' token
   }
   ^
exit status 1

Compilation error: 'traffic_light traffic_light::next_color()' cannot be overloaded with 'traffic_light traffic_light::next_color()'

In een struct of class kun je geen referentie gebruiken naar diezelfde struct of class. Ik heb daar mijn nek recentelijk over gebroken; ik weet niet meer (:frowning:) hoe ik het (toen) opgelost heb.

uint32_t previousMillis;
uint32_t currentMillis = millis();

enum traffic_colors
{
  RED,
  GREEN,
  YELLOW,
}

struct traffic_light
{
  traffic_colors color;
  int interval;
  traffic_light next_color(){};
};

void setup()
{
  // put your setup code here, to run once:
}

void loop()
{
  // put your main code here, to run repeatedly:
}

geeft hetzelfde probleem.

Ik heb je gisteren ook verteld dat je een puntkomma miste na de eerste enum. Dat is de hoofdoorzaak van je foutmelding voor zover ik kan zien. Daarna geldt hetgeen ik in het vorige antwoord heb gezet.

Dank je

Naar aanleiding van jouw opmerkingen en some googleling heb ik het gecomplieerd gekregen

#include <Arduino.h>

uint32_t previousMillis;
uint32_t currentMillis = millis();

enum traffic_colors {
  RED,
  GREEN,
  YELLOW
};

struct traffic_light {
  traffic_colors color;
  int interval;
  traffic_light* next_color();
};

traffic_light* traffic_light::next_color() {
  return this;
}

void setup() {
  // put your setup code here, to run once:
 
}

void loop() {
 
  // put your main code here, to run repeatedly:
}

maar als ik het idee verder probeer, loop ik weer eens vast

#include <Arduino.h>

uint32_t previousMillis;
uint32_t currentMillis = millis();

enum traffic_colors {
  RED,
  GREEN,
  YELLOW
};

struct traffic_light {
  traffic_colors color;
  int interval;
  traffic_light* next_color();
};


traffic_light states[1] = {
  { traffic_colors: RED, 
    300, 
    traffic_light::next_color() 
  }
};

traffic_light* traffic_light::next_color() {

  if (currentMillis - previousMillis >= interval){
         previousMillis = currentMillis;
         return states[2] ;
      };
  return this;
}

void setup() {
  // put your setup code here, to run once:
 
}

void loop() {
 
  // put your main code here, to run repeatedly:
}
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:22:31: error: cannot call member function 'traffic_light* traffic_light::next_color()' without object
     traffic_light::next_color()
                               ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:24:1: error: 'traffic_light' has no non-static data member named 'traffic_colors'
 };
 ^
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino: In member function 'traffic_light* traffic_light::next_color()':
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:30:25: error: cannot convert 'traffic_light' to 'traffic_light*' in return
          return states[2] ;
                         ^
exit status 1

Compilation error: cannot call member function 'traffic_light* traffic_light::next_color()' without object

Ik kan je niet uitleggen wat er precies verkeerd gaat.

Maar voor mijn gevoel hoort het veranderen van de kleur niet in de traffic_light.

Wat ik waarschijnlijk zou proberen is een tweede struct met daarin een array van traffic_light plaatsen en een functie om de juiste kleur voor een gegeven duur te veranderen.

1 Like

oke

Hier moet ik even over nadenken om te zien wat ik dan precies moet veranderen of hoe dat eruit ziet.

Ik heb zelf geprobeerd op deze manier :

#include <Arduino.h>

unsigned long previousMillis = 0; // track last switch time

enum traffic_colors { RED, GREEN, YELLOW };

struct traffic_light {
  traffic_colors color;
  unsigned long interval;   // milliseconds
  traffic_light* next;      // pointer to next state

  // returns the next state pointer when interval elapsed, otherwise returns this
  traffic_light* next_color() {
    unsigned long now = millis();
    if (now - previousMillis >= interval) {
      previousMillis = now;
      return next;
    }
    return this;
  }
};

traffic_light red; 
traffic_light yellow; 
traffic_light green; 

// Define states once (next will be assigned in setup)
red    = { RED,    3000UL, &green };
green  = { GREEN,  2000UL, &yellow };
yellow = { YELLOW, 1000UL, &red };

traffic_light* currentState = &red;

void setup() {
  Serial.begin(9600);
   currentState = &red;
}

void loop() {
}

` ``
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:28:1: error: 'red' does not name a type
 red    = { RED,    3000UL, &green };
 ^~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:29:1: error: 'green' does not name a type
 green  = { GREEN,  2000UL, &yellow };
 ^~~~~
C:\Users\rwobb\Documents\Arduino\traffic_light\traffic_light.ino:30:1: error: 'yellow' does not name a type
 yellow = { YELLOW, 1000UL, &red };
 ^~~~~~
exit status 1

Compilation error: 'red' does not name a type

Dit moet in setup().

oke

Ik heb een andere oplossing gevonden : https://wokwi.com/projects/442716932892595201

maar nu loop ik hier tegenaan:

sketch.ino: In function 'void loop()':
sketch.ino:44:23: error: switch quantity not an integer
    switch(currentState) {
                       ^
Error during build: exit status 1

Ja, een switch/case kan alleen integers aan in C/C++.

Je moet, als onderdeel van de struct, een functie schrijven die de lichten schakelt. Iets als

struct traffic_light
{
  ...
  ...
  void run()
  {
    ...
    ...
  }
}

Die kun je dan aanroepen met currentState->run(). En geen switch/case nodig.

Hmm, even dan goed nadenken hoe die run functie eruit ziet.

In mijn idee de leds die aan of uit moeten, hangt af van de huidige kleur.

Nee, ik zie het even niet

ik heb :

struct traffic_light {
  traffic_colors color;
  unsigned long interval;   // milliseconds
  traffic_light* next;      // pointer to next state

  traffic_light* next_color() {
    unsigned long now = millis();
    if (now - previousMillis >= interval) {
      previousMillis = now;
      return next;
    }
    return this;
  }

  void run()  {}
};

// Single array — elements can point to other elements in the same array
traffic_light states[3] = {
  { RED,    3000UL, &states[1] }, // states[0] -> states[1]
  { GREEN,  2000UL, &states[2] }, // states[1] -> states[2]
  { ORANGE, 1000UL, &states[0] }  // states[2] -> states[0]
};

Hoe weet ik nu welke led aan of uit moet als ik de huidige state niet weet.