How to Control Servo Motor with ESP32 and Arduino IDE

In this tutorial, we’re going to show you how to control servo motor with an ESP32 Web Server. Before we build the web server, we'll take a short look at ESP32 servo control.

Parts List

You will need the following items to proceed with this project:

You can use the preceding links to find all the parts for your projects at the best price!

lilygo Official Store

Connecting the Servo Motor to the ESP32

Power, ground, and signal wires are present in servo motors. The signal wire is often yellow, orange, or white; the power wire is typically red; and the GND wire is typically black or brown.

servo motor wires
WireColor
PowerRed
GNDBlack, or brown
SignalYellow, orange, or white

You can power a small servo like the S0009 directly from the ESP32 while using it, as shown in the figure below.

servo motor s009

However, you'll probably need to use an external power supply to power your servos if you're using many servos or a different type.

servo motors

If you’re using a small servo like the S0009, you need to connect:

  • GND -> ESP32 GND pin;
  • Power -> ESP32 VIN pin;
  • Signal -> GPIO 13 (or any PWM pin).

Note: Any ESP32 GPIO can produce a PWM signal; therefore, you may use any of them in this situation. However, as GPIOs 9, 10, and 11 are linked to the integrated SPI flash and are not intended for other purposes, we do not recommend using them.

Schematic

In our case, the signal wire will be connected to GPIO 13. As a result, you may wire your servo motor by following the next schematic.

keyestudio Official Store

servo esp32 schematic

How to Control a Servo Motor?

Various angles, ranging from 0 to 180°, may be used to position the servo's shaft. Using a pulse width modulation (PWM) signal, servos are controlled. This implies that the position of the shaft will be determined by the PWM signal sent to the motor.

0 180 degrees

The ESP32's PWM capabilities may be used to operate the motor by simply sending a signal at 50 Hz with the right pulse width. Alternatively, you may use a library to greatly simplify this task.

Preparing the Arduino IDE

The ESP32 may be programmed using the Arduino IDE and its programming language, using an add-on for that platform. If you haven't already, prepare your Arduino IDE to work with the ESP32 by following one of the next tutorials.

After making sure you have the ESP32 add-on installed, you can continue this tutorial.

Installing the ESP32_Arduino_Servo_Library

The ESP32 Arduino Servo Library makes it simpler to use your ESP32 to operate a servo motor using the Arduino IDE. Install the library in your Arduino IDE by following the next steps:

TSCINBUNY Official Store

  1. Click here to download the ESP32_Arduino_Servo_Library. You should have a .zip folder in your Downloads folder.
  2. Unzip the .zip folder and you should get ESP32-Arduino-Servo-Library-Master folder.
  3. Rename your folder from ESP32-Arduino-Servo-Library-Master to ESP32_Arduino_Servo_Library.
  4. Move the ESP32_Arduino_Servo_Library folder to your Arduino IDE installation libraries folder.
  5. Finally, re-open your Arduino IDE.

Testing an Example

Go to your Arduino IDE after installing the library. Go to File > Examples > ServoESP32 > Simple Servo after making sure the ESP32 board is chosen.

/*********
  LEDEdit PRO
  Complete project details at https://lededitpro.com  
  Written by BARRAGAN and modified by Scott Fitzgerald
*********/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

void setup() {
  myservo.attach(13);  // attaches the servo on pin 13 to the servo object
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
}

Understanding the code

The servo rotates 180 degrees to one side and 180 degrees to the other in this sketch. See how it works below.

First, you need to include the Servo library:

#include <Servo.h>

Then, you need to create a servo object. In this case, it is called “myservo“.

Servo myservo;

setup()

You attach GPIO 13 to the servo object in the setup() and initialize serial communication for debugging purposes.

void setup() {  
  myservo.attach(13); 
}

loop()

The motor's shaft position is changed from 0 to 180 degrees in the loop() function, and then back to 0 degrees again. You just need to use the write() function of the servo object to set the shaft to a certain position. You provide an integer number with the position in degrees as an input.

