Driving Two Servos on One Board

Hey everyone, I was trying to create an animatronic project using two servo motors, but they refuse to work at the same time. One is used for a wagging tail and the other for a singing jaw. Granted I assume this is something that I did wrong, but the one thing I do know is that the hardware and breadboarding is all correct since I have gotten both to work separately. I believe I have a sufficient power supply but im not entirely sure about the code once again. The code I used was the sweep sketch and one for a Halloween skull from this page: http://www.open-electronics.org/simple-halloween-skull/ . I had used both the tail and jaw separately on two separate arduinos but I cant seem to get them both on one. Here is my mixed code (where only the jaw works) and I’d appreciate any help if anyone has any ideas, thanks.

/*Animatronic Circuit*/

#include <Servo.h>
Servo tailservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position
Servo jawservo;  // create servo object to control a servo 
int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin  


 void setup() 
{ 
  tailservo.attach(11);  // attaches the tail servo on pin 11 to the servo object
  jawservo.attach(9);  // attaches the servo on pin 9 to the servo object
}  


void loop() {
  jaw();
  tail();
}

 
/* Animatronic Jaw on 9 */
void jaw() {
  val = (analogRead(potpin)*3);            // reads the value of the potentiometer
  val = map(val, 0, 1023, 50, 0);     // scale it to use it with the servo
  jawservo.write(val);                  // sets the servo position according to the scaled value
  delay(15);                           // waits 15ms for the servo to reach the position 
}
                         
 /* Animatronic Tail on 11 */
 void tail() {
  for(pos = 0; pos <= 180; pos += 1) // goes from 0 degrees to 180 degrees                                    // in steps of 1 degree 
    tailservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(3.5);                       // waits 3.5ms for the servo to reach the position 
  
  for(pos = 180; pos>=0; pos-=1)     // goes from 180 degrees to 0 degrees                       
    tailservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(3.5);                       // waits 3.5ms for the servo to reach the position 
  };

I believe I have a sufficient power supply

What makes you think that? Are you powering the servos from an external power supply?

lgn631: Hey everyone, I was trying to create an animatronic project using two servo motors, but they refuse to work at the same time.

void loop() {
  jaw();
  tail();
}

That is hardly suprising because your tail() function goes through its full movement before returning. You also want to get rid of all uses of delay()

Have a look at the demo Several Things at a Time

You need code that moves each servo a little bit for each iteration of loop().

I suggest you create another separate function to read the potentiometer to take that out of the servo code. Have a look at Planning and Implementing a Program

...R

Yes zoomkat, I have an external power supply for the servos, sufficient enough for both, and it's grounded to the arduino.

Also Robin, I tried to touch up the code a bit but im still a little lost on what you mean by the function goes through its full movement. When I try to use it (even with this new code) it rapidly twitches. I also found that if I add the delays back in the tail functions but the jaw stops.

/*
 *Two servos running, requiring an external power supply. 
 *A standard metal gear servo for the tail and plastic micro
  is used for the jaw mechanism.
*/

#include <Servo.h>
Servo tailservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position

Servo jawservo;  // create servo object to control a servo 
int potpin = A0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin  

/*
 * Jaw is connected to pin 9 for signal 
 * Tail is connected to pin 11 for signal
*/

 void setup() 
{ 
  tailservo.attach(11);  // attaches the tail servo on pin 11 to the servo object
  jawservo.attach(9);  // attaches the servo on pin 9 to the servo object
}  


void loop() 
{
  readpot();
  jaw();
  
  tail();
}

   /* Audio signal into Analog 0 for the Jaw*/
void readpot() 
{
val = (analogRead(potpin)*3);  // anylzes the sound signal and converts it for the servo
}


  /* Animatronic Jaw on 9 */
void jaw() 
{
  val = map(val, 0, 1023, 50, 0);     // scale readpot value to use it with the servo
  jawservo.write(val);               // sets the servo position according to the scaled value                          
}

                
  /* Animatronic Tail on 11 */
void tail() 
{
  for(pos = 0; pos <= 180; pos+=1) {    // goes from 0 degrees to 180 degrees in steps of 1 degree   
tailservo.write(pos); // tell servo to go to position in variable 'pos' 
   }  
                         
  for(pos = 180; pos>=0; pos-=1) {     // goes from 180 degrees to 0 degrees in steps of 1 degree                       
tailservo.write(pos);                // tell servo to go to position in variable 'pos' 
    }                      
}

lgn631:
Also Robin, I tried to touch up the code a bit

You did not study the links I gave you.

This code

  for(pos = 0; pos <= 180; pos+=1) {    // goes from 0 degrees to 180 degrees in steps of 1 degree   
tailservo.write(pos); // tell servo to go to position in variable 'pos'
   }

goes through all the steps to get from 0 to 180 before it returns to loop().

It should only do a single step for each iteration of loop().

I also found that if I add the delays back in the tail functions but the jaw stops.

The very last thing you need is a delay()

…R

I had read through the given information (Thank you by the way because it did open my eyes to some new and useful info) but I am still only starting to learn the language so I got somewhat lost during some of the reading. Sorry about not saying I was new-ish to this earlier, but I once again ran into a problem. I tried to break down the steps for the tail’s for statements and now I can’t figure out why the tail commands are “not declared”. Also when you said the very last thing I need is a delay, do you mean as a separate loop command at the very bottom or at the end of each servo movement (like I think I have in the code)? Once again I’d like to say I appreciate all of the help you’ve offered so far, it’s hard to do this stuff when you’re so inexperienced with it.

/*
 *Two servos running, requiring an external power supply. 
 *A standard metal gear servo for the tail and plastic micro
  is used for the jaw mechanism.
*/

