Control a servo with Arduino and a potentiometer

Control a servo with a potentiometer using an Arduino Uno

We are going to play today with a micro servo. In general, a servo motor is a rotary actuator o linear actuator and it allows for precise control of angular or linear position, velocity and acceleration. Micro servos, which are just small servos, are widely used in radio control (RC) vehicles and robotics. Being able to control a servo motor is important because it allows you to physically operate  the world around you from the Arduino.

1. An Arduino board with an USB connection and the Arduino IDE installed.
2. Here I used a 2K ohm linear potentiometer, but you may use a different one.
3. A micro-servo motor, for this post I used a TowerPro SG90, but any similar micro-servo should work. You can control a bigger servo, but in that case you cannot power it using the Arduino and it has to have its own power supply.
4. A breadboard and wires.

Circuit diagram
The circuit diagram can be splatted in two parts, one is a voltage divider using a potentiometer and the other part is the connection to the servo motor. The connection of the different elements should look like this:

Circuit diagram to control a servo with a potentiometer

As said, because we are using a small micro servo, you can power it directly to the Arduino board. If you want to control more than one servo, or you want to use a more powerful servo, you should add a power supply for the servo(s) and remember to connect the ground of the Arduino to the ground of your power supply!, in that case the circuit diagram will look like this:

Circuit diagram with an external power supply using AA batteries
Circuit diagram with an external power supply using 4 AA batteries (I’ve assumed that the servo operates within 4.8 to 6V)

Arduino Code
I’m going to divide the code in two parts to make it clear, the first part is where I declare all the variables I need:

As you can see, the first thing is to include the servo library which is already installed with the Arduino IDE, so you just have to call it. Then I declare three variables for the servo, the first one is the position, the second one is the pin where I have connected the device (in this case the servo is connected to digital pin number 9 on the Arduino Uno board) and finally a small delay to let the servo reach its position and settle down before sending a new position.

Once everything is declared for the servo, we need to declare the two variables we need for the potentiometer: the first value is to store the value we read from the potentiometer and the second variable is the pin where I have connected the potentiometer, in this case is the analog in pin A0.

In the void setup, the one that only runs once, we declare to what pin the servo is connected. Next, inside the void loop, the first thing we do is reading the potentiometer doing an analogRead(pin) of the pin where it is connected. Now comes the ‘tricky’ part, how to convert the reading from the potentiometer to a position from 0 to 180 degrees for the micro servo:

What we know:
– The servo range of movement goes from 0 to 180 degrees, sometimes the servos don’t fully get the full range, so you may want to reduce the range from 5 to 175 degrees for example to be safe.
– The potentiometer read (that is, the analogRead()) goes from 0 to 1023.

With this information we can start to think about the situations we can guess. The first one is when the potentiometer reading is 0 and this should move the first potentiometer position, which will be 5 degrees. In the same way, we know that the final point is when the potentiometer reading is 1023 and the servo position is 175. This gives us two points as in the following plot:

Servo position vs potentiometer read plot
Servo position vs potentiometer read plot

And because we want a linear change with the potentiometer read, we can use now the equation of a line to figure out how to calculate the angle of the servo from the potentiometer read:
– The slope of the line is calculated as m=(y_2-y_1)/(x_2-x_1) where our y values are the servo position and our x values are the potentiometer readings. This translates to m=(175-5)/(1023-0)=170/1023.
– The equation of a line is y-y_1=m(x-x_1) which in our case, using the first point (0,5) leads us to y-5=170/1023(x-0).

Rearranging a little bit and using the defined variables x = potRead and y = pos whe have: pos=170/1023potRead+5, which is what is written on line 7 in the second chunk of code. The point after the values inside the division is to tell the Arduino to do a float division even if later the value is truncated to an integer. It is recommended to do it this way because when we divide integers weird things might happen and this simple addition solves that problem.

Finally, the calculated position of the servo is sent to the servo motor and we finally give a small delay for the servo to reach the position. The code is now completed, you can copy it from the previous blocks or find it on my Github account. The last required step is to just send the code to the Arduino board. Once is uploaded, every change made on the potentiometer knob will move the servo motor position in any direction.


  • ​hey bro can u please help me with something

    ​i am using servos in the back wheels of car so i mod this motor to rotate continuously with help of you-tube videos now i want that if i push up the joystick module so the motor start rotating in that direction and keep rotating until i release the stick and when i release the pressure from stick the motor should stop immediately.

    can u please help me with the code in this case

    ​thnx in advance

    • Ok, what you need is to read the position of the joystick and when it is higher than a certain value, the servo angle has to increase (or decrease). The arduino code should be something in this line (be aware that I didn’t try this, so it will not work if you just copy it)

      int xPin_joy = A0; //pin to read the position of the joystick (left - right)
      int xPos_joy; //integer to read the position
      int pos = 0; //declare variable for servo position
      int servoPin = 9; //declare the pin where the servo is connected
      Servo myServo; // create a servo object called myServo

      void setup() {
      pinMode(xPin_joy, INPUT); //the pin is configured as an input
      myServo.attach(servoPin); //declare to which pin is the servo connected
      void loop() {
      xPos_joy = analogRead(xPin_j1);
      //This is the part you have to change yourself, depending the value you enter in 'enter_value_here', you will have a different dead zone
      if (xPos_joy>enter_value_here){
      pos = pos+5; // update the position that will go to the servo, so it will keep rotating
      myServo.write(pos); //write the position on the servo
      delay(100); // add some delay between reads

      Also, if you want it to go reverse, you have to add another if loop that a certain vale (negative position in the x axis) will substract a certain angle in the position of the servo

      • ok thnx alot
        i’ll give it a try and let you know the result and if have any problem i’ll post it

  • Hi, I know that this question sounds basic, but how the servoDelay is 15 ms, the interaction between the potentiometer (input) and the servo (output) is faster right? So if the servo Delay is 1000 ms, then the response of the servo to the signal emitted by the potentiometer is slower right.
    Second question, how did you know that the potentiometer read goes from 0 to 1023, is this a measurement of the resistance from potentiometer or just some calculation from arduino program?

    Thanks in advance, these are my questions,have a nice day.

    • Hi Stephan,

      Sorry for the delay in answering you. The servoDelay is included so the servo has some time to get to the correct position before reading a second input. It will also work as you say, you put 1000ms and the servo will reach the position and stay idle until the time is finished.

      To your second question, the analogRead() function from Arduino maps an input between 0 to 5V into integer values from 0 to 1023 (as you can see in the reference). That’s how I know what to use in the code.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.