Pedestrian Crossing Using State Machine

Hi,

I'm trying to design a pedestrian crossing using a state machine. The crossing is suppose to be able to detect a button press no matter what the colour of the traffic lights are. i.e. if someone just missed the crossing and pressed the button while the traffic lights were red for cars, the system should remember that and stop traffic in 30s time.

Traffic light sequence is green - orange - red - red &orange - green.

I've managed to create a system that doesn't use the delay() function for timing but i'm not sure how to take it further. It currently has all the same limitations as a similar system that uses the delay() function due to the way I've programmed it.

As is obvious from the post this is my first ever time coding an arduino. Also I have looked at some of the examples (including blinking led) but I think i'm just not getting how to use a state machine. Code is below.

//Declare LEDs


//declare button 
int btnPedestrian = 13;
int btnPedestrian2 = 7;

int red =  2;      
int redstate = LOW;            
unsigned long previoustime1 = 0;        // will store last time LED was updated

 
int orange =  4;     
int orangestate = LOW;           


int green =  6;      
int greenstate = LOW;            


unsigned long orangetimer = 0;
unsigned long redtimer = 0;
unsigned long redorangetimer = 0;
unsigned long test = 0;
int counter =0;
  
void setup (){
  
  
//put set up code here:
  
  pinMode(green, OUTPUT);
  pinMode(orange, OUTPUT);
  pinMode(red, OUTPUT);

  
  //Turn all LEDs off
  digitalWrite(green, LOW);
  digitalWrite(orange, LOW);
  digitalWrite(red, LOW);
  
  
  //Set button to input
  pinMode(btnPedestrian, INPUT);
  pinMode(btnPedestrian2, INPUT);
  
  
 //Serial Monitor
  Serial.begin(9600); 
}
  

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

  
  //Sets light to green if button hasn't been pressed and traffic light isn't orange or red
    if(orangestate == LOW && redstate == LOW && digitalRead(btnPedestrian)==LOW){
        greenstate = HIGH;
        digitalWrite(green, greenstate);
      
    } 
  
  //If light is green and someone presses button  then light will change to orange
      else if   (greenstate == HIGH && redstate == LOW && orangestate == LOW &&digitalRead(btnPedestrian)==HIGH){
 
    greenstate = LOW;  
    orangestate = HIGH;
      
    digitalWrite(orange, orangestate);
      digitalWrite(green, greenstate);
        previoustime1=currenttime;
    }
        
  

  //if light is orange but no red or green then wait 2s then turn red on and orange off
  if (currenttime - previoustime1 >= 2000 && orangestate == HIGH && redstate == LOW && greenstate == LOW){
  orangestate = LOW;
  redstate = HIGH;
    test = currenttime - previoustime1;
    Serial.print(test);
  previoustime1 = currenttime;
  Serial.print(previoustime1);
    
    
    digitalWrite(red, redstate);
    digitalWrite(orange, orangestate);
  
  }
  
  //if light is red but no orange or green then wait 5s then turn orange on
  if (currenttime - previoustime1 >=5000 && redstate == HIGH && greenstate == LOW && orangestate == LOW){
    orangestate = HIGH;
    previoustime1 = currenttime;
    Serial.print(previoustime1);
    
    digitalWrite(orange, orangestate);
  }
  //if light is orange and red for 2s then turn green on and turn red and orange off
  if (currenttime - previoustime1 >= 2000 && orangestate == HIGH && redstate == HIGH && greenstate == LOW){
    redstate = LOW;
    orangestate = LOW;
    greenstate = HIGH;
    
    previoustime1 = currenttime;
    Serial.print(previoustime1);
    
    digitalWrite(orange, orangestate);
    digitalWrite(red, redstate);
    digitalWrite(green, greenstate);
  
  }
  
}
// Pedestrian crossing lights

const int led13Pin =  13;    // LED pin number
const int PgrnPin =  2;      // Pedestrian
const int PredPin =  3;
const int RgrnPin =  5;      // Road
const int RyelPin =  6;
const int RredPin =  7;
const int button1 =  10;     // Button to ground

int led13State = LOW;        // initialise the LED
int PgrnState = LOW;
int PredState = LOW;
int RgrnState = LOW;
int RyelState = LOW;
int RredState = LOW;
char bstate1 = 0;
boolean press = false;

unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long count4 = 0;
unsigned long count5 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

void setout(unsigned long *marker) {
  *marker = millis();             // initialise
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}


void setleds() {
  digitalWrite(led13Pin, led13State);
  digitalWrite(PredPin, PredState);
  digitalWrite(PgrnPin, PgrnState);
  digitalWrite(RredPin, RredState);
  digitalWrite(RyelPin, RyelState);
  digitalWrite(RgrnPin, RgrnState);
}

boolean ispress() { // One-directional read of button - sets but does not clear!
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    press = true;
  } 
  return(press);
}

void setup() {
  Serial.begin(9600);
  pinMode(led13Pin, OUTPUT);      
  pinMode(PgrnPin, OUTPUT);      
  pinMode(PredPin, OUTPUT);      
  pinMode(RgrnPin, OUTPUT);      
  pinMode(RyelPin, OUTPUT);      
  pinMode(RredPin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
  press = false;
  Serial.println("Starting ...");
}

void loop() {
  // All red phase
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Red phase");
  setout(&count3);  
  while (!timeout(&count3, 3000UL )) {
    ispress();  // Check on the button
  }

  // Road Green
  RredState = LOW;
  RyelState = LOW; 
  RgrnState = HIGH; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road green");
  setout(&count3);  
  while (!timeout(&count3, 8000UL )) { // Reasonable time on green
    ispress();  // Check on the button
  }
  Serial.println("Green stale, wait on button");

  while ( press == false )  // Now wait for the button 
  {
    if (timeout(&count2, 300UL )) {
      if (led13State == LOW) {
        led13State = HIGH;
      }
      else {
        led13State = LOW; 
      } 
      digitalWrite(led13Pin, led13State);
    }
    ispress();   
  }
  led13State = LOW; 
  digitalWrite(led13Pin, led13State);

  Serial.println("Button sensed");
  setout(&count3);  
  while (!timeout(&count3, 4000UL )) { // Do not respond immediately!
  }

  // Road Yellow
  RredState = LOW;
  RyelState = HIGH; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road yellow");
  setout(&count3);  
  while (!timeout(&count3, 5000UL )) {
  }

  // Road Red
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road red");
  setout(&count3);  
  while (!timeout(&count3, 3000UL )) {
  }

  // Walk Green
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = LOW;
  PgrnState = HIGH; 
  setleds();
  press = false;  
  Serial.println("Walk");
  setout(&count3);  
  while (!timeout(&count3, 6000UL )) {
  }

  // Flash Don't Walk
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PgrnState = LOW; 
  Serial.println("Flash Don't Walk");
  setout(&count3);  
  while (!timeout(&count3, 7000UL )) {
    if (timeout(&count2, 500UL )) {
      if (PredState == LOW) {
        PredState = HIGH;
      }
      else {
        PredState = LOW; 
      } 
      setleds();
    }
    ispress();  // Check on the button
  }

}

void oldloop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led13State == LOW) {
      led13State = HIGH;
    }
    else {
      led13State = LOW; 
    } 
    digitalWrite(led13Pin, led13State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (PgrnState == LOW) {
      PgrnState = HIGH;
    }
    else {
      PgrnState = LOW; 
    } 
    digitalWrite(PgrnPin, PgrnState);
  } 

  if (timeout(&count3, 600UL )) {
    if (PredState == LOW) {
      PredState = HIGH;
    }
    else {
      PredState = LOW; 
    } 
    digitalWrite(PredPin, PredState);
  } 

  if (timeout(&count4, 400UL )) {
    if (RgrnState == LOW) {
      RgrnState = HIGH;
    }
    else {
      RgrnState = LOW; 
    } 
    digitalWrite(RgrnPin, RgrnState);
  } 

  if (timeout(&count5, 800UL )) {
    if (RredState == LOW) {
      RredState = HIGH;
    }
    else {
      RredState = LOW; 
    } 
    digitalWrite(RredPin, RredState);
  } 
}

Do just try it for a start!

You may find this state machine tutorial helpful.

