JMRI Arduino Multi Servo control

In my blog I will be showing how to control more than one servo for turnouts using an Arduino Mega controlled by CMRI and JMRI.

First you will need to connect up the servos as shown below. I have used three servos with the data cables connected to pins 2, 3, 4 of the Arduino. I have not used pins 0 and 1 as these are alternative serial communication pins and may be needed later. The power supply of 5v dc  will be supplied by my bench power supply, do not power all your servos from the Arduino 5V pin as you will end up damaging the Arduino voltage regulator. Because we are using a separate power source to run the servos to the Arduino which for this exercise will be powered by the PC, then we will need to connect a ground wire from the bench power supply to the Arduino GND pin. so both Arduino and servos will have a common ground.

The Arduino code is shown below. This is mostly the same as the single servo code that was in a previous post "JMRI Arduino Servo control". The additional variables at the top "int turnout2 and 3" will add the additional 2 storage places for the bit data coming in from JMRI.

We then need to add two more servo control names to the arduino with Servo turnout2 and Servo turnout3.

Each servo will need to be setup with turnout2.attach(3) so servo 2 will be attached to Arduino pin 3 and then turnout3.attach(4) so servo 3 will be attached to Arduino pin 4.

Within the Void loop we will first read the incoming bits from JMRI and store them in the new variables turnout1 - 3. Each turnout on JMRI will have an address. The cmri.get_bit(0) for turnout1 will set the address on the Arduino. This will be address 1001 on the JMRI turnout tables.

Lastly we will use an 'IF' statement for each turnout to see if the incoming bit is equal to 1 or 0. If it is equal to 1 then move the servo to position 90. If not then it must be 0 so turn the servo to 0.

Hopefully this all makes sense. You will have to setup the servos to your layout points so that the servos are in the correct position when closed or thrown. There is a tutorial on this blog to show how this is done here.

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

#define CMRI_ADDR 1
#define DE_PIN 2 

int turnout1 = 0;
int turnout2 = 0;
int turnout3 = 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(2);
    turnOut1.write(0);
    turnOut1.attach(3);
    turnOut1.write(0);
    turnOut1.attach(4);
    turnOut1.write(0);
    bus.begin(9600);
}

void loop() {
    cmri.process();
    turnout1 = (cmri.get_bit(0));
    turnout2 = (cmri.get_bit(1));
    turnout3 = (cmri.get_bit(2));
    if (turnout1 == 1){
        turnOut1.write(90);
    } else {
        turnOut1.write(0);
    }
    if (turnout2 == 1){
        turnOut2.write(90);
    } else {
        turnOut2.write(0);
    }
    if (turnout3 == 1){
        turnOut3.write(90);
    } else {
        turnOut3.write(0);
    }
}

Next we will setup the JMRI turnout table. Open up PanelPro then select Tools > Turnouts from the menu to open the Turnouts table.

Click the add button to add a turnout to the table. The system connection will be C/MRI. The address for the first turnout1 will be 1001. This is taken from the Arduino code and is 1 digit on from the bit address in the code. Now give it a name and click create. Select "Use 1 bit" then select "Steady State Output". The first turnout should now be created and shown on the table. Do the same for turnout 2 and 3 with addresses 1002 and 1003.

Once this has been done and with the bench power supply switched on you should have control of all three servos.

If you want to now connect this to the JMRI layout check out my previous blog for a single servo control which should help you get this setup.

 

The Arduino code for multiple setups will get a bit large if we are using say 15+ servos. So below I have written a more streamlined code using 'Arrays' and 'FOR' loops

 

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

#define CMRI_ADDR 1
#define DE_PIN 2 

// remember all arrays start counting from 0

int turnOut_read_bit[3];  // setup and array for storing bits sent from JMRI. This will setup 3 variables

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 T[3]; // declare three servos with an array each having name T0 to T2

void setup() {
    for (int i=0; i<3; i++){   // for loop to run three times each time increment i by 1
        T[i].attach(i + 2);    // setup each servo with the arduino pins starting from pin 2 so we need to add 2 to i
        T[i].write(0);         // This may need to be setup outside the for loop for each servo if you have a different start position on each turnout
    }
    bus.begin(9600);
}

void loop() {
    cmri.process();
    for (int i=0; i<3; i++){                     // another for loop
        turnOut_read_bit[i] = (cmri.get_bit(i)); // read each bit sent from JMRI in to the array variables
    }
    for (int i=0; i<3; i++){     
        if (T[i] == 1){                Carry out the IF statement within a FOR loop
            T[i].write(90);
        } else {
            T[i].write(0);
        }        
    }
}

This will run the same as the previous code but has not been tested beyond 3 servos. I am not sure if the buffer for reading the bit inputs from JMRI will allow it to work within a FOR loop for more than three servos. If you have problems with this part then revert back to reading each bit outside a FOR loop.

On my YouTube video I show how all this is done and what current my servos are pulling.

I hope this is helpful please leave a comment and subscribe to my YouTube channel, thank you.

Leave a Reply