JMRI turnout control with external button control

In this demonstration I will be controlling a single turnout using the Servo.h library from JMRI turnout table and panel layout and also from an external push button. This will allow the turnout to be controlled directly from JMRI or I can have an external control panel which will also control the turnout. For this to work I needed to set up some routes so when the external button was operated JMRI was updated with the button state and then changed over the turnout.

First for the Arduino code. The initial setup would be mostly the same as the previous blog setting up a single turnout. This is not using the PC9685 to make the program as simple as possible. Within the header some added variables there for the button control. This is all to take out any noise from button bounce and is the same as the debounce example in the Arduino IDE examples.

Setup sorts out the turnout and switches, I am using the PULLUP internal resistor of the Arduino so no extra external components will be needed

The initial loop starts the cmri process then reads the bit being sent out by JMRI for the turnout. Then I run an IF statement to change the turnout depending on the bit state from JMRI.

Once this has been done I call the feedback-switch function. This will read the push button, check for any noise bounce on the switch and if found that the push button has been operated this function will toggle the control variable. This control variable will then be sent to the JMRI and update the sensor table for 'sw'.

Last function reads the micro switch attached to the turnout and sends this to JMRI to update sensor table 's1'.

// Library needed to run script //
#include <Servo.h>
#include <CMRI.h>
#include <Auto485.h>

// setup CMRI //
const int bus_addr_pin = 2;  //pin for TTL DE and RE pin
Auto485 bus(bus_addr_pin);
CMRI cmri(1, 24, 48, bus);

// turnout setup
int cmri_t1_bit = 0;
Servo Tout1;

// FEEDBACK SW attached to turnout//
const int feedbackSW = 7;
int feedbackState = 0;

// Control SW to control the turnout outside of JMRI//
const int controlSW = 6;
int controlSW_state;
int lastControlState = LOW;
int control = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; 

void setup(){
pinMode(feedbackSW, INPUT_PULLUP);
pinMode(controlSW, INPUT_PULLUP);
Tout1.write(10);  // set the turnout to a position. If you change this and the feedback switch is not made then you may need to invert the feedback swich bits

void loop (){
cmri_t1_bit = (cmri.get_bit(0));   // read the bit from JMRI that controls the turnout
if (cmri_t1_bit == 0){
    Tout1.write(0);                 // if the bit was equal to 0 then throw the turnout else close the turnout
if (cmri_t1_bit == 1){
readFeedbackSW();               // call the turnout feed back function
readSwitch(); // call the read external control switch function

/* This will read the push button, check for false feeds with a debounce delay then toggle variable control if the swich has been puched
Control will be update to JMRI SW sensor*/

void readSwitch(){
int reading = digitalRead(controlSW);
if (reading != lastControlState){
    lastDebounceTime = millis;
if((millis() - lastDebounceTime) > debounceDelay){
    if (reading != lastControlState){
    lastControlState = reading;
    if (lastControlState == HIGH){
        control = !control;
cmri.set_bit(1, control);

/* This will read teh turnout switch and feed back to JMRI sensor table */
void readFeedbackSW(){
feedbackState = digitalRead (feedbackSW);  
cmri.set_bit(0, feedbackState);

For JMRI Setup first I created a turnout within the turnout table address 1001 and named 't1'

Next I Setup two sensors, one for the feedback micro switch on address 1001 named 's1' and the other for the external push button on address 1002 named 'sw'

For 'sw' push button sensor I had to add additional debounce within JMRI as I was getting the odd false feed. To do this click on the edit button for 'sw' sensor and add 3 milliseconds to each delay box. You might have to adjust this yourself if you are still getting false triggers when operating the button.

Next I Setup the feedback sensor within the turnout table. Click on edit for 't1'. Along the top tabs click on feedback tab. Then add the following as shown below

For the layout panel add a turnout symbol by clicking on the RH turnout option at the top. Hold down the tab button on the keyboard and left click on the screen to add the turnout. Then right click this turnout, edit properties and assign the 't1' turnout to this turnout.

Finally I needed to Setup a route. This will trigger when the push button has been operated and the sensor table has detected a change in state for this sensor 'sw'. Create a new route, click on the edit button and add the following.

CT1001 click the include box, then in the drop down menu select 'Set Toggle'

Sensor 1 select 'sw' in the first option box, then select 'On Change' in the second option box.

Save this and now all the programming part should be done. Now I just needed to connect up the hardware

Connect a Servo to 5v and GND on the Arduino and control wire to pin 8 on the Arduino. Connect the turnout feedback micro switch between GND pin and pin 7 of the Arduino, Then connect a push button between GND and pin 6 on the Arduino.

That's it. Recheck all wiring and upload the Arduino sketch and hopefully this should now all be working from the push button or from the layout control of JMRI.



Cookie Policy

About Us

Privacy Policy

This site was created and designed by S Brackstone