myservo.write(pos);

Testing the Sketch

On your ESP32, upload the code. After uploading the code, you should see the motor's shaft rotating to one side and then to the other.

Creating the ESP32 Web Server

Let's build the web server to control the servo now that you know how to do it with the ESP32. We'll build the following web server:

  • Contains a slider from 0 to 180 that you can adjust to control the servo’s shaft position;
  • The current slider value is automatically updated on the web page, as is the shaft position, without the need to refresh the web page. For this, we use AJAX to send HTTP requests to the ESP32 in the background.
  • Refreshing the web page doesn’t change the slider value or the shaft position.
esp32 servo web server browser

Creating the HTML Page

Let’s start by taking a look at the HTML text the ESP32 needs to send to your browser.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
    body {
      text-align: center;
      font-family: "Trebuchet MS", Arial;
      margin-left:auto;
      margin-right:auto;
    }
    .slider {
      width: 300px;
    }
  </style>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
  <h1>ESP32 with Servo</h1>
  <p>Position: <span id="servoPos"></span></p>
  <input type="range" min="0" max="180" class="slider" id="servoSlider" onchange="servo(this.value)"/>
  <script>
    var slider = document.getElementById("servoSlider");
    var servoP = document.getElementById("servoPos");
    servoP.innerHTML = slider.value;
    slider.oninput = function() {
      slider.value = this.value;
      servoP.innerHTML = this.value;
    }
    $.ajaxSetup({timeout:1000});
    function servo(pos) {
      $.get("/?value=" + pos + "&");
      {Connection: close};
    }
  </script>
</body>
</html>

Creating a Slider

This project involves building a slider for the HTML page. The <input> tag is used in HTML to create sliders. The <input> tag specifies a field in which the user may enter data.

A wide variety of input types are available. Use the “type” property together with the “range” value to define a slider. Using the “min” and “max” properties in a slider, you also need to define the minimum and maximum ranges.

<input type="range" min="0" max="180" class="slider" id="servoSlider" onchange="servo(this.value)"/>

You also need to define other attributes, like:

  • the class to style the slider.
  • the id to update the current position displayed on the web page.
  • And finally, the onchange attribute calls the servo function to send an HTTP request to the ESP32 when the slider moves.

Adding JavaScript to the HTML File

Using the <script> and </script> tags, you will now need to add some JavaScript code to your HTML file. With the current web slider position, this snippet of code updates the web page:

var slider = document.getElementById("servoSlider");
    var servoP = document.getElementById("servoPos");
    servoP.innerHTML = slider.value;
    slider.oninput = function() {
      slider.value = this.value;
      servoP.innerHTML = this.value;
    }

And the next lines make an HTTP GET request to the ESP IP address in this specific URL path: /?value=[SLIDER_POSITION]&.

$.ajaxSetup({timeout:1000});
function servo(pos) {
  $.get("/?value=" + pos + "&");
}

For example, when the slider is at 0, you make an HTTP GET request on the following URL:

http://192.168.1.135/?value=0&

And when the slider is at 180 degrees, you’ll have something as follows:

http://192.168.1.135/?value=180&

The servo motor may then be moved to the right position when the ESP32 receives the GET request and retrieves the value parameter from the URL.

Code

Now we must include the previous HTML text in the sketch and rotate the servo as needed. This next sketch does precisely that.

Note: As previously mentioned, you need to install the ESP32 add-on in your Arduino IDE. If you haven't previously, install the ESP32 board in the Arduino IDE using one of the following tutorials:

But before you upload it, copy the following code into your Arduino IDE: Let's take a quick look at how it works first.

/*********
  LEDEdit PRO
  Complete project details at https://lededitpro.com  
*********/

#include <WiFi.h>
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

