Controlling RC servos with Arduino is relatively simple, at least when you use Arduino’s servo library. But the default timing may be a bit off for your application and the library seems a bit useless, or is there a simple way to fix this?
How is a RC servo controlled

For the electronics part, RC servos are controlled with a PWM (Pulse Width Modulation) signal. That means the servo will receive a pulse every x milliseconds, width a variable pulse width that corresponds with the servos position (or angle). Small pulse width for small angle, large pulse width for large angle.
There are two main categories in the RC servos
- Normal servos
- High Resolution Servos (HRS)
Normal servo
The normal, or standard servos, use a PWM of 50Hz. That means the servo will receive 50 pulses per second, or a pulse every 20 milliseconds, to command it to travel to a certain position or angle.
HRS servos
The other type is called the HRS or “High Resolution Servos” that use a PWM of 250Hz. That is a pulse signal every 4 milliseconds.

HRS servos can be used with 50Hz PWM signals, they will just work like a normal servo. However, normal servos cannot be controlled with a 250Hz PWM signal.
Centre position
The centre position of a servo is normally between a pulse width of 1500µs to 1520µs, depending on the servo’s brand and model. However, there are some servos that use 560µs, 760µs, 960µs as their centre position. These are “Narrow Band Servos”, and are most commonly used with tail gyros and FBL systems (FlyBarLess systems in RC helicopters). They may be over-steered and even damaged when controlled with the 1500µs signal. So be careful if you happen to get your hands on one of these servos.
The Arduino servo library
The servo library from Arduino only outputs a 50Hz PWM, so basically using anything more performant than a standard servo with this library, is pretty pointless. The pulse width however can be easily adjusted.
Using the library with default settings

To use the Arduino servo library with default settings, use the below sample code.
In Set the pin number to which the servo control wire is connected.
By default this is set to pin 2.
// Set servo pin #define pinServo 2
Sample code for default library
// Include servo library #include <Servo.h>; // Set servo pin #define pinServo 2 // Create servo object Servo myServo; /**************************************************************** SETUP ****************************************************************/ void setup() { Serial.begin(115200); while (!Serial) { ; // Wait for Serial } Serial.println("--- Serial monitor started ---"); Serial.println("Connecting servo"); myServo.attach(pinServo); // Connect servo } /**************************************************************** LOOP ****************************************************************/ void loop() { Serial.println("Travel to 0°"); myServo.write(0); // Travel to 0° angle delay(1000); // wait 1s (1000ms) Serial.println("Travel to 90°"); myServo.write(90); // Travel to 90° angle (centre point) delay(1000); Serial.println("Travel to 180°"); myServo.write(180); // Travel to 180° angle delay(1000); } // END
With the command servo.attch(<pin>) the servo will be controlled from the pin specified, and the angles will correspond to the pulse width specified as
- 544µs for 0° angle
- 2400µs for 180° angle
That will leave the centre position (90°) at a pulse width of 1472µs.
For most standard servos, this will not work very well and may result in several problems:
- If the servo was already pre-assembled with the levers, the centre position will not be 90°
- The far edges (0° and 180°) will overshoot the servo and may even damage it
- Accuracy may be insufficient
Default values for controlling a standard servo are usually in these ranges
Minimum | Centre | Maximum |
1100µs | 1500µs | 1900µs |
900µs | 1500µs | 2100µs |
920µs | 1520µs | 2120µs |
Custom settings
Luckily, the servo library has a solution for this: servo.attach(<pin>, <min µs>, <max µs>)

Set the pin numbers to which the servo control wires are attached.
By default these are pins 2, 3 and 4.
// Define servo connections #define pinServo1 2 #define pinServo2 3 #define pinServo3 4
Sample code for custom settings
// Include servo library #include <Servo.h>; // Define servo connections #define pinServo1 2 #define pinServo2 3 #define pinServo3 4 // Create servo object Servo myServo1; Servo myServo2; Servo myServo3; /**************************************************************** SETUP ****************************************************************/ void setup() { // Connect servo and set min and max to 1000µs and 1900µs (1500µs = centre) myServo1.attach(pinServo1, 1100, 1900); // Connect servo and set min and max to 900µs and 2100µs (1500µs = centre) myServo2.attach(pinServo2, 900, 2100); // Connect servo and set min and max to 920µs and 2120µs (1520µs = centre !) myServo3.attach(pinServo3, 920, 2120); // Move all servos to centre position (90°) myServo1.write(90); myServo2.write(90); myServo3.write(90); } /**************************************************************** LOOP ****************************************************************/ void loop() { ; } //END
As myServo1 and myServo2 have their centre position at 1500µs and myServo3 at 1520µs, when traveling to their centre position (90° angle) the pulse width for myServo3 will be 1520µs, rather than 1500µs as with myServo1 and myServo2.

Note: Looking at the diagram, you’ll also notice that the servos are controlled one by one, rather than all at the same time.
Write microseconds
There is another way of controlling the servo. You can directly specify the pulse width (in µs) using the function servo.writeMicroseconds(<µs>) instead of servo.write(<angle>)
Sample code with writeMicroseconds
// Include servo library #include <Servo.h>; // Define servo connections #define pinServo1 2 #define pinServo2 3 #define pinServo3 4 // Create servo object Servo myServo1; Servo myServo2; Servo myServo3; /**************************************************************** SETUP ****************************************************************/ void setup() { // Connect servo and set min and max to 1000µs and 1900µs (1500µs = centre) myServo1.attach(pinServo1, 1100, 1900); // Connect servo and set min and max to 900µs and 2100µs (1500µs = centre) myServo2.attach(pinServo2, 900, 2100); // Connect servo and set min and max to 920µs and 2120µs (1520µs = centre !) myServo3.attach(pinServo3, 920, 2120); myServo1.writeMicroseconds(1500); // Centre position myServo2.writeMicroseconds(1500); // Centre position myServo3.writeMicroseconds(1500); // This won't be the centre position } /**************************************************************** LOOP ****************************************************************/ void loop() { ; } //END
Because the position was directly set specifying the pulse width rather than the angle, all three servos now have a pulse width of 1500µs, even myServo3, which will now be slightly off-centre.

Final note
The servo library is a very easy to use library, without limiting the possibility of fine-tuning the servo positions. In the RC world, every transmitter has a function to “trim” the servo, so the centre can be perfectly set to a 90° angle. With the servo library now understood properly, you can make the same kind of mechanism so all servo centres are perfectly 90°.
References
Arduino Boards: Arduino Uno R3
Arduino Software: Arduino IDE
Arduino Reference: Servo library