Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

The Software Servo Library

The Software Servo Library can drive servos on all of your pins simultaneously. The API is patterned after the wiring.org servo library but the code is different. You are not limited to 8 servos, but you must call the SoftwareServo::refresh() method at least once every 50ms or so to keep your servos updating.

Note that as of Arduino 0017, the Arduino Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega. The Arduino library does not need to have explicit calls to refresh so is easer to use than the software servo code that follows. If you have an Arduino version earlier than 0017 you can download the new hardware servo code from here.

Download

SoftwareServo.zip

Standard Methods

attach(int)
Turn a pin into a servo driver. Calls pinMode. Returns 0 on failure.
detach()
Release a pin from servo driving.
write(int)
Set the angle of the servo in degrees, 0 to 180.
read()
return that value set with the last write().
attached()
return 1 if the servo is currently attached.

Extra Methods

refresh()
You must call this at least once every 50ms to keep the servos updated. You can call it as often as you like, it won't fire more than once every 20ms. When it does fire, it will take from .5 to 2.5 milliseconds to complete, but won't disable interrupts.
setMinimumPulse(uint16_t)
set the duration of the 0 degree pulse in microseconds. (default minimum value is 544 microseconds)
setMaximumPulse(uint16_t)
set the duration of the 180 degree pulse in microseconds. (default maximum pluse value is 2400 microsconds)

Safety Quirk

Even though you attach a servo, it won't receive any control signals until you send its first position with the write() method to keep it from jumping to some odd arbitrary value.

Size

The library takes about 850 bytes of flash and 6+(8*servos) bytes of SRAM.

Limitations

This library does not stop your interrupts, so millis() will still work and you won't lose incoming serial data, but a pulse end can be extended by the maximum length of your interrupt handles which can cause a small glitch in the servo position. If you have a large number of servos there will be a slight (1-3 degrees) position distortion in the ones with the lowest angular values.

An Example

The following code lets you control Servo on pin2 by potentiometer on analog 0

#include <SoftwareServo.h> 

SoftwareServo myservo;  // 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() 
{ 
  myservo.attach(2);  // attaches the servo on pin 2 to the servo object 
} 

void loop() 
{ 
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023) 
  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180) 
  myservo.write(val);                  // sets the servo position according to the scaled value 
  delay(15);                           // waits for the servo to get there 

  SoftwareServo::refresh();
} 

An other Example

The following code is a ping/pong rotations on A0 pin with speed variable


#include <SoftwareServo.h> 

SoftwareServo myservo;  // create servo object to control a servo 

#define pinServo A0

int speed = 1;
int limits[2] = {30,150};	// set limitations (min/max: 0->180)
boolean refresh = false;	// toggle refresh on/off

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

	// attaches the servo on pin to the servo object
	myservo.attach(pinServo);  

	// init angle of servo inbetween two limitations
	myservo.write((limits[1]-limits[0])/2); 
} 

void loop() 
{ 
	// refresh angle
	int angle = myservo.read();

	// change direction when limits
	if (angle >= limits[1] || angle <= limits[0])  speed = -speed;

	myservo.write(angle + speed);	

	// set refresh one time / 2
	refresh = refresh ? false : true;
	if (refresh) SoftwareServo::refresh();

	Serial.print("Angle: ");
	Serial.println(angle);
}