Arduino servo library: Why is the output not between 1000us and 2000us? - and how to fix it. Find out what to download to make the library work and how to get super accurate Servo positioning. Find out what to do if you're already using Timer 1 for something else.

The Arduino servo library can generate up to twelve servo signals on most Arduino boards, that you can output from any pin (including analogue pins e.g. A0). They are generated using a single 16 bit timer - Timer 1.

If you need more servo outputs use an Arduino Mega - 48 Servos, or Arduino Due - 60 Servos.

You can see that a servo only has three wires and two of them provide power and ground. The third is a control signal that is a PWM modulated waveform.

Note: The Arduino Servo library does not use the PWM timer capabilities.

This control signal, needs to be a 50 Hz PWM voltage waveform varying in mark to space pulse width from 1~2 ms out of a 20 ms total period, with 5V high and 0V low levels. This conveys sub-millisecond positional commands to the servo motor.

The length of the "on-time" part of the signal conveys the positional information, and 1ms mark time sets the servo to 0 Degrees, while a 2ms mark time sets the servo to 180 Degrees. You can set the position of the servo between these limits by changing the servo on-time.

The main requirement is that the signal must continuously generated at the control signal pin. You cannot set the position of the servo and then turn off the control signal because it is actually an analogue system that requires constant refresh to maintain the position of the output shaft.

Installing the Arduino Servo library

The code for the Arduino servo library is already integrated into the Arduino IDE environment so there is no "Arduino servo library download" needed. So you don't need to install servo library Arduino code.

All you do is include the library using the include operation at the top of your program and then use the Servo functions (as below).

How to use the Arduino Servo library

Here's a very simple program that shows how to use the Servo library:

#include <Servo.h>

Servo myServo;

void setup() {
  myServo.attach(9); // See WARNING below
}

void loop() {

// Control servo using write() for(int pos = 0; pos <= 180; pos += 4) { myServo.write(pos); delay(15); } for(int pos = 180; pos>=0; pos-= 4) { myServo.write(pos); delay(15); } // Control servo using writeMicroseconds() for(int pulse = 500; pulse <= 2500; pulse += 20) { myServo.writeMicroseconds(pulse); delay(15); } for(int pulse = 2500; pulse >= 500; pulse -= 20) { myServo.writeMicroseconds(pulse); delay(15); } }

Just for demonstration purposes, the code above uses both functions 'write()' and 'writeMicroseconds()'. Both these function allow controlling the servo position by specifying the angle (for the former function) and pulse width in microseconds for the latter function. The typical servo pulse widths are:

500 μs = 0 degrees
1500 μs = 90 degrees
2500 μs = 180 degrees

So this added code sweeps the pulse from 500 to 2500 μs and back, which moves the servo from one extreme position to the other. It does this alternating between functions 'write' and 'writeMicroseconds'

You would expect exactly the same output from both but the pulse lengths will be different: Find out why below:

Warning on myServo.attach(pin)

Warning: If you use the above code output pulses you observe will be wrong, specifically when you use myServo.write(angle).

The default output pulses, when you only specify an attach pin, here pin '9', (with no other parameters) are 544us (angle of 0°) 2400us (for an angle of 180°). See below for more details

Arduino Servo library: Initialisation and functions

There are two ways to initialise an Arduino Servo library object:

servo.attach(pin)
servo.attach(pin, min, max)

There are two ways to control a servo signal (two member functions in the Servo class):

    angle                       function:     write(int angle);
    microsecond pulse    function:     writeMicroseconds(int newPulse);

How to get Super-accurate Servo positioning

Don't use write(), use writeMicroseconds().

TIP: Use writeMicroseconds() for very fine control over the Servo position.

Since you can specify the pulse width to within a microsecond using the function writeMicroseconds(). This is the function to use if you want fine control over the signal sent to the servo. If you use the write function you can specify integer degrees values only which result in multiple microsecond steps.

Arduino library Servo results

Measuring the pulse width for various servo outputs (on pin 9) when using the initialisation function without min and max values:


Angle requested
pulse out (us)
0
548
45
1012
90
1476
135
1940
180
2400

Well, that looks completely wrong the minimum (at 0°) should be 1000us and the maximum (at 180°) should be 2000us. Investigating this further it is a deliberate default state set by the Servo library.

If you use the first initialisation function 'write(pin)' i.e. without specifying (min and max values), then you will see different pulse width output periods than the ones you expect (they are not 1ms ~ 2ms!).

Warning: Default servo outputs are wrong with no initialisation.

You can set the minimum and maximum pulse width output by the library when you use the attach command. The default values if you don't explicitly write them in are 544us and 2400us.

Here's the relevant section of the Arduino reference:

servo.attach(pin)
servo.attach(pin, min, max)

min (optional): the pulse width, in microseconds, corresponding to the minimum (0 degree) angle on the servo (defaults to 544).

max (optional): the pulse width, in microseconds, corresponding to the maximum (180 degree) angle on the servo (defaults to 2400).

These default values have probably been set to ensure that your servo will go to its fullest limits, since servos are not the most angle-accurate devices. The other reason is that it allows you to individually tune each servo to the minimum and maximum angles (servos can be different even for the same batch).

Warning: The default min and max pulses are odd values of 544us and 2400us; these are not 1000us and 2000us that you expect! (You can changes these values in initialisation).

Sketch that outputs 1ms to 2ms pulses

To fix the odd pulse length outputs simply initialise the attach function with the minimum and maximum output pulse length that you need for 0° and 180°.

Here's an example Arduino Servo library program with correct pulse outputs:

#include <Servo.h>

#define MIN_PULSE 1000
#define MAX_PULSE 2000

Servo myServo;

void setup(){
  myServo.attach(9, MIN_PULSE, MAX_PULSE); 
}

void loop() {

  // Sweep from 0 to 180 degrees
  for(int angle = 0; angle <= 180; angle += 4) {
    myServo.write(angle);
    delay(15);
  }

  // Sweep from 180 to 0 degrees
  for(int angle = 180; angle >= 0; angle -= 4) {
    myServo.write(angle);
    delay(15);
  }

}

Code locations

Here are the arduino servo library github locations

servo.h - the class include file (that you include in your file):

    https://github.com/arduino-libraries/Servo/blob/master/src/Servo.h

This defines the class Servo and the maximum number of servos :  MAX_SERVOS.
Source code for servo class is here:

    servo.cpp and ServoTimers.h

    https://github.com/arduino-libraries/Servo/blob/master/src/avr/Servo.cpp
    https://github.com/arduino-libraries/Servo/blob/master/src/avr/ServoTimers.h

Alternative Servo Library (uses T2)

If you are already using Timer 1 for something else, for example another library is using Timer1, and you still want to control servos, then the built-in Arduino Servo library is not going to be of any use.

Fortunately there is another library that you can use that only uses Timer 2.

You can find this library on github here:

    https://github.com/nabontra/ServoTimer2/tree/master

Download the zip and install to IDE - Menu>Sketch>Include library >Add .ZIP library

Note: The library notes for Servotimer2 say you can use up to 8 servos on an Arduino.

What to do if you don't want T1 or T2?

If you have other code that uses Timer1 and Timer2 there is one other possibilty and that is to directly control PWM output using the millisecond timer - millis(). Note that there is an extra  twist - you can't just use the millis() timer. Find out how to do it in this link : Arduino control servo without library.


Written by John Main who has a degree in Electronic Engineering.

Note: Parts of this page were written using claude instant a research assistant.


Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.



Privacy Policy | Contact | About Me

Site Map | Terms of Use