• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

guidance required with Arduino code for model rail signals

Deltech

New Member
Explanation of project:~
I am a complete novice to Arduino, and am using the TinkerCAD website to try and devise a code to provide automatic control for 3-aspect model rail signals.

I have only included 3 signals in the code, in order to keep it simple, and so that I can grasp the principles before increasing the number of signals.

The 3 signals can be considered to be equally spaced around a circular track, in such a manner as the Train will pass signal 1, then pass signal 2, then pass signal 3, and then pass signal 1 again, etc, etc, etc.

Each signal has a Red, Yellow, and, Green aspect, and SHOULD only display 1 colour at any time.

If the block ahead of any signal is clear, AND the next block is also clear, the signal should show Green.

If the block ahead of any signal is clear, but the next block is occupied, then the signal should show Yellow.

If the block ahead of any signal is occupied, the signal should show Red.

As I am using the TinkerCAD website, I have created a project using 3 switches as INPUTS, to simulate the Train being detected in the block section(s) ahead of each signal.

When a switch is closed this tells the Arduino that a Train has passed the corresponding signal, and is occupying the block ahead, and the corresponding signal should show Red, and the signal behind (a.k.a. the previous signal) should be Yellow, and have no effect on the signal behind that (Green).

When there is no input from the switches (no Train on track), all signals should be Green.

This is to control Trains in one direction only.



Description of problem:~
My code does not work.

I get no error messages.

When I run the program each signal displays all 3 colours (Red, Yellow, and, Green) = all 9 LEDs illuminated at the same time, and the switches have no effect.

Unfortunately, as a complete novice, I am unable to think of a solution to this problem.



Plea:~
Could somebody please provide me with some guidance as to how I can solve this issue?

I include my (very rudimentary) code.

Thanks.


const int R1 = 2; // choose pin for signal 1 RED aspect
const int Y1 = 3; // choose pin for signal 1 YELLOW aspect
const int G1 = 4; // choose pin for signal 1 GREEN aspect
const int R2 = 5; // choose pin for signal 2 RED aspect
const int Y2 = 6; // choose pin for signal 2 YELLOW aspect
const int G2 = 7; // choose pin for signal 2 GREEN aspect
const int R3 = 8; // choose pin for signal 3 RED aspect
const int Y3 = 9; // choose pin for signal 3 YELLOW aspect
const int G3 = 10; // choose pin for signal 3 GREEN aspect

const int inPin1 = 14; // choose pin for pushbutton 1
int val1 = 0; // variable for reading the pin status
const int inPin2 = 15; // choose pin for pushbutton 2
int val2 = 1; // variable for reading the pin status
const int inPin3 = 16; // choose pin for pushbutton 3
int val3 = 2; // variable for reading the pin status


void setup()
{
pinMode(R1, OUTPUT); // set pin as output
pinMode(Y1, OUTPUT); // set pin as output
pinMode(G1, OUTPUT); // set pin as output
pinMode(R2, OUTPUT); // set pin as output
pinMode(Y2, OUTPUT); // set pin as output
pinMode(G2, OUTPUT); // set pin as output
pinMode(R3, OUTPUT); // set pin as output
pinMode(Y3, OUTPUT); // set pin as output
pinMode(G3, OUTPUT); // set pin as output
pinMode(14, INPUT); // set pin as input
pinMode(15, INPUT); // set pin as input
pinMode(16, INPUT); // set pin as input


// start with all signals Green

digitalWrite(R1, LOW); // turn R1 OFF
digitalWrite(Y1, LOW); // turn Y1 OFF
digitalWrite(G1, HIGH); // turn G1 ON
digitalWrite(R2, LOW); // turn R2 OFF
digitalWrite(Y2, LOW); // turn Y2 OFF
digitalWrite(G2, HIGH); // turn G2 ON
digitalWrite(R3, LOW); // turn R3 OFF
digitalWrite(Y3, LOW); // turn Y3 OFF
digitalWrite(G3, HIGH); // turn G3 ON

}


