Arduino to control model rail traffic lights

Hi everyone,

My dad has a model railway, which he wants to have automated traffic lights on, which will detect an approaching train, go green, then cycle through yellow to red. I am fairly computer savvy, however have no idea where to even start with this project.

If anyone could help me towards some practice codes whichwould lead me in the right direction, or if anyone has done anything similar and has any advice it would be amazing.

I currently have the arduino starter set, and can purchase necessary detectors etc.

Thanks in advance to those who can help

Jon

Traffic lights are a regular project. Do a search in the box at the top of the page.

Weedpharma

Jonadams:
Hi everyone,

My dad has a model railway, which he wants to have automated traffic lights on, which will detect an approaching train, go green, then cycle through yellow to red. I am fairly computer savvy, however have no idea where to even start with this project.

If anyone could help me towards some practice codes whichwould lead me in the right direction, or if anyone has done anything similar and has any advice it would be amazing.

I currently have the arduino starter set, and can purchase necessary detectors etc.

Thanks in advance to those who can help

Jon

Jon,
the first thing you need to do, is figure out something to measure. The Arduino can directly measure a voltage between 0v and 5V, or measure ON, OFF (5v or 0V).

With your model train what can you measure?

On fullsize trains they run an electrical signal out one rail, the train wheels and axles are solid steel. The wheel sets act to short the signal across the rails. They measure a current out one rail and back in the other. I am not familiar with model trains.

You other options are vibrations sensors, (usually too sensitive. Most model layout are quite compact), weight sensors( switches under the track that are depressed by the presence of the train), photo interrupters, (photo electric eyes), Ultrasonic (sound radar bouncers, these can measure distance over a small range, usually 2cm to 400cm.

Figure out what you can measure, that will dictate what you need to build. After you have a working 'detector' then you can write the software to use this 'detection' signal to activate your signal lights.

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560's. It adds 1MB of RAM for those projects where 8KB is not enough.

A simple way to detect a model train is with a Light Dependent Resistor (LDR) set between the sleepers. They are small, unobtrusive and simple.

On the real railway the signal goes red when the train passes the detector and it goes orange when the next detector is triggered and green when a third one is triggered. That may not be practical due to the shorter distances on model railways so some simple time sequence may be sufficient.

The demo several things at a time shows how to use millis() to manage timing while allowing the Arduino to continue detecting events.

You might also find useful stuff in planning and implementing a program.

...R

Hi,

We, dad and us two sons, used to have a large model railway ,(Gods Wonderful Railway), and to detect a train we used to have trackside "furniture".
Say a signal box or rock or such, and it would have a LDR in it, with a corresponding LED in an opposite bit of "furniture" on the other side of the track.
This would detect a train passing.
The train would latch the signal to RED, on the positive going output to detect the front.
The other side of the crossing another pair to unlatch the RED signal, this time triggering on negative going output to detect the end of the train.

To distinguish between gaps between rolling stock, the equivalent of a button de-bounce could be implemented on the departing sensor.

Tom...... :slight_smile:

Or possibly mount a magnet under the engine and have a reed or hall effect switch(es) between the rails for detection? I know a colleague of mine used that approach.

Bernie

Hi everyone,

Thanks for the great and quick replies. I will either be using light dependant resistors or IR dots as he has too many locos to attach magnets under each of them.

I am working through the book I got with my arduino, and have come across a slight oddity. I am doing the state machine build with the three LEDs, it is all working perfectly, switching between the states, but only when I manually break the circuit. I have tried both push buttons I got in the kit, and neither work as intended. I have tried increasing and decreasing the "delay()" on the debounce function, but no change, but if i pull the button out, and replace it, it changes to next state.

Hopefully that makes some kind of sense. If anyone has any ideas as to why it may not be working?

Thanks

Jon

Hi,
Is the button one of the tactile flat buttons with 4 pins?
If so turn the button 90Deg, the pins are wired in parallel.
Check with a DMM, if you have one,

It is worthwhile getting a DMM to help with trouble shooting, even the cheap ebay units are okay if they measure DC/AC volts, Resistance at least.

Tom... :slight_smile:

Thanks for the quick reply. I've tried them both in the only 2 orientations they fit into the breadboard. And yes the flat ones with 4 pins.

Jon

Hi.
Have you tested them with DMM, or used them before in another example in the kit to prove they are a normally open switch?
If no DMM, use a simple switch=resistor=LED series circuit to see it you can turn LED on and off.

Tom.... :slight_smile:

Sooooo.......it may have turned out that I was short circuiting it across a straight, rather than running the connection diagonally across..... oops!

Jon

Hi,

I'm really starting to get into this now. As a starting point I have got the following code:

int LED1=12;
int LED2=11;
int LED3=10;
int SW1=2;
int cnt=0;
int state=0;

void setup() {
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(SW1,INPUT);
  digitalWrite(SW1,HIGH);

}

void loop() 
 {
  if(!digitalRead(SW1))
  {
    delay(50);
    if(!digitalRead(SW1))
    {
      Statemaschine();
      while(!digitalRead(SW1));
    }
  }
  delay(10);
}
void Statemaschine(void)
{
  switch(state)
  {
   
   case 0:
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);
    state++;
    break; 
    
    case 1:
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);
    delay(2000);
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,LOW);
    delay(2000);
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,HIGH);
    delay(2000);
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,LOW);
    delay(2000);
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);
    delay(2000);
    state=0;
    break;
  }
}

