Guidance request - combining code from two sketches for slow motion turnouts controlled from JMRI

I'm relatively new to the world of coding. I started out just cherry picking bits I wanted and tweaking minor things. I soon realised that there is a lot of info out there, which left me wallowing in information overload. Now I'm trying to work through the basics on a number of fronts.
Specifically I'm watching the Core Electronics Arduino Workshop on YouTube, reading through Arduino for Dummies and using the Sololearn app for structure practice.

So, enough about me. The problem I am currently having is this:

Rob at Little Wicket Railway has published two sketches parts of which I would like to combine (by the way, I have been in touch with Rob and he is happy for me to use/quote his sketches).
Specifically there is one script that drives turnouts with servos controlled from JMRI via CMRI
There is a second script that drives turnouts in slow motion using servos but activated by a pushbutton.
I have been attempting to get the slow motion action activated from JMRI. I naively thought it would just be a case of changing the input pin reference but that proved to be a bit optimistic.
I've been fiddling around for about a week now, so it's time to ask for help. If I wait until I've learnt enough I'll never get the railway built!

I have annotated the sketch with things I have tried (well, most of them. It took me a while to get into the habit of recording things as I did them).

Initially what I would like is some pointers on where I should concentrate my efforts and any specific guidance I should follow up. I'm definitely a person who learns by writing code rather than just reading other peoples work.

Here is the combined code as I have it at present. It compiles and uploads without issue but the servos persist in running at full speed.


// github.com/LittleWicketRailway/ServoControl/blob/master/Servos.ino
// github.com/LittleWicketRailway/SlowMoServos/blob/main/MillisFunctionImproved.ino

#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, signal, etc.
int Throw[numServos]; //Create a table to hold the throw value for each servo
int Close[numServos]; //Create a table to hold the close value for each servo

int CurrentPosition[4];  // added IR
int StepSize[4] = {50, 25, 15, 5}; // added IR - fourth value changed for servo (was LED)  Note: Differnt values for each servos in these two lines just to see how they behave
int DelayTime[4] = {100, 150, 200, 300}; // added IR - fourth value changed for servo
unsigned long previousMillis[4];    // added IR
//  for (int i = 0; i < numServos; i++)  // should I replace for loops in setup and loop with a global for loop?
//  int i;   // tried making i global variable but this caused only servo 0 to operate

void moveServos(int inputPin, int connection)  //function added, inputPin changed to DE_PIN, also added pinMode to setup.  This did not change servo speed so changed back to inputPin IR
{
  unsigned long currentMillis = millis();
  if ((digitalRead(inputPin) != Status[connection]) && (currentMillis - previousMillis[connection] >= DelayTime[connection]))
  {
    previousMillis[connection] = currentMillis;
    if (digitalRead(inputPin) == 1)
    {
      if (CurrentPosition[connection] < Close[connection])  // MaxValue changed to Close IR
      {
        CurrentPosition[connection] = CurrentPosition[connection] + StepSize[connection];
        pwm.writeMicroseconds(connection, CurrentPosition[connection]);
      }
      else
      {
        Status[connection] = 1;
      }
    }
    else
    {
      if (CurrentPosition[connection] > Throw[connection])  // MinValue changed to Throw IR
      {
        CurrentPosition[connection] = CurrentPosition[connection] - StepSize[connection];
        pwm.writeMicroseconds(connection, CurrentPosition[connection]);
      }
      else
      {
        Status[connection] = 0;
      }
    }
  }
}

void setup() {
  Serial.begin(9600);
  bus.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(50);  // This is the maximum PWM frequency
  pinMode(2, INPUT); //Added to refer to CMRI input but did not work IR
//  int i;
  for (int i = 0; i < 5; i = i + 1) // added IR - changed i < 4 to i < 5.  Tried taking this for loop out and declaring i separately (see line above) but it made no difference
  {
    CurrentPosition[i] = Throw[i]; // added IR - MinValue changed to Throw
  }

  //SET THE THROW AND CLOSE VALUES FOR EACH SERVO BASED ON THE CALIBRATION PROCESS

  //Servo connection 0 - point motor
  Throw[0] = 1000;
  Close[0] = 1600;

  //Servo connection 1 - point motor
  Throw[1] = 1100;
  Close[1] = 1675;

  //Servo connection 2 - point motor
  Throw[2] = 1200;
  Close[2] = 1750;

  //Servo connection 3 - point motor
  Throw[3] = 1300;
  Close[3] = 1800;
}

void loop() {

  cmri.process();

  moveServos[2, 0]; // added, inputPin ref changed to DE_PIN then 2  IR
  moveServos[2, 1]; // added IR
  moveServos[2, 2]; // added IR
  moveServos[2, 3]; // added IR

  for (int i = 0; i < numServos; i++)  //duplication?  IR  taking this section out stops servos operating at all
  {
    Status[i] = (cmri.get_bit(i));
    if (Status[i] == 1) {
      pwm.writeMicroseconds(i, Throw[i]);
    }
    else {
      pwm.writeMicroseconds(i, Close[i]);
    }
  }
  }
type or paste code here

Thanks for reading this far. I'm off to do some more practice exercises.

In moveServos, it looks like each servo had a pin to tell you which position its turnout should be in. It takes care of the slow move (or is intended to).

Now though, you're trying to use this to tell you the same thing:

cmri.get_bit(i)

I suggest that you move that into moveServos instead of the digitalRead you're using. You will likely then end up with some errors to correct. Also get rid of the pwm.writeMicroseconds stuff - it's fighting with the code in moveServos.

Thanks Bill,

I've had a quick play today. The last 8 lines have been disabled to get rid of the pwm conflict and I have replaced digitalRead with cmri.get_bit(i) within moveServos.

Apart from the minor format tweaks, the immediate issue was the need to declare i at some point. Time is limited today (work getting in the way of the important stuff), but here is what I've tried so far just to make sure I've understood you correctly. I'll have another go tomorrow.

//Original LWR servo_control sketch with 'added IR' sections from LWR SlowMoServos (Improved) sketch

// https://github.com/LittleWicketRailway/ServoControl/blob/master/Servos.ino
// https://github.com/LittleWicketRailway/SlowMoServos/blob/main/MillisFunctionImproved.ino

#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, signal, etc.
int Throw[numServos]; //Create a table to hold the throw value for each servo
int Close[numServos]; //Create a table to hold the close value for each servo

int CurrentPosition[4];  // added IR
int StepSize[4] = {50, 25, 15, 5}; // added IR - fourth value changed for servo (was LED)  Note: Differnt values for each servos in these two lines just to see how they behave
int DelayTime[4] = {100, 150, 200, 300}; // added IR - fourth value changed for servo
unsigned long previousMillis[4];    // added IR
//  for (int i = 0; i < numServos; i++)  // should I replace for loops in setup and loop with a global for loop?
//int i;   // tried making i global variable but this cauesd only servo 0 to operate

void moveServos(int inputPin, int connection)  //function added, inputPin changed to DE_PIN, also added pinMode to setup.  This did not change servo speed so changed back to inputPin IR
{
for (int i = 0; i < numServos; i=i+1) { // tried adding int = i, then for (int i = 0; i < numServos; i++), then for (int i = 0; i < numServos; i=i+1) for WB changes
  unsigned long currentMillis = millis();
  if (((cmri.get_bit(i) != Status[connection]) && (currentMillis - previousMillis[connection] >= DelayTime[connection]))) // (cmri.get_bit(i)) subbed in for digitalRead (WB)
  {
    previousMillis[connection] = currentMillis;
    if ((cmri.get_bit(i) == 1  ))// (cmri.get_bit(i)) subbed in for digitalRead (WB)
    {
      if (CurrentPosition[connection] < Close[connection])  // MaxValue changed to Close IR
      {
        CurrentPosition[connection] = CurrentPosition[connection] + StepSize[connection];
        pwm.writeMicroseconds(connection, CurrentPosition[connection]);
      }
      else
      {
        Status[connection] = 1;
      }
    }
    else
    {
      if (CurrentPosition[connection] > Throw[connection])  // MinValue changed to Throw IR
      {
        CurrentPosition[connection] = CurrentPosition[connection] - StepSize[connection];
        pwm.writeMicroseconds(connection, CurrentPosition[connection]);
      }
      else
      {
        Status[connection] = 0;
      }
    }
  }
}
}


