Problem with controlling a servo

I am still new to this, so sorry if I have done things incorrectly.

I found this sketch somewhere, for just controlling some servos. I reduced the number of servos to four, and added the four relays.

It is used for operating points on an oo gauge layout, The relays are for switching the electrofrog sections on each point.

The problem is that when you apply power the servos seem to go to a random position until you cycle each switch, and that is a pain, as we have 12 points.

What I am looking for is a modification to make the servos go straight to the position as selected by each switch. I hope that is clear.

Thanks for your help.

// A not so simple Arduino Sketch to control 4 servos for point or signal control
// using 4 toggle switches.
// Each servo moves between one of two position depending on the switch setting
// each servo can have different limits to it's movement.
// 4 relays can be added for changing the power polarity on Electro-Frog Points
// Unfortunately these relays will not work with Turnouts or switches, only points.

// The servos must not be powered from the Arduino, it can't supply enough current
// typical wiring for the servos is like this
//
// Arduino servo pin -------------------Servo Signal wire (Orange or white perhaps)
// Power supply Positive -------------- Servo Positive (Centre wire - red)
// Power supply Ground -------------- Servo Ground (Black or Brown wire)
// |
// Arduino Ground ----------- (NB Arduino Ground must be connected to power supply ground)

// The toggle switches should be connected so that when switched they connect the Arduino switch pin
// to +5VDC, and have a pull down resistor connected to Arduino Ground
//
// If the switch moves the servo in the wrong direction reverse the limits 50 to 150 and 150 to 50

// The high and low positions can be set separately for each servo by editing the data in the
// arrays servoLowPos and servoHighPos. In the program as written they are all set to 50 and 150 degrees.

#include <Servo.h>

Servo pointServo[4];

byte servoPin[] = { 2, 3, 4, 5}; // pin numbers for servo signals
byte switchPin[] = { 19, 18, 17, 16}; // pin numbers for switch connections
// Uno analog pins A5 A4 A3 A2
byte servoLowPos[] = { 55, 55, 55, 55}; // degrees for low servo position S-4, S-3, S-2, S-1
byte servoHighPos[] = {145, 145, 145, 145}; // degrees for high servo position S-4, S-3, S-2, S-1

byte servoPos[4];
const int rly1Pin = 8;
const int rly2Pin = 9;
const int rly3Pin = 10;
const int rly4Pin = 11;

const int button1Pin = A2;
const int button2Pin = A3;
const int button3Pin = A4;
const int button4Pin = A5;

int button1State = 0; //variables for reading the pushbutton status
int button2State = 0; //variables for reading the pushbutton status
int button3State = 0; //variables for reading the pushbutton status
int button4State = 0; //variables for reading the pushbutton status

void setup() {
Serial.begin(9600);
setupServos();
setupSwitches();
pinMode(rly1Pin, OUTPUT); //initialize the relay pin as an output
pinMode(rly2Pin, OUTPUT); //initialize the relay pin as an output
pinMode(rly3Pin, OUTPUT); //initialize the relay pin as an output
pinMode(rly4Pin, OUTPUT); //initialize the relay pin as an output

pinMode(button1Pin, INPUT); //initialize the pushbutton pin as an input
pinMode(button2Pin, INPUT); //initialize the pushbutton pin as an input
pinMode(button3Pin, INPUT); //initialize the pushbutton pin as an input
pinMode(button4Pin, INPUT); //initialize the pushbutton pin as an input

}

