JMRI Arduino Servo control

In this blog I will be setting up a servo to control a turnout on my layout using JMRI as the interface on the computer and the Arduino as CMRI interface.

First I had to connect up the servo to the Arduino. I have a number of Tower Pro SG90 which i picked up cheap on ebay. They work very well for the price. The wiring colors are shown below.

brown = GND

red = +5v

orange = data line (in this blog i have this connected to pin 9)

Below is the arduino code for the servo control. There are a few lines different from the previous blog on setting up the Arduino to the JMRI. First I have added the servo library at the top #include <Servo.h>, I have created a variable called turnout1 which will store the incoming bit from JMRI. I have setup this servo to be called turnout1 with Servo turnOut1; you can set many servos up like this with different names. In the setup I have started the servo library and set the servo to zero position. When you have setup your servo on a turn out you can set this part in setup so the turnout always starts in the same position when the Arduino is turned on. I will be going over the setup later. Finally I have setup an if statement that will turn the servo one way if the incoming bit 47 is equal to 1 and back to the startup position if the bit is equal to 0. For this demonstration I have also used bit 47 so you can see we have 48 input and outputs from one Arduino with zero being address 1.

#include <CMRI.h>
#include <Auto485.h>
#include <Servo.h>

#define CMRI_ADDR 1

#define DE_PIN 2
int turnout1 = 0;

Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
CMRI cmri(CMRI_ADDR, 24, 48, bus); // defaults to a SMINI with address 0. SMINI = 24 inputs, 48 outputs
Servo turnOut1;

void setup() {
 turnOut1.attach(9);
 turnOut1.write(0);
 bus.begin(9600);
}

void loop() {

cmri.process();
 turnout1 = (cmri.get_bit(47));
 if (turnout1 == 1){
 turnOut1.write(90);
 }
 else{
 turnOut1.write(0);
 }
}

Once you have uploaded this to your Arduino, start up JMRI and open your panel as shown in the previous blog. Now select the turnout table and click on add so we can add this turnout. The address for this will be 1048 and the name can be what ever you want. Below is a picture of my setup.

Now click OK select use 1 bit and steady state. You should now see your turnout on the table. Go ahead and select the button below Cmd tab and your Arduino should change the servo state on each click. We now have control of a servo through JMRI and an Arduino. With this basic setup you could control 48 servos (turnouts) with one Arduino.

If this is all you need to do then just remember the power supply for 48 servos cannot come from the Arduino as shown in the picture. You will need to give a separate power supply for this servos and only the control wire for the servos from the Arduino. The GND from the external power supply and the Arduino GND will need to be connected together for this to work properly.

Lets now add a light to the arduino code and to the light table in JMRI so that the light changes state then the turnout has been thrown. First change the Arduino code so it is as shown below.

#include <CMRI.h>
#include <Auto485.h>
#include <Servo.h> #define CMRI_ADDR 1 #define LED 13 #define DE_PIN 2 int turnout1 = 0; Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins CMRI cmri(CMRI_ADDR, 24, 48, bus); // defaults to a SMINI with address 0. SMINI = 24 inputs, 48 outputs Servo turnOut1; void setup() { pinMode (LED, OUTPUT); turnOut1.attach(9); turnOut1.write(0); bus.begin(9600); } void loop() { cmri.process(); digitalWrite (LED, cmri.get_bit(0)); turnout1 = (cmri.get_bit(47)); if (turnout1 == 1){ turnOut1.write(90); } else{ turnOut1.write(0); } }

This has added pin 13 on the arduin to turn on with bit 0 from JMRI as shown in the setup blog (remember JMRI must be shut down when uploading Arduino code or you will get a communication conflict). One uploaded open JMRI and open your panel. Go to the tables and select the light table. Click add and enter the address 1001 and a name for your light. We will now add a control, click on control and in the control type select turn out status. Then give it the turnout name you setup above. We will turn on the LED when the turnout has been thrown so select Thrown in the status for on menu click create new then create new in the other window and you should have a light created in the table.

Now go back to the turnout table and click on the thrown/close button. Each time the status is thrown the LED on the Arduino should turn on. So we can set this up to put a red signal on when the turnout has been thrown.

Finnaly for this blog entry we will create a panel with a turn out that will operate our turnout on our layout. On the panelPro main page click on Panels > New Panel > Layout Editor

You should now have a panel as shown below. Ensure the tick box for type RH has been selected as shown below. then on the canvas hold down the shift button on you keyboard and left click on the canvas to insert a turnout.

You should now have a turn out on your canvas as shown to the right. At the moment this will not do anything as it has not been assigned to your turnout table. Right click on the turnout and select edit. An edit window will open for this turnout. The turnout name will have to be the turnout name you used in your turnout table, click done. You have now assigned the turnout table to this layout turnout. Click on the turnout on the canvas and if all has gone correct the servo should change state on each click.

4 Comment

  1. Miguel Rodrigues says: Reply

    Hi Setece,

    Can I trouble you for a little help?

    I have a CMRI Arduino with the code for a turntable.
    I setup the turnouts on JMRI turnout table and in the layout editor
    When I use the turnout table everything works, every time, it doesn’t matter if the turnout state is closed or thrown.
    When I’m in the layout editor it only works if the turnout state is Closed…

    I already read the manual over and over at some point they refer to “…To set the turntable to the desired position, simply click on the ray that you wish the turntable to be aligned with….” And that’s true, but only if the state is Closed, if it is Thrown it does nothing, there is no activity on the CMRI Monitor.

    if you want I can send you the code and a small video demonstrating the problem.
    Sorry if I’m imposing and appreciate any help you can provide.
    Miguel
    miguelcarmor gmail com

    1. admin says: Reply

      Sorry Miguel I have not done any testing on turntables yet. I am hoping to run my turntable with a stepper motor using an arduino. By the sound of it your problem may be a JMRI setting problem. Might be worth posting it on the yahoo group good luck

  2. Dennis says: Reply

    Hi,

    I wonder how to setup a second and more servo’s on this sketch and how to connect. I use a PCA9685 breakout board

    Greeting Dennis

    1. admin says: Reply

      Hi Dennis
      I am unable to test this as I have dismantled my set at present but from memory try the following.
      In JMRI setup another turnout in the turnout panel make it a different address like 1047 should work.

      The Arduino sketch might work as shown below with the second turn out connected to pin 8. This has not been tested so try and error will be needed

      #include
      #include
      #include

      #define CMRI_ADDR 1

      #define DE_PIN 2
      int turnout1 = 0;
      int turnout2 = 0; // initialise the second turn out variable

      Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
      CMRI cmri(CMRI_ADDR, 24, 48, bus); // defaults to a SMINI with address 0. SMINI = 24 inputs, 48 outputs
      Servo turnOut1;
      Servo turnout2;

      void setup() {
      turnOut1.attach(9);
      turnOut1.write(0);
      turnOut2.attach(8);
      turnOut2.write(0);
      bus.begin(9600);
      }

      void loop() {

      cmri.process();
      turnout1 = (cmri.get_bit(47));
      if (turnout1 == 1){
      turnOut1.write(90);
      }
      else{
      turnOut1.write(0);
      }

      turnout2 = (cmri.get_bit(46));
      if (turnout2 == 1){
      turnOut2.write(90);
      }
      else{
      turnOut2.write(0);
      }
      }

      See if this will work, if it does then just duplicate the code for each turnout. If it works and you require a lot turnouts then you coule use FOR loops for some of the code to reduce the writing

Leave a Reply