Control 16 turnouts using PCA9685 with CMRI

Moving on with controlling turnouts with servos, thanks to a comment on my blog from Erik I have now been experimenting with PCA9685 cards which allow you to control 16 turnouts on each card only using two pins from the Arduino i2C communication. On the mega board this will be pins 20 and 21 and on the UNO this will be A4 and A5. The PCA9685 can be connected to other PCA9685 in a serial linkup allowing each card to be separately addressed and control 16 servos. Apparently you can connect up to 62 boards giving a possible 992 servo controls. Which means your only limitation is the JMRI CMRI 48 addresses and your power supply capacity.

For this blog I will be showing how I set this up to be controlled by JMRI using the CMRI library. For full information on the PCS9685, how to connect it up and set addresses and specifications you are best to check out the Adafruit web site here.

I will be demonstrating controlling two servos. The wiring will be as shown below. I will have two connected servos on the first two sets of pins. For addresses the first pins are address 0 (zero) and the second pins are address 1 and so on. The board address solder pads have not been touched so the board address will be 0 (zero).



For the Arduino code first we need to get the library from Adafruit and put it into your Arduino library directory. Click on the link below and download the zip folder. Open the folder and copy the content file "Adafruit-PWM-Servo-Driver-Library-master"  into your Arduino library folder which will be found in you Arduino folder probably in your Documents folder.

Arduino library

Now restart the Arduino IDE if you already had it running. If all has gone well you should now have the Adafruit PWM servo example at the bottom of the example tab.

img

For my code the top part we will include the wire, Adafruit_PWMServoDriver, CMRI and Auto485 library as shown below.

 
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <CMRI.h>
#include <Auto485.h>
            


Next I will setup the CMRI and Auto485 the same as previous examples but will include the PWM servo setup with no numbers in the brackets as this will be a single board on address 0

#define CMRI_ADDR 1
#define DE_PIN 2
int Tbit[2];

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); //setup the board address 0
Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
CMRI cmri(CMRI_ADDR, 24, 48, bus);
            

The setup will be as shown below

void setup() {
Serial.begin(9600);
bus.begin(9600);
pwm.begin();
pwm.setPWMFreq(60);  // This is the maximum PWM frequency
}
            

Finally the void loop. I will be reading the CMRI bit from JMRI as previously done

   
Tbit[0] = (cmri.get_bit(0)); //TMU1
Tbit[1] = (cmri.get_bit(1)); //TBD1
            

The If statements will be similar to the Servo control and PL-11 control as previously done but this time within the IF statement we will be sending out a signal to the PCA9685 to control the servos. This is done with PWM.setPWM(0, 0, 200); where the first number is the servo address, the second number is the board address (for this example board address is 0) and the last number is the position of the servo to be moved to.

   
if (Tbit[0] == 1){
    pwm.setPWM(0, 0, 170);
    Serial.println("throw");
}
            

The full code to control the two servos which will be connected to the first two sets of pins address 0 and address 1 is shown below

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <CMRI.h>
#include <Auto485.h>

#define CMRI_ADDR 1
#define DE_PIN 2 
int Tbit[2];

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); //setup the board address 0
Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
CMRI cmri(CMRI_ADDR, 24, 48, bus); 


void setup() {
Serial.begin(9600);
bus.begin(9600);
pwm.begin();
pwm.setPWMFreq(60);  // This is the maximum PWM frequency
//pwm.setPWM(0, 0, 150);
//pwm.setPWM(1, 0, 200);

}

void loop(){
cmri.process();
Tbit[0] = (cmri.get_bit(0)); //TMU1
Tbit[1] = (cmri.get_bit(1)); //TBD1

if (Tbit[0] == 1){
    pwm.setPWM(0, 0, 170);
    Serial.println("trow");
}
if (Tbit[0] == 0){
    pwm.setPWM(0, 0, 150);
    Serial.println("close");
}
if (Tbit[1] == 1){
    pwm.setPWM(1, 0, 100);
}
if (Tbit[1] == 0){
    pwm.setPWM(1, 0, 200);
}
}
            


One last thing to mention. The power supply for the servos 5v does not have to come from the PCA card. On my layout I have a 5v power supply bus line going around the base board so I tap of this for the servo 5v power and send the one cable signal wire to the PCA9685. This reduces the wiring on the layout. Also the supply for the PCA9685 is 5v so can also come from the same 5V  supply instead of the Arduino. The only connection from the Arduino to the PCA card are the SCL and SDA cables, so you could move this PCA card closer to all your turnouts to be controlled and run the SDA SDL cables to the card again reducing more wiring.

Next will be setting up JMRI turnout table which will be the same as previous setups with a single bit steady state pulse. First open the turnout table as shown below.

img

Within the turnout table click on add a turnout button, ensure you have the CMRI selected as the system connection drop down selection box. Make the address 1001 which will be for CMRI bit 0. Give it a name and click create. Select 1 bit as we will only be using one address bit on JMRI and steady state so we will always have a 1 or 0 as a constant bit and not a pulse.

With this setup and all communication working with my Arduino and JMRI I can now control the servos with JMRI through the Arduino to the PCA9685.


Comments



13

Cookie Policy

About Us

Privacy Policy

This site was created and designed by S Brackstone

email: motorhome.sites.org@gmail.com