void loop() {
button1State = digitalRead(button1Pin); //read the state of the pushbutton value
button2State = digitalRead(button2Pin); //read the state of the pushbutton value
button3State = digitalRead(button3Pin); //read the state of the pushbutton value
button4State = digitalRead(button4Pin); //read the state of the pushbutton value

if (button1State == HIGH) { //check if the switc is ON
//if it is, then turn the relay on
digitalWrite(rly1Pin, HIGH); }

else { digitalWrite(rly1Pin, LOW); } // turn relay off

if (button2State == HIGH) { //check if the switc is ON
//if it is, then turn the relay on
digitalWrite(rly2Pin, HIGH); }

else { digitalWrite(rly2Pin, LOW); } // turn relay off

if (button3State == HIGH) { //check if the switc is ON
//if it is, then turn the relay on
digitalWrite(rly3Pin, HIGH); }

else { digitalWrite(rly3Pin, LOW); } // turn relay off

if (button4State == HIGH) { //check if the switc is ON
//if it is, then turn the relay on
digitalWrite(rly4Pin, HIGH); }

else { digitalWrite(rly4Pin, LOW); } // turn relay off

for (byte n = 0; n < 4; n++) {
boolean servoMove = false;
byte sw = digitalRead(switchPin[n]);
if (sw == HIGH) {
if (servoPos[n] != servoHighPos[n]) { // check if the position has changed
servoMove = true;
servoPos[n] = servoHighPos[n];
}
}
else { // if sw == LOW
if (servoPos[n] != servoLowPos[n]) { // check if the position has changed
servoMove = true;
servoPos[n] = servoLowPos[n];
}
}
if (servoMove) { // only move the servo if the switch has changed
pointServo[n].write(servoPos[n]);
}
}
}

void setupServos() {
for (byte n = 0; n < 4; n++) {
pointServo[n].attach(servoPin[n]);
servoPos[n] = servoLowPos[n]; // this is just a starting value and may be over-ridden immediately by a switch
}
}

void setupSwitches() {
for (byte n = 0; n < 4; n++) {
pinMode(switchPin[n], INPUT);
}
}

The problem is that when you apply power the servos seem to go to a random position until you cycle each switch, and that is a pain, as we have 12 points.

Use the wtite() function to set an initial position for the servos before attaching them in setup()

Bob,

I am very new to this, so a little more explanation, or could you just modify the sketch, that would help me a lot.

Would your modification make the servos go "where they should be", based on the switch inputs, as that is the problem at present.

Thanks again for your help.

BC

I am very new to this, so a little more explanation, or could you just modify the sketch, that would help me a lot.

Let's start with a specification of what you want to happen at startup.
Where should the servos move to ?
Each to the same standard position, if so, what position ?
Each to a standard, but possibly different position, if so, which positions ?
Each to their last commanded position ?
Something else ?

if (button1State == HIGH)  { //check if the switc is ON
    //if it is, then turn the relay on
    digitalWrite(rly1Pin, HIGH); }
 
else { digitalWrite(rly1Pin, LOW); }

Aka

 digitalWrite(rly1Pin, button1State);

I think what you're asking for is that, on power up, the servos start up respecting the current switch positions.

If so you will probably want to make all the switch reading/servo writing code currently in loop() into a separate function. Then you can call that new function in setup() before you call setupServos() to do the attach() for all the servos and call it again in loop().

It's not very difficult but it's not exactly a trivial change.

Steve

Switching everything over to arrays will greatly simplify the code:

#include <Servo.h>


const byte ServoCount = 4;


Servo PointServos[ServoCount];


const int RelayPins[ServoCount] = {8, 9, 10, 11};


const byte ServoPins[ServoCount] =     {  2,   3,   4,   5}; // pin numbers for servo signals
const byte SwitchPins[ServoCount] =    { A5,  A4,  A3,  A2}; // pin numbers for switch connections


const byte ServosLowPos[ServoCount] =  { 55,  55,  55,  55}; // degrees for low servo position  S-4,  S-3,  S-2,  S-1
const byte ServosHighPos[ServoCount] = {145, 145, 145, 145}; // degrees for high servo position  S-4,  S-3,  S-2,  S-1


