Model railway signal control

I am thinking about creating an arduino controlled signal system for my model railway.
I am going to use a red and green led for each signal (stop/go lights) so I was thinking 3 wires to a signal
A GND, +green and +red.

The only trouble is I cannot work out how to program a computer interface to control it,
I kind of want a image or the track plan as the background with buttons to change the signal.

Please could someone help me :slight_smile:

Steve Virgo

Google JMRI. :slight_smile:

That will give you a starting point. Then you will need to connect the Arduino to JMRI somehow. It's designed to be expandable, so such a thing should be relatively straight forward.

Ok, Well I have just installed jmri and a scrpit to my arduino called ArduinoCRMI and I am having no luck with anything for some reason, Not even the basic hello world JMRI light script.

Im confused again :frowning:

I'm just playing around with CMRI to see how it works. I have got the Hello World example running.

I am using JMRI version 2.12 as that's what I installed a year or so ago, but the instructions should apply to the latest version. There are instructions at the top of the hello world sketch, but regardless, here goes:

(1) Open JMRI (Decoder Pro), then go to Edit->Preferences. You should see a connections option on the left of the screen. Click connections and then go to the '+' tab along the top. This will add a new connection.
(2) Select 'C/MRI' as the system manufacturer, and then select 'Serial' as the system connection.
(3) Select your serial port and then check the "Additional Connection Settings" box. Make sure the Baud rate is set to 9600.
(4) Click "Configure C/MRI Node"
(5) On the window that appears set the following:
Node Address = 0
Node Type = SMINI
Leave all the other settings alone.
(6) Click Add Node. You should see a message under Notes saying "C/MRI Node added. Node Address = 0".
If you see a warning saying that "Error - Node with address '0' already exists", then click the Delete Node button, then click the Add Node button again.
(7) Click 'Done' and then 'Ok'. Finally click the 'Save' button in the bottom left of the screen.
(8) It will ask if you want to restart JMRI. Click yes. JMRI will then exit. Now, reopen JRMI.
(9) Once it reopens you should see in the main window:
"C/MRI: using Serial on COMx"
(If you see an error message, ensure you have downloaded the hello_world sketch to the Arduino and the correct COM port is selected)

C/MRI is now set up.

To use the hello_world sketch, you need to set up an output in JMRI. You can do this one of two ways, either using a 'Light' (good for a quick test), or using a 'Signal Head' (You will need this later for your signals).

Lets start with a quick test and set up a 'Light'.

(10) Go to Tools->Tables->Lights
(11) Click the Add... button at the bottom of the screen.
(12) Set the 'System' to C/MRI
Set the Hardware Address = 1
Username allows you to set a friendly name for the Light. I called it DigitalPin13, but anything will do, even an empty box.
(13) Click 'Create'. You should see "New Light added:CL1,DigitalPin13" or a message along those lines.
(14) Click 'Cancel to close the window. Then click 'OK' to the reminder that appears (its just telling you to remember to save changes later on)
(15) You should see your new light in the 'Lights' window you opened in step 10. There will be a button beside it under 'State' which lets you control the light. Click the button the LED attached to D13 should come on. Click it again, the light will go off.

Quick note, to save the changes, in the lights window, click 'File->Store Configuration only to file'.
To load the file next time you open JMRI, on the main JMRI window select Panels->Load Panels. Select the file you saved previously and click Load.

You will note that in Step (10) I said to use hardware address 1. The hardware address relates to your CMRI program as follows:

For Outputs:
cmri.get_bit(0) = Hardware address 1
cmri.get_bit(1) = Hardware address 2
cmri.get_bit(2) = Hardware address 3
Or more generally:

For a give Hardware address in JRMI, use the following in your Arduino sketch:
cmri.get_bit(Hardware Address - 1);

For Inputs:
Inputs can be defined in JRMI using the ‘Sensors’ table. You set up sensors in a similar way to the Lights, and each sensor has its own hardware address. The hardware address relates to the Arduino sketch as follows:
cmri.set_bit((Hardware Address - 1),state);
Where state is the logic state you want your Arduino to report back to JMRI.