A few thoughts about this

    if(orangestate == LOW && redstate == LOW && digitalRead(btnPedestrian)==LOW){

Those are the states of the lights rather than the state of the system. I think it would be better to manage the state of the system which could be

CARS_MOVING
PEDESTRIAN_WAITING
CARS_SLOWING
CARS_STOPPED

The progression from one state to the next will probably depend on time

The PEDESTRIAN_WAITING state is a little different because it can overlap the others but none of the other 3 states can overlap each other.

In general there will only be one selection of lights for each of those states so there should be no need to check the individual lights. The way your code is designed now it is as though the system is driven by the lights whereas in reality the lights must obey the system.

Only read the pedestrian button once in every iteration of loop() and save its value.

...R

You need another state machine for the traffic lights.

Did you have a look at Task Makros already?

DrDiettrich:
You need another state machine for the traffic lights.

That implies "different from something". What is the something?

...R

Another here: one more.

DrDiettrich:
Another here: one more.

Maybe it's the glass of wine, but I still don't understand what you mean by "more" - more than what?

...R

The program contains one state machine for the buttons, and another machine should be added for the lights.

DrDiettrich:
The program contains one state machine for the buttons, and another machine should be added for the lights.

OK. That makes things clearer.

I'm not sure that I agree with you. In my mind the states of the lights follow directly from the state of the system. If the system is in X state then that directly implies a particular setting for the lights. For example if the system is in the state CARS_MOVING the light can only be green.

...R

It can be done with a single state machine plus a flag for the pedestrian button that gets set when it's pressed.

When pedestrian button pressed: BUTTON_PRESSED = true, and set the time it happened. Ignore any further presses until BUTTON_PRESSED is set to false again.

You'd cycle through these states:

  1. lights green - default state.
  2. Some specific time after the button got pressed: turn lights yellow for some time, then red.
  3. Some time after lights red: turn pedestrian light green.
  4. After some time passed: pedestrian light flashing. Set BUTTON_PRESSED = false to start recording button presses again, and if pressed set the time it happened.
  5. After some time passed: pedestrian light red.
  6. After some time passed: car lights red+yellow.
  7. After some time passed: car lights green.

You'd get a few more states if it's an intersection.

I admit that I've been confused by the code of Paul_B, and the fact that no state variable and switch has been used for the light state.

wvmarle just presented the states of the lights machine which I also had in mind. The LED states then reflect that state variable, updated with every change of the state variable.

"Doctors differ and patients die"

...R

DrDiettrich:
I admit that I've been confused by the code of Paul_B, and the fact that no state variable and switch has been used for the light state.

It is in fact, not "state machine" code as the nature of this particular problem does not need an overall state machine - not that you can or should not use one. The button code is a state machine.

It is simple (well, perhaps not quite :grinning: ) linear code where the main loop() performs the phases step by step. It takes into account that the button needs to be monitored only during two particular phases - while the "Don't Walk" is flashing and while the road is green. The button is irrelevant at any other time notwithstanding what pedestrians may imagine or do. :roll_eyes:

My apologies - it contains some dross left there purely for my own reference; I didn't notice before since I have not worked on the code for several years. Here is the cleaned-up version:

// Pedestrian crossing lights    ** Paul B. **

const int led13Pin =  13;    // LED pin number
const int PgrnPin =  6;
const int PredPin =  5;
const int RgrnPin =  4;
const int RyelPin =  3;
const int RredPin =  2;
const int button1 =  10;

int led13State = LOW;        // initialise the LED
int PgrnState = LOW;
int PredState = LOW;
int RgrnState = LOW;
int RyelState = LOW;
int RredState = LOW;
char bstate1 = 0;
boolean press = false;

unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long count4 = 0;
unsigned long count5 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

void setout(unsigned long *marker) {
  *marker = millis();             // initialise
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}


void setleds() {
  digitalWrite(led13Pin, led13State);
  digitalWrite(PredPin, PredState);
  digitalWrite(PgrnPin, PgrnState);
  digitalWrite(RredPin, RredState);
  digitalWrite(RyelPin, RyelState);
  digitalWrite(RgrnPin, RgrnState);
}

boolean ispress() { // One-directional read of button - sets but does not clear!
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    press = true;
  } 
  return(press);
}