void loop() {

val1 = digitalRead(inPin1); // read input value 1
val2 = digitalRead(inPin2); // read input value 2
val3 = digitalRead(inPin3); // read input value 3


if (val1 == HIGH && val2 == HIGH);
{ digitalWrite(G1, HIGH);} // turns on G1


if (val1 == HIGH && val2 == LOW);
{ digitalWrite(Y1, HIGH);} // turns on Y1


if (val1 == LOW);
{ digitalWrite(R1, HIGH);} // turns on R1


// REPEAT FOR NEXT SIGNAL

if (val2 == HIGH && val3 == HIGH);
{ digitalWrite(G2, HIGH);} // turns on G2


if (val2 == HIGH && val3 == LOW);
{ digitalWrite(Y2, HIGH);} // turns on Y2


if (val2 == LOW);
{digitalWrite(R2, HIGH);} // turns on R2


// REPEAT FOR NEXT SIGNAL

if (val3 == HIGH && val1 == HIGH);
{ digitalWrite(G3, HIGH);} // turns on G3


if (val3 == HIGH && val1 == LOW);
{ digitalWrite(Y3, HIGH);} // turns on Y3


if (val3 == LOW);
{digitalWrite(R3, HIGH);} // turns on R3

}

// END
 

Visitor

Well-Known Member
First, just try to make one LED flash – on for a second, off for a second.

Next, turn one LED on and off according to a switch. You haven't described your hardware, but I suspect the problem is here. Do you have pull-up resistors on your switches? These could be physical resistors of 10k or so, or internal pull-ups on the Arduino, which I don't believe you've enabled.

Finally, using serial print statements to print out variable values where you think something should happen is very useful.
 

Deltech

New Member
In the absence of a "physical" Arduino, I am using a "virtual" one, on the TinkerCAD website; an Uno R3.

I am using "external" resistors, so to speak, rather than the "built-in" ones.

How do I use serial print statements to print out variables where I think something should happen?
 

rjenkinsgb

Well-Known Member
Most Helpful Member
Two problems I can see:

Code:
if (val1 == HIGH && val2 == HIGH);
{ digitalWrite(G1, HIGH);} // turns on G1
You are terminating the IF lines with a ;
That ends the conditional part, so the next line always executes.

Also, there is no corresponding statement to turn off an LED if the ON condition is false.

Try them like this:

Code:
if (val1 == HIGH && val2 == HIGH) {
    digitalWrite(G1, HIGH);  // turns on G1
}
else {
    digitalWrite(G1, LOW); // turn off G1
}
 

sagor1

Active Member
With 3 inputs, you have 8 combinations. I would make an array of 8 for each block and define the LED states for each of the 8 input states. Thus you read the inputs, make a byte value from them in the range of 0 to 7 and then read each block array (3 x 8 byte arrays, one for each block) for a given state and output that value for the LEDs.
For a simple 3 block example, this can work well. Once you get into many blocks and many LED states, like dozens of them, it gets more complicated....
 

Deltech

New Member
rjenkinsgb,
thanks for that suggestion.

I have now added ELSES to every IF, and the signals now go on and off in direct response to the switches.

BUT>>>> although LEDs go from unlit to lit immediately upon the operation of a switch (or combination of switches), any LED which goes from lit back to unlit, takes about 10 seconds to be completely OFF.

Any suggestions as to why it takes so long to go completely OFF?

Is this normal, or is it just because I'm using a "virtual" Arduino?

Amended code below, and (hopefully) a screenshot of the project.

3 x 3-aspect signals, and 3 x switches.jpg

Code:
const int R1 = 2;        // choose pin for signal 1 RED aspect
const int Y1 = 3;       // choose pin for signal 1 YELLOW aspect
const int G1 = 4;       // choose pin for signal 1 GREEN aspect
const int R2 = 5;       // choose pin for signal 2 RED aspect
const int Y2 = 6;       // choose pin for signal 2 YELLOW aspect
const int G2 = 7;       // choose pin for signal 2 GREEN aspect
const int R3 = 8;       // choose pin for signal 3 RED aspect
const int Y3 = 9;       // choose pin for signal 3 YELLOW aspect
const int G3 = 10;        // choose pin for signal 3 GREEN aspect

