Level Crossing or Grade Crossing Control
Here are the assumptions for this adventure:
There are 2 gates both servo motor controlled, four LEDs for warning flashers, and two infrared (IR) detectors positioned before and after the crossing.
Servo Motor
IR Detector
The servos can be found in many hobby stores and on the web, and are commonly used by Radio Control (RC) enthusiasts. The IR detector I use is a low cost ($1.37) module I found on ebay: http://tinyurl.com/p3gvazj that has an adjustable sensitivity and whose output pin goes low when an object is sensed in front of it. It is powered by +5Volts. Paint ALL sides of both LEDs on the IR Sensor board black EXCEPT the very front of each to improve its sensitivity to ambient light.
Servos attach to Arduino Digital Pins 3 and 4, IR Detectors to Pins 5 and 6, LED flashers to 10 & 11, and 12 & 13 respectively. All powered by a 5 Volt power supply. The Arduino sketch is complete below. Copy, paste and load it into yours. The Blinkers are assumed to be LEDs with a common cathode (negative side) each LED with its own current limiting resistor (820-4700 Ohms is usually a good range). LEDs blink in pairs led1, led1 (pins 10,11) and led3 ,led4 (pins 12,13).
As a train is sensed by either sensor the flashers turn on immediately and continue for 3 seconds, when the gates come down—slowly. Flashing continues with the gates down until the other sensor is triggered and then remains untriggered for at least 1.2 seconds. Then the gates come up and the lights will go off. The train can arrive in either direction, but is must go completely through the crossing. If you need to deal with a train that enters, stops, and backs up through the crossing this might give you a good starting point.
If you want to add some good looking flashers and gates, give this easy "kitbashing" project a try:
http://nycshs.files.wordpress.com/2013/08/nycm_2q2012.pdf
or
http://www.scalemodelanimation.com/Articles/Crossbucks_&_Crossing_Gates.pdf
‘Hope this helps enliven your crossings! Have Fun!
Best Regards,
Geoff Bunza
Aduino Sketch for COMMON ANODE can be downloaded from here: CrossingComAnode1.4.1.zip
Aduino Sketch for COMMON CATHODE can be downloaded from here: LevelCrossing1.4.zip
Aduino Sketch for COMMON CATHODE :
// Example Level Crossing Control Driving Common Cathode LEDs
// Version 1.4 Geoff Bunza 2018
//
#include <Servo.h>
Servo gate1servo; // create servo object to control crossing gate 1
//ASSUMPTION Gate is down at position 30 and up at position 120
Servo gate2servo; // create servo object to control crossing gate 2
//ASSUMPTION Gate is down at position 30 and up at position 120
int sensor1 = 5; // IR sensor pin Assumption== Pin goes LOW when train detected
int sensor2 = 6; // IR sensor pin Assumption== Pin goes LOW when train detected
int led1 = 10; // Led 1 pin first alternating flasher
int led2 = 11; // Led 2 pin first alternating flasher
int led3 = 12; // Led 3 pin second alternating flasher
int led4 = 13; // Led 4 pin second alternating flasher
int gatelow = 30; // variable to store the servo low gate stop position
int gatehigh = 120; // variable to store the servo high gate stop position
int gateposition = 120; // variable to store the servo gateposition
int entering_sensor = 5; //this will tell which sensor was triggered first
int leaving_sensor = 6; // this will tell which sensor shows train leaving
int gates_started = 0; // this says if the crossing is active
int flash_state = 0;
long flash_time = 0;
long flash_interval = 900; // time in milliseconds between alternating flashes
int sensor_count = 0;
void setup()
{
gate1servo.attach(3); // attaches the servo on pin 3 to the servo object
gate2servo.attach(4); // attaches the servo on pin 4 to the servo object
gate1servo.write(gateposition); //start assuming no train
gate2servo.write(gateposition); //start assuming no train
pinMode(sensor1, INPUT);
pinMode(sensor2, INPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
digitalWrite(led1, LOW); // Start with all flashers off
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
flash_time = millis();
}
void loop()
{
if ((digitalRead (sensor1)==LOW)&& (gates_started==0)) {
gates_started = 1;
leaving_sensor = sensor2;
starting_sequence();
}
if ((digitalRead (sensor2)==LOW)&& (gates_started==0)) {
gates_started = 1;
leaving_sensor = sensor1;
starting_sequence();
}
if (gates_started) flash_leds(); //gates are down continue flashing
if ((digitalRead(leaving_sensor)==LOW)&&(gates_started==1)) { //train is starting to leave
//as long as the leaving sensor is active the train is still in the crossing
while (gates_started==1) { //now check if train is REALLY gone
sensor_count = 0;
for (int i=1; i< 40; i++) {
if (digitalRead(leaving_sensor)==LOW) sensor_count++;
delay (30);
flash_leds();
}
if (sensor_count==0) gates_started=0;
flash_leds();
}
// we only get here if the train has really left the crossing
ending_sequence();
}
}
void starting_sequence() {
long wait_time;
flash_time = millis();
wait_time = millis()+3000;
while (wait_time> millis()) flash_leds(); //flash before dropping gates
for(gateposition = gatehigh; gateposition> gatelow; gateposition-=1) // goes from gatehigh degrees to gatelow degrees
{
gate1servo.write(gateposition); // tell servo to go to gateposition in variable 'gateposition'
gate2servo.write(gateposition); // tell servo to go to gateposition in variable 'gateposition'
flash_leds(); // keep flashing leds
delay(40); // waits 40ms to slow servo
}
}
void ending_sequence() {
for(gateposition = gatelow; gateposition< gatehigh; gateposition++) // goes from gatelow degrees to gatehigh degrees
{
gate1servo.write(gateposition); // tell servo to go to gateposition in variable 'gateposition'
gate2servo.write(gateposition); // tell servo to go to gateposition in variable 'gateposition'
flash_leds(); // keep flashing leds
delay(40); // waits 40ms to slow servo
}
digitalWrite(led1, LOW); // flashers completely off
digitalWrite(led3, LOW);
digitalWrite(led2, LOW);
digitalWrite(led4, LOW);
delay(30000); // 30 second delay to account for the train passing the starting entry sensor
}
void flash_leds() {
if (flash_time> millis()) return;
flash_state = ~flash_state;
digitalWrite(led1, flash_state); // Alternate flashers
digitalWrite(led3, flash_state);
digitalWrite(led2, ~flash_state);
digitalWrite(led4, ~flash_state);
flash_time = millis()+flash_interval;
}