void setup() {
  Serial.begin(9600);
  pinMode(led13Pin, OUTPUT);      
  pinMode(PgrnPin, OUTPUT);      
  pinMode(PredPin, OUTPUT);      
  pinMode(RgrnPin, OUTPUT);      
  pinMode(RyelPin, OUTPUT);      
  pinMode(RredPin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
  press = false;
  Serial.println("Starting ...");
}

void loop() {
  // All red phase
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Red phase");
  setout(&count3);  
  while (!timeout(&count3, 3000UL )) {
    ispress();  // Check on the button
  }

  // Road Green
  RredState = LOW;
  RyelState = LOW; 
  RgrnState = HIGH; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road green");
  setout(&count3);  
  while (!timeout(&count3, 8000UL )) { // Reasonable time on green
    ispress();  // Check on the button
  }
  Serial.println("Green stale, wait on button");

  while ( press == false )  // Now wait for the button 
  {
    if (timeout(&count2, 300UL )) {
      if (led13State == LOW) {
        led13State = HIGH;
      }
      else {
        led13State = LOW; 
      } 
      digitalWrite(led13Pin, led13State);
    }
    ispress();   
  }
  led13State = LOW; 
  digitalWrite(led13Pin, led13State);

  Serial.println("Button sensed");
  setout(&count3);  
  while (!timeout(&count3, 4000UL )) { // Do not respond immediately!
  }

  // Road Yellow
  RredState = LOW;
  RyelState = HIGH; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road yellow");
  setout(&count3);  
  while (!timeout(&count3, 5000UL )) {
  }

  // Road Red
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = HIGH;
  PgrnState = LOW; 
  setleds();
  Serial.println("Road red");
  setout(&count3);  
  while (!timeout(&count3, 3000UL )) {
  }

  // Walk Green
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PredState = LOW;
  PgrnState = HIGH; 
  setleds();
  press = false;  
  Serial.println("Walk");
  setout(&count3);  
  while (!timeout(&count3, 6000UL )) {
  }

  // Flash Don't Walk
  RredState = HIGH;
  RyelState = LOW; 
  RgrnState = LOW; 
  PgrnState = LOW; 
  Serial.println("Flash Don't Walk");
  setout(&count3);  
  while (!timeout(&count3, 7000UL )) {
    if (timeout(&count2, 500UL )) {
      if (PredState == LOW) {
        PredState = HIGH;
      }
      else {
        PredState = LOW; 
      } 
      setleds();
    }
    ispress();  // Check on the button
  }

}

Hi everyone,

Thanks for the helpful replies. I've developed code which satisfies this problem, using a state machine (I think). I've also incorporated a proximity detection system much like the real "puffin" crossing that this particular pedestrian crossing is based on.

I've attached the code below, maybe it can be more efficiently written?

Again thanks for everyone's help.

Note: Timings are not realistic

//Lewis W
//Design 3
//24/03/2019
//This code has no known design flaws. Arduino can respond to sensor inputs in all scenarios

//Note: DETECT indicates section of code which can actively detect button state changes 

//Declare pins
const int wait =  13;    
const int Pgreen =  2;
const int Pred =  3;
const int green =  5;
const int amber =  6;
const int red =  7;
const int button1 =  10;
const int button2 = 11;
const int trigPin = 12;
const int echoPin = 11;

 // Set LED states
int greenState = LOW;
int redState = LOW;
int amberState= LOW;
int PredState = LOW;
int PgreenState = LOW;
int waitState = LOW;
int greenred = LOW;

//Set states of state machine
int cars_moving = LOW;
int cars_slowing = LOW;
int cars_stopped = LOW;
int cars_leaving = LOW;
int pedestrian_waiting = LOW;
int pedestrian_crossing = LOW;
int pedestrian_crossingend = LOW;

// Set up counters/timers
int presscounter = 0;
unsigned long previoustime;
unsigned long waittime;

void setup () {
  
//Declare outputs
pinMode(Pgreen, OUTPUT);
pinMode(Pred, OUTPUT);
pinMode(green, OUTPUT);
pinMode(amber, OUTPUT);
pinMode(red, OUTPUT);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
pinMode(wait, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
 
  
//Set states of state machine
cars_moving = HIGH;
  
//Start Serial Monitor to monitor certain output/inputs
Serial.begin(9600);
}

void loop () {
  
  //Declares clock for all timings
  unsigned long counter = millis();

  
//Declares car_moving state - DETECT
  if (cars_moving == HIGH){
  Serial.print(presscounter);
     
  redState = LOW;
  amberState = LOW;    
  greenState = HIGH;
  PredState = HIGH;
    
  digitalWrite(green, greenState);
  digitalWrite(Pred, PredState);
  digitalWrite(red, redState);
  digitalWrite(amber, amberState);
    
    //Reads for button press
    if (digitalRead (button1) == HIGH){
      
      presscounter = 1;
        waitState=HIGH;
      digitalWrite(wait,waitState);
      waittime=counter;
    }
     
  
    
    //used to determine distance 
  long duration, distance;
  digitalWrite(trigPin,HIGH);
  delayMicroseconds(3000);
  digitalWrite(trigPin, LOW);
  duration=pulseIn(echoPin, HIGH);
  distance =(duration/2)*0.0343;
  
    //turns of wait light after expired time
    if (counter - waittime >= 4000 && waitState==HIGH){
      presscounter = 0; 
        waitState=LOW;
      digitalWrite(wait,waitState);
      waittime=counter;
    }  
    
   
    //block pedestrian crossing for 30s 
    if (counter - previoustime >=3000){
      

      if ((digitalRead (button1) == HIGH && distance < 100) || (presscounter > 0 && distance <100)){
 	  greenred = HIGH;
      Serial.print(button1); 
      presscounter=0;
      previoustime = counter;
      cars_moving = LOW;
    }
    }
  }
  
  //Add 2 second transistion gap (greenred state)
  
  if (greenred == HIGH){
    
    if (counter - previoustime >=2000){
      
     greenred = LOW;
     cars_slowing = HIGH;
     pedestrian_waiting = HIGH;
     
     previoustime = counter;
    }
  }
  
  
//Declare cars_slowing state
  if (cars_slowing == HIGH && pedestrian_waiting) {
    greenState = LOW;
    amberState= HIGH;
    PredState = HIGH;
    
    digitalWrite(Pred, PredState);
	digitalWrite(green, greenState);
  	digitalWrite(amber, amberState);
    
    if (counter - previoustime >=2000){ 
    cars_slowing = LOW;
    cars_stopped = HIGH;
    previoustime=counter;
    }
  }
  
  
  //Declare Cars stopped 
  if (cars_stopped == HIGH){
  
    amberState=LOW;
    PredState = HIGH;
    redState = HIGH;
      
    digitalWrite(red, redState);
    digitalWrite(Pred, PredState);
  	digitalWrite(amber, amberState);
    
    if (counter - previoustime >= 2000){
      cars_stopped = LOW;
      pedestrian_crossing = HIGH;
      previoustime = counter;
    }
    
   }
  
  //Declare pedestrian_crosssing
  if (pedestrian_crossing == HIGH){
    
    waitState=LOW;  
    redState = HIGH;
    PredState = LOW;
    PgreenState = HIGH;
    
    digitalWrite(Pgreen, PgreenState);
  	digitalWrite(red, redState);
    digitalWrite(Pred, PredState);
  	digitalWrite(wait,waitState);
    
    if (counter - previoustime >= 2000){
      
      pedestrian_crossing = LOW;
      pedestrian_crossingend = HIGH;
      previoustime = counter;
      
    }
   }
  
  
  //Declare pedestrian_crossingend -- DETECT
  
  if (pedestrian_crossingend == HIGH){
   
   PredState = HIGH;
   PgreenState = LOW;
    
    digitalWrite(Pgreen, PgreenState);
    digitalWrite(Pred, PredState);
    
    if (digitalRead (button1) == HIGH){
      
      presscounter = 1;
      waitState=HIGH;
      digitalWrite(wait,waitState);  
    }
    
    //2s delay before lights change
    if (counter-previoustime >= 2000){
      
      pedestrian_crossingend = LOW;
      cars_leaving = HIGH;
      previoustime = counter;
      
      
    
  }
  }
  
  //Declare cars_leaving -- DETECT
  if (cars_leaving == HIGH) {

  redState = HIGH;
  amberState = HIGH;    
 
  digitalWrite(red, redState);
  digitalWrite(amber, amberState);
   
    if (digitalRead (button1) == HIGH){
      presscounter = 1;
        waitState=HIGH;
      digitalWrite(wait,waitState);
      Serial.print(presscounter);
    }
    
    if (counter-previoustime >= 2000){
     cars_leaving = LOW;
      cars_moving = HIGH;
      previoustime = counter;
      waittime=counter;
 
    } 
         
  
  }
 }

A state machine does not consist of a lot of ...state variables, but is based on only one state variable.