Servo control

Hello, I’m brand new to the Arduino and am starting with a simple project but have run into something that I can’t figure out. The project is controlling three servos hooked to blast gates on a home shop dust collection system. The servos are switched using three interlocked switches (only one switch can be on at a time). My program was initially successful but in testing, I found that the larger of the three blast gates was struggling to open so I decided to open the two smaller blast gates first (to relieve pressure) then shortly afterward, open the larger blast gate and after a short delay, close the two small blast gates. Here’s the code I used to do that (full code is below):

 if (sw4inState == LOW)  
   {
   servoMS.write(MSOpen);
   servoBS.write(BSOpen);
   delay(200);
   servo4in.write(bigOpen);
   delay(1000);  
   servoMS.write(MSClosed);
   servoBS.write(BSClosed);

This code worked fine through the “servo4in.write(bigOpen);” command but nothing happened after that when the two smaller gates should have closed. I tried varying the second delay (up to 10 seconds) just to let things settle but the smaller gates never closed until the “sw4inState” switch was closed. Any idea of why this is not responding properly? I’d also appreciate any input as to a better way to do this or suggestions for cleaning up the code.

Thanks for your help.

Here’s the entire program.

/*
Controlling three servos using three switches
*/

#include <Servo.h>

Servo servo4in;  // create servo object to control a servo
Servo servoBS;
Servo servoMS;

//three control switches, interlocked so only one can be used at a time
int sw4in = 14;   //switch for four inch hose
int swBS = 15;    //switch for bandsaw hose
int swMS = 16;    //switch for mitersaw hose

int sw4inState = 0;
int swBSState = 0;
int swMSState = 0;

//The following sets the range of the three servos with respect to blast gate 
//opening, it is adjusted for each individual servo/blast gate.

int bigOpen = 55;   //4in hose:  0 is open, 180 is closed
int bigClosed = 170;

int BSOpen = 90;    //BandSaw  180 is open, 0 is closed
int BSClosed = 10;

int MSOpen = 75;    //MiterSaw  180 is open, 0 is closed
int MSClosed =  5;


void setup() {

 pinMode(sw4in, INPUT);
 pinMode(swBS, INPUT);
 pinMode(swMS, INPUT);
 
 servo4in.attach(5);
 servoBS.attach(6);
 servoMS.attach(9);

 servo4in.write(bigClosed);  //closes all three blast gates
 servoBS.write(BSClosed);
 servoMS.write(MSClosed);
}

void loop() {

sw4inState = digitalRead(sw4in);  //reads the status of all three switches
swBSState = digitalRead(swBS);
swMSState = digitalRead(swMS);


//the following code responds to the three switches, LOW is on, HIGH is off.

if (sw4inState == LOW)  
   {
   servoMS.write(MSOpen);
   servoBS.write(BSOpen);
   delay(200);
   servo4in.write(bigOpen);
   delay(1000);  
   servoMS.write(MSClosed);
   servoBS.write(BSClosed);
   }

 if (swBSState == LOW)
   { servoBS.write(BSOpen);}
   
 if (swMSState == LOW)
   {servoMS.write(MSOpen);}
      

if  (sw4inState == HIGH) 
   {servo4in.write(bigClosed);}  

if (swBSState == HIGH)
   {servoBS.write(BSClosed);}
   
if (swMSState == HIGH)
   {servoMS.write(MSClosed);}

   }

Do you have external pullup resistors (10k) on the switch pins? If not, replace lines 31 - 33 with:

  pinMode(sw4in, INPUT_PULLUP);
  pinMode(swBS, INPUT_PULLUP);
  pinMode(swMS, INPUT_PULLUP);

Assuming you have the switches wired between pin and GND. Do you?
If switches are wired between pin and 5V, you should have pulldown resistors from pin to GND.

Also, if you want all gates closed at startup, replace the last lines in setup() with:

    //attaches and closes all three blast gates
  servo4in.write(bigClosed);
  servo4in.attach(5);
  servoBS.write(BSClosed);
  servoBS.attach(6); 
  servoMS.write(MSClosed);
  servoMS.attach(9);
}

BTW: Here's how to post code so it appears in a scrollable box like above:
HowToPostCode