void setup() {
  Serial.begin(9600);
  bus.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(50);  // This is the maximum PWM frequency
  pinMode(2, INPUT); //Added to refer to CMRI input but did not work IR
  //  int i;
  for (int i = 0; i < 5; i = i + 1) // added IR - changed i < 4 to i < 5.  Tried taking this for loop out and declaring i separately (see line above) but it made no difference
  {
    CurrentPosition[i] = Throw[i]; // added IR - MinValue changed to Throw
  }

  //SET THE THROW AND CLOSE VALUES FOR EACH SERVO BASED ON THE CALIBRATION PROCESS

  //Servo connection 0 - point motor
  Throw[0] = 1000;
  Close[0] = 1600;

  //Servo connection 1 - point motor
  Throw[1] = 1100;
  Close[1] = 1675;

  //Servo connection 2 - point motor
  Throw[2] = 1200;
  Close[2] = 1750;

  //Servo connection 3 - point motor
  Throw[3] = 1300;
  Close[3] = 1800;
}

void loop() {

  cmri.process();

  moveServos[2, 0]; // added, inputPin ref changed to DE_PIN then 2  IR
  moveServos[2, 1]; // added IR
  moveServos[2, 2]; // added IR
  moveServos[2, 3]; // added IR

  //  for (int i = 0; i < numServos; i++)  //duplication?  IR  taking this section out stops servos operating at all  - 8 lines taken out (WB)
  //  {
  //    Status[i] = (cmri.get_bit(i));
  //    if (Status[i] == 1) {
  //      pwm.writeMicroseconds(i, Throw[i]);
  //    }
  //    else {
  //      pwm.writeMicroseconds(i, Close[i]);
}

It appears to me that the connection parameter was intended to specify the servo to work on, which explains why there are four calls to moveServo.

You could keep it that way and use connection instead of i or call once and use i instead of connection.

It needs to be one or the other though.

Thanks. I'll give that a try when I get home.

I've tried both routes. The 'use i instead of connection' option looks neater to me. Still playing (and reading up on functions) but taking a break as I think I'm going round in circles. My next step is to tidy up the sketch and clear out some of the older notes.

Making some progress now. In this form the first servo operates in slow motion from JMRI. However, the other three remain inert. I thought it was related to the lack of a for loop but what I've tried so far (see the notes within the sketch) has not improved matters (actually it stopped the servos operating at all).

I did try another version of the for loop using numServos instead of the fixed number 4 but that threw up a load of errors, so I'll be looking at those when I next get a chance.

One other issue is that the servo goes hard right when JMRI opens up, which is not going to do the servo mounts or turnouts any good. I suspect that I will have to take this into account when I'm mounting and calibrating the servos. Positioning the operating arm so that the required right position is close to the limit of travel should do the trick.

Anyway, here's the sketch in its current form:

//Original LWR servo_control sketch with 'added IR' sections from LWR SlowMoServos (Improved) sketch
//WB indicates changes made following advice from Wildbill on the Arduino Forum

// https://github.com/LittleWicketRailway/ServoControl/blob/master/Servos.ino
// https://github.com/LittleWicketRailway/SlowMoServos/blob/main/MillisFunctionImproved.ino

#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, signal, etc.
int Throw[numServos];  //Create a table to hold the throw value for each servo
int Close[numServos];  //Create a table to hold the close value for each servo

int CurrentPosition[numServos];  // added IR 4 changed to numServos
int StepSize[numServos] = {5, 25, 15, 5}; // added IR - fourth value changed for servo (was LED)  Note: Differnt values for each servos in these two lines just to see how they behave - 4 changed to numServos
int DelayTime[numServos] = {15, 150, 200, 300}; // added IR - fourth value changed for servo - 4 changed to numServos
unsigned long previousMillis[numServos];    // added IR - 4 changed to numServos

  void moveServos(int inputPin, int i)  //function added IR - int i substituted in for int connection (WB)
{
  unsigned long currentMillis = millis();

  //  for (int i = 0; i < 4; i=i++)  // added for loop here, unsuccessful, no servos operated IR - tried numServos in place of 4 (this location only) -  gave an Error which requires further investigation

  if (((cmri.get_bit(i) != Status[i]) && (currentMillis - previousMillis[i] >= DelayTime[i]))) // (cmri.get_bit(i)) substituted in for digitalRead (WB)- i substituted in for connection (WB)
  {
    previousMillis[i] = currentMillis;  // i substituted in for connection (WB)
    if ((cmri.get_bit(i) == 1  ))// (cmri.get_bit(i)) substituted in for digitalRead (WB)
    {
      if (CurrentPosition[i] < Close[i])  // MaxValue changed to Close IR - i substituted in for connection (WB)
      {
        CurrentPosition[i] = CurrentPosition[i] + StepSize[i]; // i substituted in for connection (WB)
        pwm.writeMicroseconds(i, CurrentPosition[i]);  // i substituted in for connection (WB)
      }
      else
      {
        Status[i] = 1;  //i substituted in for connection (WB)
      }
    }
    else
    {
      if (CurrentPosition[i] > Throw[i])  // MinValue changed to Throw IR - i substituted in for connection (WB)
      {
        CurrentPosition[i] = CurrentPosition[i] - StepSize[i];  // i substituted in for connection (WB)
        pwm.writeMicroseconds(i, CurrentPosition[i]); //  i substituted in for connection (WB)
      }
      else
      {
        Status[i] = 0;  // i substituted in for connection (WB)
      }
    }
  }
}


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

  int i;  // tried for loop here, unsuccessful, no servos operated IR

  {
    CurrentPosition[i] = Throw[i]; // added IR - MinValue changed to Throw
  }

  //SET THE THROW AND CLOSE VALUES FOR EACH SERVO BASED ON THE CALIBRATION PROCESS

  //Servo connection 0 - point motor
  Throw[0] = 1000;
  Close[0] = 2000;

  //Servo connection 1 - point motor
  Throw[1] = 1100;
  Close[1] = 1675;

  //Servo connection 2 - point motor
  Throw[2] = 1200;
  Close[2] = 1750;

  //Servo connection 3 - point motor
  Throw[3] = 1300;
  Close[3] = 1800;
}

void loop()
{
  cmri.process();

  int i;  //  tried for loop here, unsuccessful, no servos operated  IR

  moveServos(2, i); // added, inputPin ref changed to DE_PIN then 2  IR  // i substituted in for connection (0), individual moveServo functions removed (WB)
}

In loop your i variable has no value assigned. Try giving it a servo number and run the code. Probably worth checking it with each number (0-3) in turn.

It sounds like I was heading off down a blind alley with the for loop. Thanks for saving me from that.

BINGO!

I tried the individual servos as you suggested - all good.

Then I edited the loop to:

void loop()
{
  cmri.process();
  
  for (int i = 0; i < 4; i=i++)  //  added  IR
  
    moveServos(2, i); // added, inputPin ref changed to DE_PIN then 2  IR  // i substituted in for connection (0), individual moveServo functions removed (WB)
}

This didn't move any of the servos. I then changed the last term of the for loop from i=i++ (copied from one of the original sketches) to i++. SUCCESS!!! All four servos responding to CMRI with slow operating speed.

Then I got carried away and altered the term 4 in the for loop to [NumServos], which threw out a load of error messages. I can't say that reading the error messages helped much but I changed the parenthesis (guesswork) to (NumServos) and away we go again.

Thanks for all the help getting this going. I'm going to attempt adding a relay operation to each turnout next. If (when) I get stuck on that I'll post it as a new tread.

Upper & lower case are important in C++. NumServos doesn't exist in your code, numServos does.

If you have new questions, consider adding to this thread - it helps folks trying to help to see the history. Of course, if it really is a separate issue, it may be better to start a new one.

Good point on the cases. I had actually used numServos in the sketch but got a bit over-enthusiastic when I was typing here. I also take your point on adding further developments to this thread. I'll report back on developments as they occur.

For the benefit of anyone following this topic, here is a tidied up version of the working sketch in its current form:

/*
This sketch operates a number of servos at a realistic speed taking the close/throw commands from JMRI
It 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

This sketch is based on the servoControl sketch with 'added IR' indicating sections from the MillisFunctionImproved sketch
'WB' indicates changes made following 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

WARNING - the servos tend to kick to full deflection right as they are operated for the first time after JMRI opens, so care will be needed to ensure this does not damage servos/turnouts when in use on a layout
*/

#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, signal, etc.
int Throw[numServos];  //Create a table to hold the throw value for each servo
int Close[numServos];  //Create a table to hold the close value for each servo

int CurrentPosition[numServos];  // added IR '4' changed to 'numServos'
int StepSize[numServos] = {5, 5, 5, 5}; // added IR - fourth value changed for servo (was LED) - '4' changed to 'numServos'
int DelayTime[numServos] = {15, 15, 15, 15}; // added IR - fourth value changed for servo - '4' changed to 'numServos'
unsigned long previousMillis[numServos];    // added IR - '4' changed to 'numServos'

void moveServos(int inputPin, int i)  //function added IR - 'int i' substituted in for 'int connection' (WB)
{
  unsigned long currentMillis = millis();

    if (((cmri.get_bit(i) != Status[i]) && (currentMillis - previousMillis[i] >= DelayTime[i]))) // '(cmri.get_bit(i)' substituted in for 'digitalRead' (WB)- 'i' substituted in for 'connection' (WB)
  {
    previousMillis[i] = currentMillis;  // 'i' substituted in for 'connection' (WB)
    if ((cmri.get_bit(i) == 1  ))// '(cmri.get_bit(i)' substituted in for 'digitalRead' (WB)
    {
      if (CurrentPosition[i] < Close[i])  // 'MaxValue' changed to 'Close' IR - 'i' substituted in for 'connection' (WB)
      {
        CurrentPosition[i] = CurrentPosition[i] + StepSize[i]; // 'i' substituted in for 'connection' (WB)
        pwm.writeMicroseconds(i, CurrentPosition[i]);  // 'i' substituted in for 'connection' (WB)
      }
      else
      {
        Status[i] = 1;  // 'i' substituted in for 'connection' (WB)
      }
    }
    else
    {
      if (CurrentPosition[i] > Throw[i])  // 'MinValue' changed to 'Throw' IR - 'i' substituted in for 'connection' (WB)
      {
        CurrentPosition[i] = CurrentPosition[i] - StepSize[i];  // 'i' substituted in for 'connection' (WB)
        pwm.writeMicroseconds(i, CurrentPosition[i]); //  'i' substituted in for 'connection' (WB)
      }
      else
      {
        Status[i] = 0;  // 'i' substituted in for 'connection' (WB)
      }
    }
  }
}


void setup()
{
  Serial.begin(9600);
  bus.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(50);  // This is the maximum PWM frequency
  int i;  // added IR

  {
    CurrentPosition[i] = Throw[i]; // added IR - 'MinValue' changed to 'Throw'
  }

  //SET THE THROW AND CLOSE VALUES FOR EACH SERVO BASED ON THE CALIBRATION PROCESS

  //Servo connection 0 - point motor
  Throw[0] = 1000;
  Close[0] = 2000;

  //Servo connection 1 - point motor
  Throw[1] = 800;
  Close[1] = 2200;

  //Servo connection 2 - point motor
  Throw[2] = 1200;
  Close[2] = 2300;

  //Servo connection 3 - point motor
  Throw[3] = 1300;
  Close[3] = 1800;
}

void loop()
{
  cmri.process();
  
  for (int i = 0; i < (numServos); i++)  //  added  IR
  
    moveServos(2, i); // added, 'inputPin' changed to '2'  IR  // 'i' substituted in for 'connection' (0), individual moveServo functions removed (WB)
}

Hi Bill,

