First I'm new to Arduino. Have found a sketch that I have been using but have now hit a snag. The sketch which is intended to control servos on a model railroad was originally posted on the forum in Jan 22 by Iain_r and for the most part works. The problem I'm having is that only 4 servos (SG90) out of 8 servos connected to the PCA 9685 respond. I have defined “numServos ” to 8.
I have tested the servos and PCA9685 with Adafruit servo example and all work.
The Arduino Mega 2560 I’m using communicates with the controller (Pi running JMRI) with a library called CMRI. From the Pi I can see the correct CMRI traffic to tell the Mega to move servo 5 but the servo does not respond; 1 to 4 work as expected. Have replaced the PCA9685 and connected the PCA9685 to an UNO but it made no difference. PCA9685 is connected to a 5 volt power supply and the gnds are connected. Five volts to PCA is solid as tested with Fluke DVM.
From my testing I believe that the problem is with the sketch but after much reading and many changes I can not figure out where the problem lies.
/*
turnOp
This sketch operates a number of servos at a realistic speed taking the close (maxValue) and throw (minValue) commands from JMRI.
It also causes an associated relay to changes state as the turnout reaches its new position. This can be used for frog polarity switching, signals etc.
The sketch is based on two sketches compiled by Rob at Little Wicket Railway (links below)
https://github.com/LittleWicketRailway/ServoControl/blob/master/Servos.ino
https://github.com/LittleWicketRailway/SlowMoServos/blob/main/MillisFunctionImproved.ino
Starting with the servoControl sketch, sections from the MillisFunctionImproved sketch were added.
Development was then carried out with a considerable amount of advice from Wildbill on the Arduino Forum.
This sketch is currently running on a test bench operating four servos via an Arduino Mega with a PCA9685
NOTE:
minValve drives the servo right/clockwise, maxValve is left/anti-clockwise
Thrown sets the turnout to the divergent route. Closed sets the turnout to the straight route.
Iain Reeves Jan 2022
*/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <CMRI.h>
#include <Auto485.h>
#define CMRI_ADDR 1
#define DE_PIN 2
#define numServos 4 //The number of servos connected
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);
int Status[numServos]; //Create a table to hold the status of each turnout
//Create a table to hold the throw value for each servo
int minValue[numServos] = {1000, //LY1(turnout ID) - enter values obtained from the Little Wicket calibration sketch
1100, //LY2
1200, //LY3
1300}; //LY4
//Create a table to hold the close value for each servo
int maxValue[numServos] = {2000, //LY1
1800, //LY2
1900, //LY3
2000}; //LY4
int CurrentPosition[numServos]; // table to hold the current positions of each turnout
int StepSize = 5; // if you require servos operating at varying speeds use an array here int StepSize[numServos] = {5, 5, 3, 2}; to create a table to hold the step size for each turnout. Also add [i] to each StepSize term.
int DelayTime = 15; // if you require servos operating at varying speeds use an array here DelayTime[numServos] = {15, 15, 10, 5}; to create a table to hold the delay time for each turnout. Also add [i] to the DelayTime term.
// Create a table to hold the output pin for each turnout relay
int Relay[numServos] = {36, //LY1
38, //LY2
40, //LY3
42}; //LY4
unsigned long previousMillis[numServos]; // table to hold the previous movement time for each turnout
void turnOp(int inputPin, int i) //function to drive servos at slow speed
{
unsigned long currentMillis = millis();
if (((cmri.get_bit(i) != Status[i]) && (currentMillis - previousMillis[i] >= DelayTime))) // compares CMRI signal against state of turnout and checks sufficient time has passed since last movement
{
previousMillis[i] = currentMillis; // updates last movement time
if ((cmri.get_bit(i) == 1 )) // checks if (cmri.get_bit(i)is 1
{
if (CurrentPosition[i] < maxValue[i]) // then checks if current position value is less than maxValue - 'maxValue' used to account for L/R turnouts
{
CurrentPosition[i] = CurrentPosition[i] + StepSize; // if both the above statements are true, moves turnout by one step (increasing)
pwm.writeMicroseconds(i, CurrentPosition[i]); // updates current position
}
else
{
Status[i] = 1; // sets Status to 1
digitalWrite(Relay[i], LOW); // de-energises relay associated with turnout [i]
}
}
else
{
if (CurrentPosition[i] > minValue[i]) // checks if current position value is greater than minValue - 'minValue' used to account for L/R turnouts
{
CurrentPosition[i] = CurrentPosition[i] - StepSize; // moves turnout by one step (decreasing)
pwm.writeMicroseconds(i, CurrentPosition[i]); // updates current position
}
else
{
Status[i] = 0; // sets Status to 0
digitalWrite(Relay[i], HIGH); // energises relay associated with turnout [i]
}
}
}
}
void setup()
{
Serial.begin(9600);
bus.begin(9600);
pwm.begin();
pwm.setPWMFreq(50); // This is the maximum PWM frequency
int i;
// centre servos when JMRI gives first command
CurrentPosition[0] = 1500;
CurrentPosition[1] = 1500;
CurrentPosition[2] = 1500;
CurrentPosition[3] = 1500;
// set up relay pins
{
for (int i = 0; i < (numServos); i++)
pinMode(Relay[i], OUTPUT);
digitalWrite(Relay[i], HIGH);
}
}
void loop()
{
cmri.process();
for (int i = 0; i < (numServos); i++)
turnOp(2, i);
}