If you've only got red or green, you could save a wire by charlieplexing

ok tom,
Well I have just done what you said but the only light that is lighting up is the rx light for a bout half a second.
I have connected various differnent led's to pin 13 but I am getting no hope.

But one thing I did notice is that in arduino ide software this is coming up after it has finished uploading to my board:
avrdude: stk500_getsync(): not in sync: resp0x00

I wonder if this has anything to do with it???????

Lets try now a simple signal head.

(1)First download the 'inputs_and_outputs' example sketch to your Arduino.

(2)Open JMRI.
(3)To use signals, we first have to setup some outputs. It may seem weird, but for this we have to use 'Turnouts'. So lets set some up. Go to Tools->Tables->Turnouts
(4) Click Add and set the following settings:
System: C/MRI
Hardware Address: 1
Username: Red
(5) Click OK. On the window that appears, select:
'Use 1 bit'
Followed by:
'Steady State Output'
This is our first Red output setup.
(6) Repeat steps 4 and 5, only this time setting:
Hardware Address: 2
Username: Green
(7) We now have our two signal outputs set up, so we now need to convert these to a signal head. On the turnouts window, you should see your two new turnouts named Red and Green. Each light has an identifier which is shown in the column called 'System Name'. On my window they are called:

CT1 Red
CT2 Green

Make a note of these two identifiers as you will need them in the next step.
(Note, the C is the system identifier, the 'T' stands for 'Turnout' and the 1 is the turnout number)
(8)Now we will set up a Signal Head. First go to Tools->Tables->Signals->Signal Heads
(9)Click 'Add'.
(10)For this signal we need an 'Double Output' signal as we only have two outputs, a red light and a green light
(11)Enter the following settings:
System Name: CH1 (The C is the system identifier which should match step 7, the 'H' stands for 'Head' and the 1 is the signal number)
User Name: "Signal" (This can be whatever you fancy)
Green Output Number: CT2
Red Output Number: CT1
(12) You should now see your new signal. There is a button next to it called state which you can use to test it. If you connect the Red LED to digital pin 2, the Green LED to digital pin 1, then you should see the following for each of these states:

State Red: Only the Red LED will be on
State Yellow: Both the Red and Green LEDs will be on
State Green: Only the Green LED will be on
State Flashing Red: Only the Red LED will be flashing on and off
State Flashing Yellow: Both the Red and Green LEDs will be flashing on and off
State Flashing Green: Only the Green LED will be flashing on and off


That means the Arduino is not being programmed.

The number in get_bit() will be 1 less than the Hardware address in JMRI.

Have you got any Idea how to fix this....????

Is JMRI open when you try to upload?

yep, That was exactly the problem.

So far....

I have got the light on/off hello world sketch to work and i can use it...

But for some reason I cant do the turnout/signal one yet?????

Why can't you? What's not working?

well. The sketch uploads to the arduino perfectly (I have swapped to a better pc! )
but I think I am going wrong in JMRI.

currently this is what I am doing:

Opening JMRI once the sketch is uploaded,
then opening tools menu -> tables -> turnouts
then adding turnouts:
adress 1
username red
adress 2 username green

Then going to the signal heads tab and filling in the green and red output number.

also as soon as i plug the leds into PWM pins 1 and 2, the led plugged into pwm pin 1 is lighting up straight away.

That's because they LEDs should be on D2 and D3.

If you look at the Arduino sketch, there is the following 4 lines:

  digitalWrite(2, cmri.get_bit(0));
  digitalWrite(3, cmri.get_bit(1));
  digitalWrite(4, cmri.get_bit(2));
  digitalWrite(5, cmri.get_bit(3));

These map CMRI output numbers to Arduino Digital pin numbers.

So from these lines:
CMRI bit 0 is digital pin 2
CMRI bit 1 is digital pin 3
CMRI bit 2 is digital pin 4
CMRI bit 3 is digital pin 5.

Just to be confusing, and due to the way the ArduinoCMRI library was written, the JMRI 'Hardware Address' is the CMRI bit number + 1. So CMRI bit 0 = JMRI Hardware Address 1

