.

Welcome to My HO Model Railroad Blog

Arduino Crossing Gate Controller Project



I found some very slick Arduino IR Detectors on eBay at a very good price and I figured that they would be worth the investment of 45¢ to play with, 10 for $4.50.

 

They turned out to be very good for under the track type obstacle detectors.  So good I decided to give Geoff Bunza’s Crossing Gate Controller a shot.  The detectors and the Arduino Sketch work great!

For some reason I didn't do my regular bench test setup thing and just built up a UNO Expansion Board.  I went with the same format as I used for the Random Lighting Controller by using a driver chip for the crossing lights.  All of my crossing flashing lights are Grain of Wheat incandescent bulbs and take more current than the Arduino ports will handle.  Because Geoff's sketch is written for LEDs I decided to use a non inverting TD62304AP high current driver chip for the flashing bulbs rather than changing the program for the ULN2003 inverting chip. 




After dinking around with the working controller a problem occurred and it took an hour to figure out that the UNO developed a internal problem.  I've seen this happen before with the UNO but still investigated it thoroughly.  One of the I/O ports (6) wouldn't return to the high state causing the UNO to lockup.  I added PULLUP to the statement and it had no effect, bad port.  I moved both IR inputs from 5 & 6 to 7 & 8 and corrected the sketch.  I've had it running for several hours without any more problems.  I've seen defective UNO ports that don't work as an input before but still work OK as an output ????

The Tower SG90 Servos work great and I think they will perform much better than a single Tortoise for operating the gate arms.  In test mode on my bench they look very good.  There also a bunch cheaper at $1.49 each compared to a $18 Tortoise.  The servos have a lot of torque and a Tortoise has very little.  Another advantage of using a servo is you can program it to an exact movement.

Here is the Geoff Bunza sketch with the IR ports at 7 & 8.


==============================

//Aduino Sketch:
// Example Level Crossing Control Driving Common Cathode LEDs
// Version 1.4  Geoff Bunza 2018
// Uses software servo Library
//
#include
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 = 7;   // IR sensor pin Assumption== Pin goes LOW when train detected
int sensor2 = 8;   // 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 = 7;       //this will tell which sensor was triggered first
int leaving_sensor = 8;        // 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_PULLUP); 
  pinMode(sensor2, INPUT_PULLUP);
  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 br="" i="" nbsp="">      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  {                              
    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(15000);             // 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;
}



==============================

When I get one of my crossings removed from my layout and working on the bench I'll post a short video of the operation.  Geoff hit the nail right on the head with the timing.

No comments: