Servo motors are capable of very precise control over the directional movement of its motor’s shaft. It allows you to set exact rotating angles to control devices either by programming in code, a joystick, or with a simple push of a button or a potentiometer. Servo motors are available in various configurations. For this discussion and project, we will use one that rotates between 0 and 180 degrees.

One of the first uses of servo motors was to control RC planes and steering remote-controlled cars. Today, you can find them in numerous devices like robots, industrial controls, and Arduino devices.

In this tutorial, we will describe how servo motors function, its power requirements, how to set the positions, timing parameters, and how they are used to control a device along with an Arduino UNO. We will also create two sample programs for controlling a servo motor. The first example will allow you to control the direction and exact position of a servo motor using two pushbuttons. The second one will cover the use of a potentiometer to control the position of the servo motor.

Alright, let’s get started!

How Servo Motors Work

A servo motor controls the rotation of a DC motor that has been geared down to reduce the speed and increase the torque. The required circuitry is built into the servo to control the exact angle of rotation, to be capable of controlling its rotation one degree at a time. Control is achieved by the width of an electrical pulse sent to the servo from the controller. For the sample project, we will use an Arduino UNO and a specific library that creates the functions needed to control the servo motor.

Also, depending on the servo you use, you should consider using a separate DC power supply to protect the Arduino.

The servo motor expects a pulse every 20 ms. The servo determines the amount of rotation depending on the width of the pulses delivered by the Arduino. For most servo motors, a 1ms pulse results in a zero degree rotation, a 1.5 ms pulse results in a 90-degree rotation, and a 2ms pulse results in a complete 180-degree rotation, as shown above.

Arduinos usually include a library to simplify the control for a servo motor. The library is included in Arduino IDE and loading the Servo.h library is the first thing entered in the program.

Setting Up the Servo Motor

Now, let’s see how to control the servo motor. But first, have your components ready and connect them according to the diagram above.

Programming the Arduino

Open Arduino IDE and connect to the UNO then use the following code:

#include <Servo.h>
Servo servo1;
int servoPin = 9;
void setup(){
servo1.attach(servoPin);
}
void loop(){
servo1.write(0);
delay(1000);
servo1.write(90);
delay(1000);
servo1.write(180);
delay(1000);
}

Save and upload the compiled program to your Arduino. The servo motor should initialize at zero degrees, pause for a second, then move to 90 degrees, pause for a second, then move to 180 degrees, pause for a second and start over.

The first line of code loads the <Servo.h> library that facilitates the control of the servo. In the next line, you are creating an object in the library to reference the specific servo motor throughout the code. Multiple servos can be controlled, so for this example, we will use servo1 to designate our servo. The pin used to connect the servo, serverPin, is used in the attach() function, servo1.attach(servoPin);.

To move the servos to any direction, use the write() function, servo1.write(angle); . Angle should be in degrees (0-180). The angle changes the pulse width sent to the servo motor which then determines the amount of rotation.

Using the servo.writeMicroseconds() Function

The command servo.write(angle) works for most servo motors, but not really for all. Some servo motors have a range of 180 degrees, some have a range of 90 degrees, and some have anywhere in between. Using the command servo.write(angle) allows for a maximum of 180 steps. However, there is a command that allows up to 1000 steps–servo.writeMicroseconds(). For most applications, the simpler servo.write(angle) will work out just fine. But if you want more precise control, you may want to use servo.writeMicroseconds().

From the previous code, change the command from servo1.write() to servo1.writeMicroseconds(). Change the angular values from (0,90,180) degrees to (1000,1500,2000) microseconds. Upload and run the program using the same hardware setup. For a servo motor capable of a range up to 180, the values will be 1000 Microseconds = 0 degrees, 1500 Microseconds = 90 degrees, and 2000 Microseconds = 180 degrees.

#include <Servo.h>
Servo servo1;
int servoPin = 9;
void setup(){
servo1.attach(servoPin);
}
void loop(){
servo1.writeMicroseconds(1000);
delay(1000);
servo1.writeMicroseconds(1500);
delay(1000);
servo1.writeMicroseconds(2000);
delay(1000);
}

Depending on the servo motor you are using, you may notice a difference. Interestingly on my setup, while monitoring the pulses on an oscilloscope, I noticed that when using servo1.write(0);, the pulse width was only about 700 microseconds, not 1000 which is the way the function should work when set at zero degrees. But when using servo1.writeMicroseconds(1000); the output was exactly 1000 microseconds.

Controlling a Servo Motor with Push-Button Switches

 How to Control Servo Motors on the Arduino - Servo Control With Push Buttons Wiring Diagram

Build your circuit as shown in the diagram above, then upload the code shown below.

#include<Servo.h>
int pos = 90;
int pin4 = 4;
int pin3 = 3;
int LedHi = 5;
int LedLow = 6;
Servo servo1;
void setup() {
  pinMode(LedHi, OUTPUT);
  pinMode(LedLow, OUTPUT);
  pinMode(pin4, INPUT);
  pinMode(pin3, INPUT);
  Serial.begin(9600);
  servo1.attach(9);
}
void loop() {
  while (digitalRead(pin3) == HIGH && pos < 180) {
    digitalWrite(LedLow, LOW);
    pos++;
    servo1.write(pos);
    Serial.print("Degrees rotation= ");
    Serial.println(pos);
    if (pos == 180) {
      Serial.print("Reached top end ");
      digitalWrite(LedHi, HIGH);
    }
    delay(10);
  }

  while (digitalRead(pin4) == HIGH && pos > 0) {
    digitalWrite(LedHi, LOW);
    pos--;
    servo1.write(pos);
    Serial.print("Degrees rotation= ");
    Serial.println(pos);
    if (pos == 0) {
      Serial.print("Reached low end ");
      digitalWrite(LedLow, HIGH);
    }
    delay(10);
  }
}

After uploading the compiled code, open the Serial Monitor on your Arduino. As you push on either button, the servo should increase or decrease as shown on the serial monitor. Initially, the code will set the servo at 90 degrees. Use the button connected to pin 3 to increase the angle. When you reach 180 degrees, the high end of the rotation, the led connected to pin 5 will turn on. When you reach the low end of the range which is 0 degrees, the led connected to pin 6 will turn on.

To determine the result of the button push, a while statement verifies the button and the angle of the shaft. while (digitalRead(pin3) == HIGH && pos < 180) determines that the button was pushed (HIGH) and the angle is less than 180, so the program adds one degree and loops on. The second button while (digitalRead(pin4) == HIGH && pos > 0) determines that the button was pushed (HIGH) and the angle is greater than 0. This causes the angle to decrease by one and loops on. The LedHi and LedLow level for leds are each controlled by an if statement that checks the angle to see if it’s 0 or 180. The leds are turned off as soon as the angle changes in each of the two while statements.

Controlling a Servo Motor a Potentiometer

Build the circuit as shown in the diagram using a 10K potentiometer to control the servo motor. Then upload the code below.

#include <Servo.h>
int LowLed = 5;
int HiLed = 6;
Servo servo1;  
int pot = A0; 
int val;   

void setup() {
  servo1.attach(9);  
  pinMode(LowLed, OUTPUT);
  pinMode(HiLed, OUTPUT);
  Serial.begin(9600);
}
void loop() {
  val = analogRead(pot);            
  val = map(val, 0, 1023, 0, 180);     
  servo1.write(val);                  
  Serial.println(val);
  if (val == 0)
    digitalWrite(LowLed, HIGH);
  if (val == 180)
    digitalWrite(HiLed, HIGH);
  if (val > 0)
    digitalWrite(LowLed, LOW);
  if (val < 180)
    digitalWrite(HiLed, LOW);
  delay(10);
}

After uploading the code, open the Serial Monitor on your Arduino. As you adjust the potentiometer, the rotation of the servo will change accordingly. When you reach the lower limit of the range, the Low Led will turn on, and as you reach the upper limit, the High Led will turn on.

The code is straightforward. The first line of code in the Loop() Function should be:

val = analogRead(pot);            
val = map(val, 0, 1023, 0, 180);     
servo1.write(val);  

An Analog Read takes in the voltage from the potentiometer as an analog signal. It accepts the values of the full range of input accepted in an Arduino (0-5V). It captures it as an integer in the range of (0-1023). So for example, a DC value of 0V would be captured as the integer 0; a full range value of 5V would be captured as the integer 1023, and half the input range of 2.5V would be captured as the integer 512, half of 1023.

The next line of code val = map(val, 0, 1023, 0, 180); maps out the value of val within the range of 0,1023, to a value of 0,180.

The next line of code servo1.write(val); is the write() command that takes the integer stored in val as the argument and applies it to the servo. The servo receives a pulse from the servo1.write(val); and the pulse width is determined by the value of val. The servo uses the width of this pulse to determine its rotation.