There had been some requests to also do a UK crossing. The UK version has a couple of extra steps. First there is a yellow light, then there are two red lights and only then the red lights start blinking and then the gate closes.
We use the same 5 step approach to translate this State Transition Diagram with 2 additional states and 2 additional transitions into code.
#define GATE_SPEED 120 // [ms] lower number is higher servo speed #define GATE_DELAY 2000 // [ms] time after double red before gate closes #define GATE_OPEN 60 // servo angle #define GATE_CLOSED 135 // servo angle #define BLINK_SPEED 400 // [ms] smaller number is faster blinking #define YELLOW_TIME 2000 // [ms] #define RED_TIME 1000 // [ms] #define SERVO_PIN 3 #define LEDY_PIN 5 #define LEDR1_PIN 6 #define LEDR2_PIN 7 #define SENSOR1_PIN 10 #define SENSOR2_PIN 11 byte state = 1, transition; byte ledr1, ledr2, blink_enabled; byte angle = GATE_OPEN; byte setpoint = GATE_OPEN; unsigned long time_to_blink; unsigned long time_to_close_gate; unsigned long time_for_servo; unsigned long end_yellow_time; unsigned long end_double_red_time; #include <Servo.h> Servo gate_servo; void setup() { pinMode(SENSOR1_PIN, INPUT_PULLUP); pinMode(SENSOR2_PIN, INPUT_PULLUP); pinMode(LEDY_PIN, OUTPUT); pinMode(LEDR1_PIN, OUTPUT); pinMode(LEDR2_PIN, OUTPUT); gate_servo.attach(SERVO_PIN); gate_servo.write(angle); Serial.begin(9600); Serial.println("Railway Crossing Control Ready"); Serial.println(); Serial.println("Waiting for train"); } void loop() { switch(state) { case 1: // idle if(digitalRead(SENSOR1_PIN) == LOW) transition = 12; break; case 2: // yellow if (millis() > end_yellow_time) transition = 23; break; case 3: // double red if (millis() > end_double_red_time) transition = 34; break; case 4: // blinking, gate still open if (millis() > time_to_close_gate) transition = 45; break; case 5: // blinking, gate closing if(digitalRead(SENSOR2_PIN) == LOW) transition = 56; break; case 6: // blinking, gate opening if(angle == GATE_OPEN) transition = 61; break; } switch(transition) { case 12: // Serial.println("Train detected, start yellow"); digitalWrite(LEDY_PIN, HIGH); end_yellow_time = millis() + (unsigned long)YELLOW_TIME; transition = 0; state = 2; break; case 23: // Serial.println("Time to end Yellow and start Double Red"); digitalWrite(LEDY_PIN, LOW); ledr1 = 1; ledr2 = 1; end_double_red_time = millis() + (unsigned long)RED_TIME; transition = 0; state = 3; break; case 34: Serial.println("Time to start Red blinking"); blink_enabled = 1; time_to_close_gate = millis() + (unsigned long)GATE_DELAY; transition = 0; state = 4; break; case 45: Serial.println("Time to close the gate"); setpoint = GATE_CLOSED; transition = 0; state = 5; break; case 56: Serial.println("Train detected, open the gate"); setpoint = GATE_OPEN; transition = 0; state = 6; break; case 61: Serial.println("Gate fully open, stop blinking"); Serial.println(); Serial.println("Waiting for Train"); blink_enabled = 0; ledr1 = 0; ledr2 = 0; transition = 0; state = 1; break; } if (millis() > time_for_servo) { time_for_servo = millis() + (unsigned long)GATE_SPEED; if (angle < setpoint) angle++; if (angle > setpoint) angle--; gate_servo.write(angle); } if(blink_enabled == 1) { if(millis() > time_to_blink) { time_to_blink = millis() + (unsigned long)BLINK_SPEED; ledr1 = !ledr1; ledr2 = !ledr1; } } digitalWrite(LEDR1_PIN, ledr1); digitalWrite(LEDR2_PIN, ledr2); }
— 0 —
Thank you, Completed on breadboard. Keep up the good work.
LikeLike
Hi Rudy
I am a 72 years newbie on Arduino and I try to understand it but find it difficult.
Building a level crossing and uploading a sketch is no problem.
This sketch no 21 works nicely. thanks for that.
I have another question: Can you also change it so that your crossing sketch an old model English railway crossing with 2 gates that turn 90 degrees to each other can move.
Greetz Henk
LikeLike
Henk, in software anything is possible. If you can specify exactly what needs to be done I’ll see if it can be made without too much effort.
LikeLike