Hi outsider, Yes, I've got pullup resistors on the switches and they work fine. I'm wondering if there's a bug in the Servo Library code that won't let opposite commands happen so close together.
In this short section of code (by the way, thanks for the heads-up in how to post code), when the switch is flipped, two gates should open then 0.2 sec later another gate should open then one second later, the first two gates should close. In practice, the last function doesn't happen, the two gates don't close. Something is causing this to hang up and I'm not sure how to correct it.

 if (sw4inState == LOW) 
    {
    servoMS.write(MSOpen);
    servoBS.write(BSOpen);
    delay(200);
    servo4in.write(bigOpen);
    delay(1000); 
    servoMS.write(MSClosed);
    servoBS.write(BSClosed);
    }

In setup(), add:

Serial.begin(9600); // set Serial monitor baud rate to match

Then, change this block:

if (sw4inState == LOW)  
   {
   servoMS.write(MSOpen);
   servoBS.write(BSOpen);
   delay(200);
   servo4in.write(bigOpen);
   delay(1000);  
   servoMS.write(MSClosed);
   servoBS.write(BSClosed);
   }

To:

 if (sw4inState == LOW)
    {
    servoMS.write(MSOpen);
    servoBS.write(BSOpen);
    delay(200);
    servo4in.write(bigOpen);
    delay(1000);
    servoMS.write(MSClosed);
    servoBS.write(BSClosed);
    Serial.print(servoMS.read);
    Serial.print("\t");
    Serial.print(servoBS.read);
    Serial.print("\t");
    Serial.println(servo4in.read);
    }

And see what Serial monitor shows.

One question, have you tried the sketch without the blower running?

Hi,
Welcome to the forum.

What model Arduino are you using?
What are your servos, link to data/specs?

What is your power supply?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

I'm wondering if there's a bug in the Servo Library code that won't let opposite commands happen so close together.

I'd strongly suggest that you abandon that line of thinking. There could indeed be bugs there, but given how much use that library gets, I highly doubt you found one.

There's much more likelihood that your issue is wiring, power or your own code. Of course, if you have found a bug and can provide example code that demonstrates it, the library maintainer will probably be pleased to hear about it, but look to your own stuff first.

Thanks to everyone who has responded. Here are my answers to your questions/comments:

outsider: I just now tried the serial monitor code you suggested and get a "invalid use of non
-static member function" message from the last line of the code "Serial.println(servo4in.read);" I haven't yet tried to figure out what that means, I'll work on it, it's all part of the learning process :slight_smile:
Nearly all of my testing has been done without the blower running so that rules out interference from the motor.

TomGeorge: I'm using a SparkFun ProMicro 5v/16MHz. The servos are Hitec HS-425BB. Currently for testing, I'm using a benchtop 5volt, 5amp power supply. Here's the circuit:

wildbill: I know that was a bit brash of me, being a newbie, for speculating that it could be a bug in the library, sorry about that. It's just that everything else worked fine and I was trying to analyze what could be hanging things up with such a simple block of code.

Hi,
If you run the servos, with no mechanical load, do they function correctly?

Can you monitor the 5V supply while your program faults?

Have you tried writing code with just that block ONLY in it and the relevant input switch and servo output?
In other word just bit of code that ONLY does the "sw4inState == LOW" block.

You may have to put some initial positions for the servos in the void setup(), so you will see them move to the programmed positions.

Tom... :slight_smile:

Two random things:

  1. Why don’t you have denouncing code for the buttons/switches?

  2. Can you format your code correctly and then repost? Your tabs are off (I think) and it may be confusing yourself or us. Indentation conventions are not as trivial as most beginners think. They help code readability and make bugs easier to find.

Power_Broker:
Two random things:

  1. Why don’t you have denouncing code for the buttons/switches?

Because they haven't committed any heresy?

Because they haven't committed any heresy?

:grinning:

OOPS!, my bad, try it now:

#include <Servo.h>

Servo servo4in;  // create servo object to control a servo
Servo servoBS;
Servo servoMS;

//three control switches, interlocked so only one can be used at a time
int sw4in = 14;   //switch for four inch hose
int swBS = 15;    //switch for bandsaw hose
int swMS = 16;    //switch for mitersaw hose

int sw4inState = 0;
int swBSState = 0;
int swMSState = 0;

//The following sets the range of the three servos with respect to blast gate
//opening, it is adjusted for each individual servo/blast gate.