Very much thanks for the helps,
With what you have taught me I should be able to get by...

So If I was going to add another signal I could use hardware adress 3 and 4 for the second signal,
and that would be pins 5 & 6??? Am I right?


The CMRI sketch allows you to have up to 48 outputs. Though granted on an Uno there aren't that many pins.

In terms of which pin numbers you use, you can simply modify the sketch and choose the ones you want to use.

Wait, the outputs will be on digital pins 4 and 5

ok, Thanks for your help mate.
If I need anything else I will PM you.
but I should be fine from here with my basic electronics skills.

One final tutorial, this one using the Logix Table and Sensors.

For this tutorial, we'll setup a switch on pin 6 to control the state of the signal setup in the previous tutorial. I'm using pin 6 as the inputs_and_outputs sketch maps this to input Hardware address 1 with the following line of code:

cmri.set_bit(0, !digitalRead(6));

To use the switch we need a Sensor (JMRI's equivalent to an input).

(1) Open the Sensors Table. (Tools->Tables->Sensors)
(2) Click Add...
(3) Set the following:
System: CMRI
Hardware Address: 1
User Name: Switch
(4) Click OK. You should see your new switch appear. Mine has a system name of CS1 (CMRI Sensor 1)
(5) Connect a push button between pin 6 and GND. If you don't have a button, you can just use a piece of wire.
(6) When the button is unpressed (or the wire removed), you should see the sensor state as 'Inactive'. When the button is pressed (wire connected to gnd), you should see the sensor state as 'Active'

The button is now set up. So lets make JMRI control the signal based on the button. This is done using the Logix table.

(7) Go to Tools->Tables->Logix
(8) Click Add...
(9) Check the "Automatically Generate System Name" box
(10) Set the Logix user name to something like "Signal Control"
(11) Click "Create Logix" (if you see an error message about duplicate names, ignore it, its a bug)
(12) In the logix table, you should see your new Logix element. There is a button at the end of it which says "Select". Click on that, then click "Edit"
(13) Click the New Conditional button
(14) Enter a user name like "Button Pressed"
(15) Click "Add State Variable"
(16) Set the variable type to "Sensor"
Enter the sensor name, in my case CS1
Set the state to Active
and then click Update.
(17) Click "Add Action"
(18) Set the "Action Group" to "Signal Head"
Enter your signal head name from the previous tutorial. Mine was called CH1 (You can find this from the Signal Heads table)
Set the "Action Type" to "Set Signal Head Appearence"
Set the "Signal Head Appearance" to Green
Set the "Change Option" to "On change to true"
(19) Click Update. You should see your action appear
(20) Repeat steps 18 and 19, only this time select:
Set the "Signal Head Appearance" to Red
Set the "Change Option" to "On change to false"
(21) Click 'Update Conditional'. This saves your new Logix conditional.
(22) Click the 'Done' button to finish editing the Logix.

Your new Logix is set up. What you should see happening is that when you press the button connected to D6, the signal goes Green. When you release the button, the signal goes Red.

While you probably wont be using buttons, you may still find this tutorial useful. It is possible to set up Sensors which are virtual (i.e. have no Hardware Address). These sensors can be placed on virtual control panels.
Lets change that sensor to be virtual.
(23) Got to the Sensors table and click "Add..."
(24) Set the System to 'Internal'
Set the Hardware Address to 1
Set the User Name to "Virtual Button" (or anything of your choosing)
(25) Click OK.
(26) You should see a new sensor called IS1 (Internal Sensor Hardware Address 1)
(27) Go to the Logix Table
(28) Click the Select button next to your Logix and click Edit (The same as in step 11)
(29) Next to your conditional, click "Edit"
(30) Now you should see the conditional you set up previously. Click the Edit button next to the state variable (Sensor "CS1" state is Sensor Active)
(31) Change the sensor name to "IS1"
(32) Click Update, the Update Conditional, the Done.
(33) Your logix has been changed. If you go to the Sensor table again, you should see next to your internal sensor a button telling you its state.
(34) If you press that button you should now see your signal change from Red to Green depending on the state of this sensor.