void setup()
{
  Serial.begin(9600);


  for (byte n = 0; n < ServoCount; n++)
  {
    pinMode(SwitchPins[n], INPUT_PULLUP);  // Open=HIGH, Closed=LOW
    
    PointServos[n].attach(ServoPins[n]);
    PointServos[n].write(digitalRead(SwitchPins[n]) ? ServosLowPos[n] : ServosHighPos[n]);


    pinMode(RelayPins[n], OUTPUT);
  }
}


void loop()
{
  for (byte n = 0; n < ServoCount; n++)
  {
    boolean pinState = digitalRead(SwitchPins[n]);
    PointServos[n].write(pinState ? ServosLowPos[n] : ServosHighPos[n]);
    digitalWrite(RelayPins[n], pinState);
  }
}

Except that the write needs to be before the attach if you don't want the servo intialising to 90 and THEN moving to where you actually wanted it.

And as an aside, I avoid those ternary operators like the plague. They may make the code shorter but I find they also make it almost impossible to understand. Probably just me.

Steve

"What I am looking for is a modification to make the servos go straight to the position as selected by each switch. I hope that is clear."

Simple button code that might be adapted to your switch setup. You can quickly test by touching a wire between pin 4 and ground.

//zoomkat servo button test 7-30-2011
//Powering a servo from the arduino usually *DOES NOT WORK*.

#include <Servo.h>
int button1 = 4; //button pin, connect to ground to move servo
int press1 = 0;
Servo servo1;

void setup()
{
  pinMode(button1, INPUT);
  servo1.attach(7);
  digitalWrite(4, HIGH); //enable pullups to make pin high
}

void loop()
{
  press1 = digitalRead(button1);
  if (press1 == LOW)
  {
    servo1.write(160);
  }
  else {
    servo1.write(20);
  }
}

TheMemberFormerlyKnownAsAWOL:

if (button1State == HIGH)  { //check if the switc is ON

//if it is, then turn the relay on
    digitalWrite(rly1Pin, HIGH); }

else { digitalWrite(rly1Pin, LOW); }




Aka



digitalWrite(rly1Pin, button1State);

The relay is not the issue, it is the servo that is the problem.

BC

Barry_Cole:
The relay is not the issue, it is the servo that is the problem.

BC

Maybe not, but if you get rid of some of the visual junk, it is sometimes easier to the problem ("can't see the wood for the trees" and all that)

John W,
Thanks very much for some real help.

This has cured the servo problem, but the relays are not working now, and I cannot see why...

Any thoughts??

BC

Post you code as it is now

As per John's post above.??? ;D ;D

UPDATE..

Or so I thought. I must have made an error with the copy and paste.

The only problem know is that the relays work in the wrong order. Input 1 turns on relay 4.

If it is an easy mod, that would be great, as they are all wired into the layout

BC

Post your code as it is now.

Like this...

TrainServos4-Test2.ino (1.15 KB)

What order are the relay pins and the input pins in the arrays ?
Do they have to be in that order ?

Barry_Cole:
Like this...

Like what?
I can't see anything.

Bob,
This is how they come in my original:-

byte servoPin[] = { 2, 3, 4, 5}; // pin numbers for servo signals
byte switchPin[] = { 19, 18, 17, 16}; // pin numbers for switch connections
// Uno analog pins A5 A4 A3 A2
byte servoLowPos[] = { 145, 145, 55, 55}; // degrees for low servo position S-4, S-3, S-2, S-1
byte servoHighPos[] = {55, 55, 145, 145}; // degrees for high servo position S-4, S-3, S-2, S-1

byte servoPos[4];
const int rly1Pin = 8;
const int rly2Pin = 9;
const int rly3Pin = 10;
const int rly4Pin = 11;

const int button1Pin = A2;
const int button2Pin = A3;
const int button3Pin = A4;
const int button4Pin = A5;

TheMemberFormerlyKnownAsAWOL,

1/ There is a file attached.
2/ How do I post a sketch, the way you did earlier??

Again, thanks for your help.

BC

You use these [code][/code]

1/ There is a file attached

I can see that.
So?