int bigOpen = 55;   //4in hose:  0 is open, 180 is closed
int bigClosed = 170;

int BSOpen = 90;    //BandSaw  180 is open, 0 is closed
int BSClosed = 10;

int MSOpen = 75;    //MiterSaw  180 is open, 0 is closed
int MSClosed =  5;


void setup() {

 pinMode(sw4in, INPUT);
 pinMode(swBS, INPUT);
 pinMode(swMS, INPUT);
 
    //attaches and closes all three blast gates
  servo4in.write(bigClosed);
  servo4in.attach(5);
  servoBS.write(BSClosed);
  servoBS.attach(6);
  servoMS.write(MSClosed);
  servoMS.attach(9);
}


void loop() {

sw4inState = digitalRead(sw4in);  //reads the status of all three switches
swBSState = digitalRead(swBS);
swMSState = digitalRead(swMS);


//the following code responds to the three switches, LOW is on, HIGH is off.

 if (sw4inState == LOW)
    {
    servoMS.write(MSOpen);
    servoBS.write(BSOpen);
    delay(200);
    servo4in.write(bigOpen);
    delay(1000);
    servoMS.write(MSClosed);
    servoBS.write(BSClosed);
    Serial.print(servoMS.read());
    Serial.print("\t");
    Serial.print(servoBS.read());
    Serial.print("\t");
    Serial.println(servo4in.read());
    }
    
 if (swBSState == LOW)
   { servoBS.write(BSOpen);}
   
 if (swMSState == LOW)
   {servoMS.write(MSOpen);}
     

if  (sw4inState == HIGH)
   {servo4in.write(bigClosed);}  

if (swBSState == HIGH)
   {servoBS.write(BSClosed);}
   
if (swMSState == HIGH)
   {servoMS.write(MSClosed);}

   }

This code worked fine through the "servo4in.write(bigOpen);" command but nothing happened after that when the two smaller gates should have closed.

What is the state of the swBS and swMS switches at this time? Did you try flipping them to the opposite state?

The servos are switched using three interlocked switches (only one switch can be on at a time).

I don’t see that, either on your diagram or in code, please explain.

Thanks again everyone for your help on this. I haven't completely solved the problem but I have made a little progress in that direction.

Tom George: I took your advice to isolate that one section of code and was able to get the servos to respond like I wanted them to. I haven't been able to get it to run properly in the loop but I'm sure that will come with a bit of tweaking.

Power_Broker: Thanks for the question about debouncing. If I was using push buttons I realize how important this is but since I'm using toggle switches and the timing is not critical, its probably not as necessary but I'll look into including a debouncer. With regard to tabs, I'll work on that to try and make things clearer.

outsider: Thanks for the update on the serial monitor, that works fine and I can now see the position of the servos on my monitor; the program still hangs up at the same point but it gives me another resource to see what's wrong. With regard to the interlocking switches, I don't know that there's a way to show that on the schematic but my setup is similar to the push button switches on a multi-speed appliance where button one is off, button two is low speed etc. When one button is pushed, the others pop out so only one can be selected at a time. I brought that up because I realize that in this program, if two switches could be closed at the same, it could really foul things up.

I love learning new stuff and I appreciate everyone's help in assisting me to get going with the Arduino. My head is spinning right now with all the input but I'm sure I'll be able to digest it and come up with a working program.

Well, if your switches are double throw type, you can interlock through the normally closed contacts, otherwise, you can interlock with software like this, I would recommend the former though.

sw4inState = ! digitalRead(swBS) || ! digitalRead(swMS) || digitalRead(sw4in);  
swBSState =  ! digitalRead(swMS) || ! digitalRead(sw4in) || digitalRead(swBS);
swMSState =  ! digitalRead(swBS) || ! digitalRead(sw4in) || digitalRead(swMS);

Hi,

Tom George: I took your advice to isolate that one section of code and was able to get the servos to respond like I wanted them to. I haven't been able to get it to run properly in the loop but I'm sure that will come with a bit of tweaking.

Great, now write a similar code but with the second input process and see/get it working
Do the same for the third input case.

So eventually you have 3 SEPARATE codes each dealing with a separate input state.

Then combine TWO of the processes and get them working.
Once you have it working, THEN add the third code and get it working.

Do you have a servo position for all switches off, or does that not happen with your interlocked buttons?

Tom... :slight_smile: