Arduinos & servos & batteries: oh my!

So you want to control more than 2 servos with your arduino... you're in luck! I'm about to tell you how to do it!

A little bit about servos:

  1. Whether you're using a separate power supply for the servo or not, all grounds (black servo wire) must be connected together. That includes the ground of the arduino, the ground of the servo, and the ground (negative side) of the battery or power supply.

  2. Using a separate battery to power the servos is usually a good idea if you're using more than 2 servos. Otherwise you risk damaging your arduino.

  3. Most servos expect between 4.5V and 6V on the red lead (center pin), and a signal on the yellow or white lead to indicate position. This signal is called Pulse width modulation (PWM)
Pulse width modulation seems more complicated than it is. Here's how it works.
OK, let's say you have:
  • 6 servos
  • Arduino with proto-shield
  • A battery of ample size to power the servos
The PWM signal I mentioned earlier works like so... Every 20 milliseconds (20ms) the signal goes from 0 Volts (Ground) to 5 Volts for a certain length of time, usually 900 - 2400 microseconds. For most servos 1500 us (microseconds) is the middle of the servo's operational range



so here's how you'd hook up the first servo:


Now the servo has power, everything is grounded, and we're all set to start telling the servo what to do... Looks like we need to write some code! If you're not familiar with programming there is a great tutorial from ladyada. Otherwise... just use the Reference Page when you're unclear on something.

First we need to define some constants. This makes it easy to read the code, and also lets you change the value without going through all your code:
#define servoPin 1
Now whenever a function requires the pin number of the servo, we'll put servoPin instead.

The next thing we need to do is create two functions. They're required and without them nothing will happen. They functions are called setup and loop:
void setup() {

}

void loop() {

}
First the arduino runs the function called setup one time then proceeds to run the funtion loop over and over until the arduino is turned off. We're going to use the setup function to set Digital pin 1 as an output since that only needs to be done once.
void setup() {
pinMode(servoPin, OUTPUT);
}
Now we need to send the servo a pulse every 20ms so here's how to do it: We need a variable to store the time of the last pulse. We'll call it lastPulse. We need to declare it outside the functions because if you declare it inside the setup function the loop function won't be able to see it; this is called variable scope. I'm going to put the variable declaration just above the setup function:
long lastPulse = 0;

void setup() {
...
Now we just check if 20ms have passed, and if they have, send a pulse to the servo:
void loop() {
if (millis() - lastPulse > 20) {
...
}
}
The millis() function is essentially a timer. It tells you how much time has passed since the arduino was turned on. if the last pulse happened at 20 ms, and it's currently 35 ms... the arduino will skip the loop and try again, whereas if the last pulse was as 20 sec and it's currently 41ms the arduino will run the code inside the brackets.

Now it's time to send the pulse!
digitalWrite(servoPin, HIGH);
delayMicroseconds(1500);
digitalWrite(servoPin, LOW);
The first digitalWrite() sets pin 1 to high (5V), which begins the pulse. It then waits the duration of the pulse width, 1500us in this case, and then sets pin 1 back to low (0v/Ground). There's your pulse!

One more thing: you need to save the time at the time you sent the pulse so we know how long to wait before we send another:
lastPulse=millis();
Here's the program so far:
#define servoPin 1

long lastPulse = 0;

void setup() {
pinMode(servoPin, OUTPUT);
}

void loop() {
if(millis() - lastPulse > 20) {
lastPulse=millis();

digitalWrite(servoPin, HIGH);
delayMicroseconds(1500);
digitalWrite(servoPin, LOW);
}
}
Now we have some solid code to make one servo move to the middle of it's range and stay there.

To add the other 5 servos you just hook them up to the 6V Battery in parallel, while making sure to keep everything grounded. Then you hook up each servo's PWM lead to it's own digital i/o pin.



Lets say we want to set each servo to different set values:
Servo 1: 1000us
Servo 2: 1200us
Servo 3: 1400us
Servo 4: 1600us
Servo 5: 1800us
Servo 6: 2000us

Now the code is:
#define servo1Pin 1
#define servo2Pin 2
#define servo3Pin 3
#define servo4Pin 4
#define servo5Pin 5
#define servo6Pin 6

long lastPulse = 0;

void setup() {
pinMode(servo1Pin, OUTPUT);
pinMode(servo2Pin, OUTPUT);
pinMode(servo3Pin, OUTPUT);
pinMode(servo4Pin, OUTPUT);
pinMode(servo5Pin, OUTPUT);
pinMode(servo6Pin, OUTPUT);
}

void loop() {
if(millis() - lastPulse > 20) {
lastPulse=millis();

digitalWrite(servo1Pin, HIGH);
delayMicroseconds(1000);
digitalWrite(servo1Pin, LOW);

digitalWrite(servo2Pin, HIGH);
delayMicroseconds(1200);
digitalWrite(servo2Pin, LOW);

digitalWrite(servo3Pin, HIGH);
delayMicroseconds(1400);
digitalWrite(servo3Pin, LOW);

digitalWrite(servo4Pin, HIGH);
delayMicroseconds(1600);
digitalWrite(servo4Pin, LOW);

digitalWrite(servo5Pin, HIGH);
delayMicroseconds(1800);
digitalWrite(servo5Pin, LOW);

digitalWrite(servo6Pin, HIGH);
delayMicroseconds(2000);
digitalWrite(servo6Pin, LOW);
}
}
Not very elegant... but it works.

What we could do is write a function to send the pulse:
void sendPulse(int pinNumber, int pulseWidth) {
digitalWrite(pinNumber, HIGH);
delayMicroseconds(pulseWidth);
digitalWrite(pinNumber, LOW);
}
Now the loop function looks like this:
void loop() {
if(millis() - lastPulse > 20) {
lastPulse=millis();

sendPulse(servo1Pin, 1000);
sendPulse(servo2Pin, 1200);
sendPulse(servo3Pin, 1400);
sendPulse(servo4Pin, 1600);
sendPulse(servo5Pin, 1800);
sendPulse(servo6Pin, 2000);
}
}
That's much better!

Here's the finished program... happy coding!
#define servo1Pin 1
#define servo2Pin 2
#define servo3Pin 3
#define servo4Pin 4
#define servo5Pin 5
#define servo6Pin 6

long lastPulse = 0;

void setup() {
pinMode(servo1Pin, OUTPUT);
pinMode(servo2Pin, OUTPUT);
pinMode(servo3Pin, OUTPUT);
pinMode(servo4Pin, OUTPUT);
pinMode(servo5Pin, OUTPUT);
pinMode(servo6Pin, OUTPUT);
}

void loop() {
if(millis() - lastPulse > 20) {
lastPulse=millis();

sendPulse(servo1Pin, 1000);
sendPulse(servo2Pin, 1200);
sendPulse(servo3Pin, 1400);
sendPulse(servo4Pin, 1600);
sendPulse(servo5Pin, 1800);
sendPulse(servo6Pin, 2000);
}
}

void sendPulse(int pinNumber, int pulseWidth) {
digitalWrite(pinNumber, HIGH);
delayMicroseconds(pulseWidth);
digitalWrite(pinNumber, LOW);
}


Next time I'll be posting an example of how to use external input to control the servos!

 
Please Upgrade to Firefox

Um... it looks like you're using Internet Explorer. No, no... there's nothing wrong with that, it's just that... well... it kind of sucks.

You don't have to upgrade for this site, but IE has a lot of problems. Please Upgrade to Firefox (don't worry it's free).

Subscribe