// GPIO the servo is attached to
static const int servoPin = 13;

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Decode HTTP GET value
String valueString = String(5);
int pos1 = 0;
int pos2 = 0;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

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

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

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
            client.println(".slider { width: 300px; }</style>");
            client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
                     
            // Web Page
            client.println("</head><body><h1>ESP32 with Servo</h1>");
            client.println("<p>Position: <span id=\"servoPos\"></span></p>");          
            client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider\" onchange=\"servo(this.value)\" value=\""+valueString+"\"/>");
            
            client.println("<script>var slider = document.getElementById(\"servoSlider\");");
            client.println("var servoP = document.getElementById(\"servoPos\"); servoP.innerHTML = slider.value;");
            client.println("slider.oninput = function() { slider.value = this.value; servoP.innerHTML = this.value; }");
            client.println("$.ajaxSetup({timeout:1000}); function servo(pos) { ");
            client.println("$.get(\"/?value=\" + pos + \"&\"); {Connection: close};}</script>");
           
            client.println("</body></html>");     
            
            //GET /?value=180& HTTP/1.1
            if(header.indexOf("GET /?value=")>=0) {
              pos1 = header.indexOf('=');
              pos2 = header.indexOf('&');
              valueString = header.substring(pos1+1, pos2);
              
              //Rotate the servo
              myservo.write(valueString.toInt());
              Serial.println(valueString); 
            }         
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

How the Code Works

First, we include the Servo library, and create a servo object called myservo.

#include <Servo.h> 
Servo myservo; // create servo object to control a servo

We also create a variable to hold the GPIO number the servo is connected to. In this case, GPIO 13.

const int servoPin = 13;

Do not forget that you need to modify the following two lines to include your network credentials.

// Replace with your network credentials const char* ssid = ""; 
const char* password = "";

To extract the slider position from the HTTP request, create a couple of variables.

// Decode HTTP GET value 
String valueString = String(5); 
int pos1 = 0; 
int pos2 = 0;

setup()

The servo has to be attached to the GPIO it is connected to in setup() using the myservo.attach() function.

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

loop()

To show the web page, the first part of the loop() builds the web server and sends the HTML text. In this web server method, we use the same method.

The following part of the code retrieves the value from the HTTP request for the slider.

//GET /?value=180& HTTP/1.1 if(header.indexOf("GET /?value=")>=0) { pos1 = header.indexOf('=');   pos2 = header.indexOf('&');   valueString = header.substring(pos1+1, pos2); 

Make an HTTP request to the following URL, which contains the slider position between the = and & signs, when you move the slider:

http://your-esp-ip-address/?value=[SLIDER_POSITION]&

The slider position value is saved in the valueString variable.

Then, using myservo.write() and the valueString variable as parameters, we set the servo to that specific position. We need to use the toInt() method to change the valueString variable from a string to an integer number, which is the data type that the write() method accepts.

myservo.write(valueString.toInt());

Testing the Web Server

The code may now be uploaded to your ESP32. Ensure that the right board and COM port are chosen. Aside from that, don't forget to modify the code to include your network credentials.

Open the Serial Monitor with a 115200 baud rate after uploading the code.

serial monitor

Copy the ESP32 IP address that shows up on the Serial Monitor after pressing the ESP32Enable” button to restart the board.

ESP IP address

You should be able to see the web page you previously produced if you open your browser and paste the ESP IP address. To control the servo motor, slide the slider.

esp32 servo motor move slider

When you move the slider, you can also see the HTTP requests that you're sending to the ESP32 in the Serial Monitor.

servo motor esp32 serial monitor

Experiment with your web server for a while to see if it’s working properly.

Conclusion

In conclusion, you have learned how to create a web server with a slider to control its position as well as how to control a servo motor using the ESP32.

This is just one example of servo motor control. A text input field, several buttons with predefined angles, or any other suitable input field may be used in place of a slider.

If you like ESP32, you may also like:

We hope you find this tutorial useful. Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *

Developing IoT Projects with ESP32

Automate your home or business with inexpensive Wi-Fi devices