const int inPin1 = 14;      // choose pin for pushbutton 1
int val1 = 0;         // variable for reading the pin status
const int inPin2 = 15;      // choose pin for pushbutton 2
int val2 = 1;         // variable for reading the pin status
const int inPin3 = 16;      // choose pin for pushbutton 3
int val3 = 2;         // variable for reading the pin status


void setup()
{
  pinMode(R1, OUTPUT);         // set pin as output
  pinMode(Y1, OUTPUT);         // set pin as output
  pinMode(G1, OUTPUT);         // set pin as output
  pinMode(R2, OUTPUT);         // set pin as output
  pinMode(Y2, OUTPUT);         // set pin as output
  pinMode(G2, OUTPUT);         // set pin as output
  pinMode(R3, OUTPUT);         // set pin as output
  pinMode(Y3, OUTPUT);         // set pin as output
  pinMode(G3, OUTPUT);         // set pin as output
  pinMode(14, INPUT);          // set pin as input
  pinMode(15, INPUT);          // set pin as input
  pinMode(16, INPUT);          // set pin as input

  // start with all signal showing Green
  digitalWrite(R1, LOW);      // turn R1 OFF
  digitalWrite(Y1, LOW);      // turn Y1 OFF
  digitalWrite(G1, HIGH);     // turn G1 ON
  digitalWrite(R2, LOW);      // turn R2 OFF
  digitalWrite(Y2, LOW);      // turn Y2 OFF
  digitalWrite(G2, HIGH);     // turn G2 ON
  digitalWrite(R3, LOW);      // turn R3 OFF
  digitalWrite(Y3, LOW);      // turn Y3 OFF
  digitalWrite(G3, HIGH);     // turn G3 ON


}


void loop() {

  val1 = digitalRead(inPin1); // read input value 1
  val2 = digitalRead(inPin2); // read input value 2
  val3 = digitalRead(inPin3); // read input value 3

  if (val1 == HIGH && val2 == HIGH)
  {
    digitalWrite(G1, HIGH); // turns on G1
  }
  else {
    digitalWrite(G1, LOW);
  }

  if (val1 == HIGH && val2 == LOW)
  {
    digitalWrite(Y1, HIGH); // turns on Y1
  }
  else {
    digitalWrite(Y1, LOW);
  }

  if (val1 == LOW)
  {
    digitalWrite(R1, HIGH); // turns on R1
  }
  else {
    digitalWrite(R1, LOW);
  }


  // REPEAT FOR NEXT SIGNAL

  if (val2 == HIGH && val3 == HIGH)
  {
    digitalWrite(G2, HIGH); // turns on G2
  }
  else {
    digitalWrite(G2, LOW);
  }

  if (val2 == HIGH && val3 == LOW)
  {
    digitalWrite(Y2, HIGH); // turns on Y2
  }
  else {
    digitalWrite(Y2, LOW);
  }

  if (val2 == LOW)
  {
    digitalWrite(R2, HIGH); // turns on R2
  }
  else {
    digitalWrite(R2, LOW);
  }


  // REPEAT FOR NEXT SIGNAL

  if (val3 == HIGH && val1 == HIGH)
  {
    digitalWrite(G3, HIGH); // turns on G3
  }
  else {
    digitalWrite(G3, LOW);
  }

  if (val3 == HIGH && val1 == LOW)
  {
    digitalWrite(Y3, HIGH); // turns on Y3
  }
  else {
    digitalWrite(Y3, LOW);
  }

  if (val3 == LOW)
  {
    digitalWrite(R3, HIGH); // turns on R3
  }
  else {
    digitalWrite(R3, LOW);
  }

}


// END
 
Last edited:

Deltech

New Member
With 3 inputs, you have 8 combinations. I would make an array of 8 for each block and define the LED states for each of the 8 input states. Thus you read the inputs, make a byte value from them in the range of 0 to 7 and then read each block array (3 x 8 byte arrays, one for each block) for a given state and output that value for the LEDs.
For a simple 3 block example, this can work well. Once you get into many blocks and many LED states, like dozens of them, it gets more complicated....
sagor1,
thanks for the suggestion, but unfortunately I have no idea of how to "make arrays", "make bytes", or, "read block arrays".

Your suggestion would, I do not doubt, probably be a far more efficient method than my very long-winded and rudimentary way of achieving the same goal, BUT>>>>, and this is the crux of it>>>> I "understand" my long-winded method, and find it easy to work with.

Please do not think I am being ungrateful for your contribution; quite the opposite; and I am sure someone else with a similar problem will read your response and think "that's exactly what I need to do to solve my own problem".

However, I suppose it is important for any Arduino user to at least be able to write code within their own capabilties, and be able to understand what they are writing.

But thanks again for taking the time to respond.
 

Musicmanager

Active Member
Hi Deltech

There are some discrepancies between your schematic and your code .. .. ..

C:
const int R1 = 2; // choose pin for signal 1 RED aspect
const int Y1 = 3; // choose pin for signal 1 YELLOW aspect
const int G1 = 4; // choose pin for signal 1 GREEN aspect
const int R2 = 5; // choose pin for signal 2 RED aspect
const int Y2 = 6; // choose pin for signal 2 YELLOW aspect
const int G2 = 7; // choose pin for signal 2 GREEN aspect
const int R3 = 8; // choose pin for signal 3 RED aspect
const int Y3 = 9; // choose pin for signal 3 YELLOW aspect
const int G3 = 10; // choose pin for signal 3 GREEN aspect

const int inPin1 = A0; // choose pin for pushbutton 1       These three pins are connected like this
int val1 = 0; // variable for reading the pin status        on your schematic
const int inPin2 = A1; // choose pin for pushbutton 2
int val2 = 1; // variable for reading the pin status
const int inPin3 = A2; // choose pin for pushbutton 3
int val3 = 2; // variable for reading the pin status


void setup()
{
pinMode(R1, OUTPUT); // set pin as output
pinMode(Y1, OUTPUT); // set pin as output
pinMode(G1, OUTPUT); // set pin as output
pinMode(R2, OUTPUT); // set pin as output
pinMode(Y2, OUTPUT); // set pin as output
pinMode(G2, OUTPUT); // set pin as output
pinMode(R3, OUTPUT); // set pin as output
pinMode(Y3, OUTPUT); // set pin as output
pinMode(G3, OUTPUT); // set pin as output
pinMode(14, INPUT); // set pin as input
pinMode(15, INPUT); // set pin as input
pinMode(16, INPUT); // set pin as input

// start with all signal showing Green
digitalWrite(R1, LOW); // turn R1 OFF
digitalWrite(Y1, LOW); // turn Y1 OFF
digitalWrite(G1, HIGH); // turn G1 ON
digitalWrite(R2, LOW); // turn R2 OFF
digitalWrite(Y2, LOW); // turn Y2 OFF
digitalWrite(G2, HIGH); // turn G2 ON
digitalWrite(R3, LOW); // turn R3 OFF
digitalWrite(Y3, LOW); // turn Y3 OFF
digitalWrite(G3, HIGH); // turn G3 ON


}