#include <Servo.h>
Servo tailservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position

Servo jawservo;  // create servo object to control a servo 
int potpin = A0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin  


/*
 * Jaw is connected to pin 9 for signal 
 * Tail is connected to pin 11 for signal
*/

 void setup() 
{ tailservo.attach(11);  // attaches the tail servo on pin 11 to the servo object
  jawservo.attach(9);  // attaches the servo on pin 9 to the servo object
  tailservo.write(pos); // tell servo to go to position in variable
}  


void loop() 
{ readpot();
  jaw();
  
  tailRmax();
  tailRmin();
  tailRwag();
  
  tailLmax();
  tailLmin();
  tailLwag();
}


/*Jaw*/
/* Audio signal into Analog 0 for the Jaw*/
void readpot() 
  {val = (analogRead(potpin)*3);  // anylzes the sound signal and converts it for the servo
}


  /* Animatronic jaw movement */
void jaw() 
  { val = map(val, 0, 1023, 50, 0);     // scale readpot value to use it with the servo
  jawservo.write(val);               // sets the servo position according to the scaled value                          
}


/*Tail*/
/*Tail wags right*/
void tailRmax();
{for(pos <= 180) 
  }


void tailRmin();
{for(pos = 0) 
  }


void tailRwag();
{for(pos += 1) 
  {delay(3.5);      
  }


     
/*Tail wags left*/ 
void tailLmax();
{for(pos = 180)    
  }


 
void tailLmin();
{for(pos>=0)      
  }


void tailLwag(); 
{for(pos-=1;) 
  {delay(3.5);     
    }
  }

Something like this ? (not tested)

unsigned long lastTailMoveMillis;
unsigned long tailMoveInterval = 100; // millisecs between moves
byte tailPos = 0;
byte tailDirection = 1;


void tailwag() {
    if (millis() - lastTailMoveMillis >= tailMoveInterval) {
        lastTailMoveMillis += tailMoveInterval;
        
        tailPos = tailPos + tailDirection;
        if (tailPos > 180) {
            tailPos = 180;
            tailDirection = -1;
        }
        if (tailPos < 0) {
            tailPos = 0;
            tailDirection = 1;
        }
        tailServo.write(tailPos);
    }
}

Note that there are no FORs and no delay()s. It relies of loop() to provide the repetition and millis() to manage the timing.

…R

Thank you so much for all of the help, I really appreciate the patience and I'll make sure to put all of what you taught me to good use now and in the future. After a solid 16 hours (Not exaggerated) they both work at the same time. I had thought about using the IF statements but I was too stuck on the FORs to figure it out at the time. Ok so this should be my last question, if I want it to move faster, do I change the tailMoveInterval? I mean I tried it but it only rotates about half or 3/4 the max when the interval value is set around 5. Would I need to set the servo's max and min higher up in the code? Past that your code fix worked beautifully.

lgn631: if I want it to move faster, do I change the tailMoveInterval?

You need to post your complete program so I know exactly what you are talking about.

My idea was that the tailMoveInterval would control the speed.

...R

The tailMoveInterval does control the speed, but it reduces how far the servo rotates at the same time. I think it just doesn’t give the servo enough time to move.

/*
 *Two servos running, requiring an external power supply. 
 *A standard metal gear servo for the tail and plastic micro
  is used for the jaw mechanism.
*/

#include <Servo.h>
Servo tailServo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position


Servo jawservo;  // create servo object to control a servo 
int potpin = A0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin  


/*
 * Jaw is connected to pin 9 for signal 
 * Tail is connected to pin 11 for signal
*/

 void setup() 
{ tailServo.attach(11);  // attaches the tail servo on pin 11 to the servo object
  jawservo.attach(9);  // attaches the servo on pin 9 to the servo object
  tailServo.write(pos); // tell servo to go to position in variable
}  


void loop() 
{ readpot();
  jaw();
  tailwag();
}


/*Jaw*/
/* Audio signal into Analog 0 for the Jaw*/
void readpot() 
  {val = (analogRead(potpin)*3);  // anylzes the sound signal and converts it for the servo
}


  /* Animatronic jaw movement */
void jaw() 
  { val = map(val, 0, 1023, 50, 0);     // scale readpot value to use it with the servo
  jawservo.write(val);               // sets the servo position according to the scaled value                          
}


/*Tail*/
unsigned long lastTailMoveMillis;
unsigned long tailMoveInterval = 5.5; // millisecs between moves
byte tailPos = 0;
byte tailDirection = 1;

void tailwag() {
    if (millis() - lastTailMoveMillis >= tailMoveInterval) {
        lastTailMoveMillis += tailMoveInterval;
        
        tailPos = tailPos + tailDirection;
        if (tailPos > 180) {
            tailPos = 180;
            tailDirection = -1;
        }
        if (tailPos < 0) {
            tailPos = 0;
            tailDirection = 1;
        }
        tailServo.write(tailPos);
    }
}

You have a very short interval of 5.5 millisecs. I think it would be more effective to increase speed by increasing the number of degrees for each step AND increasing the interval so that it gives sufficient time for the servo to move - you will need to figure that by experiment. The servo specs usually say how fast it moves.

...R

Hey Robin, I just wanted to say thank you one last time since the code is perfect now thanks to your advice and help. I know that this is just a forum but what you're doing by educating makers, helping them improve their creations and skills, is really great of you. It may not seem like it, but you're fueling creativity and encouraging people to do better with what they love to do, or even just their hobbies. Regardless, I think a good chunk of this forum owes you a thank you because you have done a lot whether you realize it or not. So, thank you again for all the aid and I'll see you around the forums!

lgn631: Hey Robin, I just wanted to say thank you one last time

Thank you for your kind words.

...R