I've tried to take the "Solution" tag off this as there is an outstanding problem. I reloaded the original Servo control sketch and the issue with the hard right kick on the servos as they are first operated is not present. I've started comparing the two sketches to see if I can identify where the issue lies. I started with the setup (as the problem is only apparent once) and took out the term CurrentPosition[i] = minValue but this made no improvement. Having said that, not having it in the sketch does not seem to do anything detrimental either.

On a more positive note, I have incorporated the frog polarity relays without too much trouble.
Here is the current version of the sketch. I have changed Throw and Close to minValue and maxValue to avoid confusion with Left and Right handed turnouts.

/*
This sketch operates a number of servos at a realistic speed taking the close (maxValue) and throw (minValue) commands from JMRI
It 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

This sketch is based on the servoControl sketch with 'added IR' indicating sections from the MillisFunctionImproved sketch
'WB' indicates changes made following 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

WARNING - the servos tend to kick to full deflection right as they are operated for the first time after JMRI opens, so care will be needed to ensure this does not damage servos/turnouts when in use on a layout
*/

#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
int minValue[numServos];  //Create a table to hold the throw value for each servo
int maxValue[numServos];  //Create a table to hold the close value for each servo

int CurrentPosition[numServos];  // table to hold the current positions of each turnout
int StepSize[numServos] = {5, 5, 5, 5}; // table to hold the step size for each turnout
int DelayTime[numServos] = {15, 15, 15, 15}; // table to hold the delay time for each turnout
int Relay[numServos] = {36, 38, 40, 42};  // table to hold the output pin for each turnout frog rely NEW
unsigned long previousMillis[numServos];    // table to hold the previous movement time for each turnout

void moveServos(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[i]))) //  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 is less than maxValue - 'MaxValue' used to account for L/R turnouts
      {
        CurrentPosition[i] = CurrentPosition[i] + StepSize[i]; // if both the above statements are true, moves turnout by one step
        pwm.writeMicroseconds(i, CurrentPosition[i]);  
      }
      else
      {
        Status[i] = 1;
        digitalWrite(Relay[i], LOW);  // de-energises relay associated with turnout [i] NEW
      }
    }
    else
    {
      if (CurrentPosition[i] > minValue[i])  // 'MinValue' used to account for L/R turnouts
      {
        CurrentPosition[i] = CurrentPosition[i] - StepSize[i];
        pwm.writeMicroseconds(i, CurrentPosition[i]);
      }
      else
      {
        Status[i] = 0;
        digitalWrite(Relay[i], HIGH); // energises relay associated with turnout [i] NEW
      }
    }
  }
}


void setup()
{
  Serial.begin(9600);
  bus.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(50);  // This is the maximum PWM frequency
  int i; 
  
  // set up relay pins   NEW
  
 for (int i = 0; i < (numServos); i++) 
  
  pinMode(Relay[i], OUTPUT);
  digitalWrite(Relay[i], HIGH);  

  {
//    CurrentPosition[i] = minValue[i]; //  took this out and it appears to do nothing
  }

  //SET THE minValue AND maxValue VALUES FOR EACH SERVO BASED ON THE CALIBRATION PROCESS

  //Servo connection 0 - point motor
  minValue[0] = 1000;
  maxValue[0] = 2000;

  //Servo connection 1 - point motor
  minValue[1] = 1000;
  maxValue[1] = 2000;

  //Servo connection 2 - point motor
  minValue[2] = 1000;
  maxValue[2] = 2000;

  //Servo connection 3 - point motor
  minValue[3] = 1000;
  maxValue[3] = 2000;
}

void loop()
{
  cmri.process();
  
  for (int i = 0; i < (numServos); i++) 
  
    moveServos(2, i); 

}

The classic issue with using hobby servos is that you get no feedback from them to tell you what position they're currently in. In consequence, depending on where they are at startup, you may see a "kick" when you first command them as they jump to the newly commanded position.

Usually, this is when you run the attach command. In your case as you're using a PWM library to control them, I'm not sure when this will occur.

One solution is to have a power down routine that you run when you're done to set the turnouts to known positions.

Another is to get (more expensive) digital servos that can report where they are.

Thanks, I will have another look in a couple of days.