Hello,
My first post and something of a catch up from school days and feel like I'm climbing Mount Snowdon, so please bear with me as I'm trying to relearn.
OK, so my project is a semaphore railway signal control - its to replace the RTR base of a Dapol OO signal's original vertical motor . I have gone through the early projects of servo control using a potentiometer etc and then came across @gingerangles project on his semaphore signalling and thought rather that try and re-invent the wheel myself, use a sketch someone has already done. ( Programming for realistic semaphore control using PCA 9685
Now, just to make clear, I have had the servo working fine up until I changed to the below sketch, which just boots up and starts the servo motor spinning round and around as if its pulsing. i cant get it to stop or reverse.
its wired as above and has the triggers to pins 2,3, & 4. Sadly I think jumping in to this level its gone a bit over my head which I will admit may be wrong to have done, But if anyone can help out as to why my servo is spinning and not moving as prescribed would be great
Andy
//move_signals_17
//https://forum.arduino.cc/t/programming-for-realistic-semaphore-control-using-pca-9685/1283543
//NOTE : dangerPWM must always be less than clearPWM
//https://forum.arduino.cc/t/programming-for-realistic-semaphore-control-using-pca-9685/1283543/54
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver signalBoard01 = Adafruit_PWMServoDriver(0x40);
enum states
{
AT_DANGER, //each signal can be in any one of the following states
AT_CLEAR,
MOVING_TO_DANGER,
MOVING_TO_CLEAR,
BOUNCING_AT_DANGER,
BOUNCING_AT_CLEAR
};
struct signalData //struct for signal variables
{
int currentPWM; //current PWM value
unsigned long lastMoveTime; //time of last move
states currentState; //current state of signal
boolean moveDone; //true if the move to a new state is finished
boolean bounceDone; //flag to prevent bouncing being repeated
int bounceCount; //counter for bounces
boolean bounceAway; //true if bouncing away from end position
int bounceDistance; //distance to bounce
};
struct signalDefs //signal definitions
{
const byte swPinNum; //switch pin number
const int clearPWM; //PWM value for clear signal
const int dangerPWM; //PWM value for danger signal
const byte pwmChannel; //servo channel number
const byte dangerInterval; //interval between steps to danger. Lower values are faster
const byte clearInterval; //unterval between steps to clear
const unsigned int dangerBounceInterval; //interval between danger bounces
const byte dangerNumBounces; //number of bounces to perform at danger
const byte dangerBouncePercent; //percentage of total movement to bounce when reaching danger
const unsigned int clearBounceInterval; //interval between danger bounces
const byte clearNumBounces; //number of bounces to perform at danger
const byte clearBouncePercent; //percentage of total movement to bounce when reaching danger
};
signalDefs signals[] = {
//pin no, clear PWM, danager PWM, PWM Channel, danger Interval, clear Interval, danger: Bounce interval; Bounce No; Bounce %, clear: Bounce interval; Bounce No; Bounce %
{ 3, 150, 115, 0, 15, 10, 100, 5, 40, 200, 0, 50 },
{ 4, 200, 130, 1, 15, 10, 100, 5, 40, 200, 0, 50 },
{ 5, 360, 200, 2, 2, 2, 130, 4, 50, 100, 2, 20 },
};
const byte signalCount = sizeof(signals) / sizeof(signals[0]);
signalData sigVars[signalCount];
unsigned long currentTime;
void setup()
{
Serial.begin(115200);
Serial.println("GingerAngles Signal Control!");
signalBoard01.begin();
signalBoard01.setPWMFreq(50); // Analog servos run at ~60 Hz updates
initialse();
}
void loop()
{
for (int s = 0; s < signalCount; s++)
{
currentTime = millis();
byte currentSwitchState = digitalRead(signals[s].swPinNum);
switch (sigVars[s].currentState)
{
case AT_DANGER:
if (signals[s].dangerNumBounces > 0 && sigVars[s].bounceDone == false)
{
sigVars[s].currentState = BOUNCING_AT_DANGER;
Serial.print(signals[s].pwmChannel);
Serial.println(" bouncing at danger");
// sigVars[s].bounceDone = false;
sigVars[s].lastMoveTime = currentTime + signals[s].dangerBounceInterval; //force immediate bounce BBB
sigVars[s].currentPWM = signals[s].dangerPWM;
sigVars[s].bounceCount = 0;
sigVars[s].bounceAway = true;
sigVars[s].bounceDistance = (signals[s].clearPWM - signals[s].dangerPWM) / (100 / signals[s].dangerBouncePercent); //initial bounce back distance
}
else if (currentSwitchState == LOW) //the switch is closed
{
sigVars[s].currentState = MOVING_TO_CLEAR;
Serial.print(signals[s].pwmChannel);
Serial.println(" moving to clear");
sigVars[s].moveDone = false;
sigVars[s].lastMoveTime = currentTime;
}
break;
case MOVING_TO_CLEAR:
moveTowardsClear(s);
if (sigVars[s].moveDone == true)
{
sigVars[s].currentState = AT_CLEAR;
Serial.print(signals[s].pwmChannel);
Serial.println(" arrived at clear");
sigVars[s].moveDone = false;
sigVars[s].bounceDone = false;
}
break;
case AT_CLEAR:
if (signals[s].clearNumBounces > 0 && sigVars[s].bounceDone == false)
{
sigVars[s].currentState = BOUNCING_AT_CLEAR;
Serial.print(signals[s].pwmChannel);
Serial.println(" bouncing at clear");
sigVars[s].lastMoveTime = currentTime +signals[s].clearBounceInterval; //force immediate bounce
sigVars[s].currentPWM = signals[s].clearPWM;
sigVars[s].bounceCount = 0;
sigVars[s].bounceAway = true;
sigVars[s].bounceDistance = (signals[s].clearPWM - signals[s].dangerPWM) / (100 / signals[s].clearBouncePercent); //initial bounce back distance
}
else if (currentSwitchState == HIGH) //the switch is open
{
sigVars[s].currentState = MOVING_TO_DANGER;
Serial.print(signals[s].pwmChannel);
Serial.println(" moving to danger");
sigVars[s].moveDone = false;
sigVars[s].lastMoveTime = currentTime;
}
break;
case MOVING_TO_DANGER:
moveTowardsDanger(s);
if (sigVars[s].moveDone == true)
{
sigVars[s].currentState = AT_DANGER;
Serial.print(signals[s].pwmChannel);
Serial.println(" arrived at danger");
sigVars[s].moveDone = false;
sigVars[s].bounceDone = false;
}
break;
case BOUNCING_AT_CLEAR:
if (currentTime - sigVars[s].lastMoveTime >= signals[s].clearBounceInterval) //time to do another bounce
{
if (sigVars[s].bounceAway == true) //bounce away from clear - PWM is smaller when bounced away from clear
{
// Serial.print("bounceDistance ");
// Serial.println(sigVars[s].bounceDistance);
// Serial.print("clear PWM value ");
// Serial.println(signals[s].clearPWM - sigVars[s].bounceDistance);
// Serial.print("bounce # ");
// Serial.println(sigVars[s].bounceCount);
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].clearPWM - sigVars[s].bounceDistance);
sigVars[s].bounceAway = false; //next movement is back to clear
sigVars[s].lastMoveTime = currentTime;
sigVars[s].bounceCount++;
//sigVars[s].bounceDistance -= sigVars[s].bounceDistance / signals[s].clearNumBounces; //adjust bounce distance
sigVars[s].bounceDistance -= adjustBounceDistance(sigVars[s].bounceDistance, signals[s].clearNumBounces);
if (sigVars[s].bounceCount >= signals[s].clearNumBounces) //done required bounces ?
{
sigVars[s].currentState = AT_CLEAR;
sigVars[s].bounceDone = true;
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].clearPWM); //bounce back to clearPWM
Serial.print(signals[s].pwmChannel);
Serial.println(" stoppped bouncing at clear");
}
}
else //back to danger
{
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].clearPWM); //bounce back to clear
sigVars[s].lastMoveTime = currentTime;
sigVars[s].bounceAway = true;
}
} //end time to bounce
break;
case BOUNCING_AT_DANGER:
if (currentTime - sigVars[s].lastMoveTime >= signals[s].dangerBounceInterval) //time to do another bounce
{
if (sigVars[s].bounceAway == true) //bounce away from danger - PWM is smaller when bounced away from danger
{
// Serial.print("bounceDistance ");
// Serial.println(sigVars[s].bounceDistance);
// Serial.print("danger PWM value ");
// Serial.println(signals[s].dangerPWM + sigVars[s].bounceDistance);
// Serial.print("bounce # ");
// Serial.println(sigVars[s].bounceCount);
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].dangerPWM + sigVars[s].bounceDistance);
sigVars[s].bounceAway = false; //next movement is back to danger
sigVars[s].lastMoveTime = currentTime;
sigVars[s].bounceCount++;
//sigVars[s].bounceDistance -= sigVars[s].bounceDistance / signals[s].dangerNumBounces; //adjust bounce distance
sigVars[s].bounceDistance -= adjustBounceDistance(sigVars[s].bounceDistance, signals[s].dangerNumBounces);
if (sigVars[s].bounceCount >= signals[s].dangerNumBounces) //done required bounces ?
{
sigVars[s].currentState = AT_DANGER;
sigVars[s].bounceDone = true;
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].dangerPWM); //bounce back to dangerPWM
Serial.print(signals[s].pwmChannel);
Serial.println(" stoppped bouncing at danger");
}
}
else //back to danger
{
signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].dangerPWM); //bounce back to danger
sigVars[s].lastMoveTime = currentTime;
sigVars[s].bounceAway = true;
}
} //end time to bounce
break;
} //end switch case
} //end for loop
}
byte adjustBounceDistance(byte distance, byte numBounces)
{
return distance / numBounces;
}
void moveTowardsClear(byte target) //consider adding code to move in the reverse direction based on an entry in the struct
{
if (currentTime - sigVars[target].lastMoveTime > signals[target].clearInterval) //time to move ?
{
signalBoard01.setPWM(signals[target].pwmChannel, 0, sigVars[target].currentPWM);
sigVars[target].lastMoveTime = currentTime; //save time move was made
sigVars[target].currentPWM++;
if (sigVars[target].currentPWM >= signals[target].clearPWM)
{
sigVars[target].moveDone = true;
}
}
}
void moveTowardsDanger(byte target) //consider adding code to move in the reverse direction based on an entry in the struct
{
if (currentTime - sigVars[target].lastMoveTime > signals[target].dangerInterval) //time to move ?
{
signalBoard01.setPWM(signals[target].pwmChannel, 0, sigVars[target].currentPWM);
sigVars[target].lastMoveTime = currentTime; //save time move was made
sigVars[target].currentPWM--;
if (sigVars[target].currentPWM <= signals[target].dangerPWM)
{
sigVars[target].moveDone = true;
}
}
}
void initialse()
{
boolean error = false;
for (int s = 0; s < signalCount; s++)
{
if (signals[s].dangerPWM > signals[s].clearPWM)
{
Serial.print("check clearPWM and dangerPWM values for signal ");
Serial.println(signals[s].pwmChannel);
error = true;
}
if (!error)
{
pinMode(signals[s].swPinNum, INPUT_PULLUP);
sigVars[s].currentState = AT_DANGER; //set all signals to danger
sigVars[s].currentPWM = signals[s].dangerPWM;
signalBoard01.setPWM(signals[s].pwmChannel, 0, sigVars[s].currentPWM);
sigVars[s].moveDone = true;
sigVars[s].bounceDone = true;
}
}
while (error)
{
}
}