void loop() {

val1 = digitalRead(inPin1); // read input value 1
val2 = digitalRead(inPin2); // read input value 2
val3 = digitalRead(inPin3); // read input value 3

/*
digitalWrite(R1, LOW); // turn R1 OFF  .. .. you've already done this in setup .. .
digitalWrite(Y1, LOW); // turn Y1 OFF
digitalWrite(G1, LOW); // turn G1 ON
digitalWrite(R2, LOW); // turn R2 OFF
digitalWrite(Y2, LOW); // turn Y2 OFF
digitalWrite(G2, LOW); // turn G2 ON
digitalWrite(R3, LOW); // turn R3 OFF
digitalWrite(Y3, LOW); // turn Y3 OFF
digitalWrite(G3, LOW); // turn G3 ON
*/


if (val1 == HIGH && val2 == HIGH)
{
digitalWrite(G1, HIGH); // turns on G1
}

if (val1 == HIGH && val2 == LOW)
{
digitalWrite(Y1, HIGH); // turns on Y1
}

if (val1 == LOW)
{
digitalWrite(R1, HIGH); // turns on R1
}


// REPEAT FOR NEXT SIGNAL

if (val2 == HIGH && val3 == HIGH)
{
digitalWrite(G2, HIGH); // turns on G2
}

if (val2 == HIGH && val3 == LOW)
{
digitalWrite(Y2, HIGH); // turns on Y2
}

if (val2 == LOW)
{
digitalWrite(R2, HIGH); // turns on R2
}


// REPEAT FOR NEXT SIGNAL

if (val3 == HIGH && val1 == HIGH)
{
digitalWrite(G3, HIGH); // turns on G3
}

if (val3 == HIGH && val1 == LOW)
{
digitalWrite(Y3, HIGH); // turns on Y3
}

if (val3 == LOW)
{
digitalWrite(R3, HIGH); // turns on R3
}

}

// END
This does compile .. .. ..

MM
 

Deltech

New Member
Musicmanager,
that was a "copy && paste" error, (see what I did there, &&. lol) which I actually edited out shortly after posting it.

Thank you for your input.
 

Deltech

New Member
Musicmanager,
14/15/16 = A0/A1/A2.

rjenkinsgb,
thanks. I've got a "fake Chinese" Mega coming from eBay for £10. It's worth the risk for £10.......
 

Musicmanager

Active Member
There is no good reason I can see for any delay with an actual device.
const int inPin1 = 14; // choose pin for pushbutton 1
int val1 = 0; // variable for reading the pin status
const int inPin2 = 15; // choose pin for pushbutton 2
int val2 = 1; // variable for reading the pin status
const int inPin3 = 16; // choose pin for pushbutton 3
int val3 = 2; // variable for reading the pin status

Do you think it might be because pins 14, 15, 16 don't exist ?

MM
 

Deltech

New Member
Do you think it might be because pins 14, 15, 16 don't exist ?
No, analog pin A0 can be used as a digital pin 14. Likewise, analog pins A1/A2 can be used as digital pins 15/16.

Program is working fine now, with exception of the delay in going from lit to unlit, but rjenkinsgb suggests that is because I am using an online "virtual" Arduino, rather than a real "live" one.
 

Musicmanager

Active Member
Fair enough .. ..

I've never seen Arduino Analog pins labelled that way, but if it works .. it works .. well done

MM
 

eTech

Well-Known Member
Explanation of project:~
I am a complete novice to Arduino, and am using the TinkerCAD website to try and devise a code to provide automatic control for 3-aspect model rail signals.

I have only included 3 signals in the code, in order to keep it simple, and so that I can grasp the principles before increasing the number of signals.

The 3 signals can be considered to be equally spaced around a circular track, in such a manner as the Train will pass signal 1, then pass signal 2, then pass signal 3, and then pass signal 1 again, etc, etc, etc.

Each signal has a Red, Yellow, and, Green aspect, and SHOULD only display 1 colour at any time.

If the block ahead of any signal is clear, AND the next block is also clear, the signal should show Green.

If the block ahead of any signal is clear, but the next block is occupied, then the signal should show Yellow.

If the block ahead of any signal is occupied, the signal should show Red.

As I am using the TinkerCAD website, I have created a project using 3 switches as INPUTS, to simulate the Train being detected in the block section(s) ahead of each signal.

When a switch is closed this tells the Arduino that a Train has passed the corresponding signal, and is occupying the block ahead, and the corresponding signal should show Red, and the signal behind (a.k.a. the previous signal) should be Yellow, and have no effect on the signal behind that (Green).

When there is no input from the switches (no Train on track), all signals should be Green.

This is to control Trains in one direction only.
maybe i'm not understanding your requirements but...