This is working pretty much how I want it to, however I need to press the button more times than will work with the end product, can I get this to return to state 1 automatically without another press of the button? Or do I need to do this in another format?

Jon

Hi,
No probs mate, almost as good as wondering why circuit won't work and after hair pulling frustration....
Wire out by one row on protoboard, right in front of face.
Decided time to go to bed.
(Needed beauty sleep anyway..)

Tom.... :slight_smile:

If you want your system to be responsive you should not use delay() to manage timing because it blocks the Arduino and it can do nothing until the delay() interval finishes. The demo several things at a time shows how to manage timing without blocking using millis().

It is much easier to use millis() right from the start rather than convert from delay() when you have a complex program developed.

...R

Hi again everyone.

I have been further plugging away at this project, and have discovered that Robin2 I'd right. The delay function messes up the other things I want the board to do. The issue I'm now having is trying to use the 'millis' function. The only tutorial style coding involve blinking lights, single output. However as you can see from my above code, I'm trying to use 3/4 led outputs.

Sorry for ramble. Any help would be appreciated.

Jon

try this im not sure ive put the timer In the right place

int LED1=12;
int LED2=11;
int LED3=10;
int SW1=2;
int cnt=0;
int state=0;
unsigned long previousMillis=0;
unsigned int timer=0;
unsigned long interval=1000;//one second

void setup() {
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(SW1,INPUT);
  digitalWrite(SW1,HIGH);

}

void loop() 
 {
  if(!digitalRead(SW1))
  {
    delay(50);
    if(!digitalRead(SW1))
    {
      Statemaschine();
      while(!digitalRead(SW1));
    }
  }
  delay(10);
}
void Statemaschine(void)
{
  switch(state)
  {
   
   case 0:
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);
    state++;
    break; 
    
    case 1:
    
     unsigned long currentMillis = millis();//one second into timers
  if(currentMillis - previousMillis > interval) {
     timer++;//every second 
       previousMillis = currentMillis;}
    
    if (timer<=2){
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);}
    //delay(2000);
    if ((timer>2)&&(timer<=4)){
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,LOW);}
    //delay(2000);
    if ((timer>4)&&(timer<=6)){
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,HIGH);}
    //delay(2000);
     if ((timer>6)&&(timer<=8)){
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,LOW);}
    //delay(2000);
    if ((timer>8)&&(timer<=10)){
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);}
    //delay(2000);
    if(timer>10){
    state=0;
    timer=0;}
    
    break;
  }
}

gpop1:
try this im not sure ive put the timer In the right place

That is an approach I have not seen before and I think it should work. Have you tried it ?

This

if ((timer>2)&&(timer<=4)){

can be simplified to

else if (timer<=4){

etc

An I think if you change this

  if(currentMillis - previousMillis > interval) {
     timer++;//every second
       previousMillis = currentMillis;}

to

 if(currentMillis - previousMillis < interval) {
    return;
  }
  else {
     timer++;//every second
       previousMillis = currentMillis;}

your code will not bother with updating the LEDS unncessarily

...R