if its a circular track, and traffic is controlled in one direction, then all signals ahead of the train should be Grn, except 3 blocks behind the end of the train (assuming a train can't drop out of the sky:))?
Signal 1 behind train should be Red, signal 2 behind Yel, signal 3 behind Grn?

See below. The simulation is running your code.

1615832884448.png
 
Last edited:

Deltech

New Member
maybe i'm not understanding your requirements but...

if its a circular track, and traffic is controlled in one direction, then all signals ahead of the train should be Grn, except 3 blocks behind the end of the train?
Signal 1 behind train should be Red, signal 2 behind Yel, signal 3 behind Grn?
eTech,
at present, there is no track. This is virtual, for the purpose of understanding how to use an Arduino to control model rail signals. I simply used the circular track analogy for the benefit of anyone not of a Railway persuasion.

Anyway, the code seems to work fine now, on the TinkerCAD website, using a "virtual" Arduino Uno R3.

That is the only Arduino available on that site, so the options for expanding are limited, hence I've ordered a "Chinese" Mega off eBay.

I am sure there are far more efficient ways to achieve my objective, but it is very important that I can write the code in a manner that I understand; even if it takes more pages of code to do it my way.

There will eventually be approximately 30 signals to control, which will not consume a large amount of memory; some signals will be 4; Green onto double-Yellow onto single-Yellow onto Red, but I was limited by the "virtual" Arduino.

Where I have used switches in my mock-up to represent the presence of Trains on the track, this will be actually achieved by current transformers attached to one rail at numerous locations on the layout.

In addition to signals going to Red automatically when a Train passes, several of them will also have to show Red to hold a Train to allow another Train to cross from one Track to another in front of the stationary Train; which will (hopefully) be achieved by reading inputs which tell which way the points (switches/turnouts in U.S. terminology) are set.
 

Deltech

New Member
I just want to add to all who have responded, that I am most grateful for your guidance.

It is ironic that when I asked for help on the official Arduino forum, they were most UNhelpful.

Having read through many post on the official Ardunio forum, they are littered with sarcastic responses, and comments like "don't do it like that"; and telling people to use a "this", or a "that", or an "another", without either explaining what a "this", or a "that", or an "another", actually is, OR, how to implement a "this", or a "that", or an "another".

They mock you for such things as using & instead of &&, = instead of ==, or missing a ; or placing a ; where you shouldn't.

It is not conducive to gaining confidence with writing code.

Yet, the people in this forum have been extremely polite and helpful, so thanks again to you all.


I will no doubt be back again with another problem lol...............................
 

eTech

Well-Known Member
eTech,
at present, there is no track. This is virtual, for the purpose of understanding how to use an Arduino to control model rail signals. I simply used the circular track analogy for the benefit of anyone not of a Railway persuasion.

Anyway, the code seems to work fine now, on the TinkerCAD website, using a "virtual" Arduino Uno R3.

That is the only Arduino available on that site, so the options for expanding are limited, hence I've ordered a "Chinese" Mega off eBay.

I am sure there are far more efficient ways to achieve my objective, but it is very important that I can write the code in a manner that I understand; even if it takes more pages of code to do it my way.

There will eventually be approximately 30 signals to control, which will not consume a large amount of memory; some signals will be 4; Green onto double-Yellow onto single-Yellow onto Red, but I was limited by the "virtual" Arduino.

Where I have used switches in my mock-up to represent the presence of Trains on the track, this will be actually achieved by current transformers attached to one rail at numerous locations on the layout.

In addition to signals going to Red automatically when a Train passes, several of them will also have to show Red to hold a Train to allow another Train to cross from one Track to another in front of the stationary Train; which will (hopefully) be achieved by reading inputs which tell which way the points (switches/turnouts in U.S. terminology) are set.
ok..cool (I understand RR signaling)

If you can afford "Proteus for Arduino" ($250 USD), I highly recommend it. It works great for this type of simulation (with animation).
It simulates all type of arduino including Mega.
 

EE World Online Articles

Loading
Top