IOT

How To Drive a Servo Motor Using ESP32 Development Board?

In this lesson, we’ll look at utilizing an ESP32 Development Board to drive a servo motor. We will first create a sweeping program that causes the servo to oscillate back and forth in order to show how the ESP32 Servo Control works. Then, we’ll show how to use a potentiometer to control the servo. Finally, because ESP32 is all about the Internet of Things development, we will use an ESP32 project to construct a web-controlled servo.

Servo-Sweep-ESP32

I’ve already created an ESP8266-based Web Controlled Servo. Check it out if you’re interested in that.

The Web Controlled Servo utilizing the ESP8266 was a prototype. You can use the same procedures and apply them to an ESP8266 NodeMCU board if you want to have the most recent design (as implemented in this project). [ESP32 Projects for Beginners]

Prerequisites

Little preparation is required before moving on, although there are two earlier ESP32 projects that will make it easier to construct this ESP32 Servo Control Project. The ESP32 PWM Tutorial is the first, while the ESP32 Web Server Tutorial is the second.

I’ll utilize the ESP32’s PWM Peripheral to control the servo instead of a servo motor control library. Determining how to produce PWM signals in the ESP32 via the LEDC Peripheral is so beneficial.

The second prerequisite is relatively easy to meet. You must create a web page and set up ESP32 as a web server in order to host it if you want to build an ESP32-based Web Controlled Servo Project. It will be very helpful to know how to build an ESP32 web server.

Therefore, finish such tasks before moving on.

A Brief Note on Servo Motors

Robotics, business, automation, CNC machines, and even do-it-yourself projects all require servo motors. Let’s discuss about the SG90 and MG 996R servo motors since we are looking for small, inexpensive servo motors to employ in our projects.

SG-90-MG-996R-Servo-Motors

Both of these servo motors are affordable and widely accessible. A metal gear servo, the MG 996R, has a torque of 9.4 kgf.cm compared to the plastic gear SG90’s 1.8 kgf.cm.

If you look at the datasheet for these servos, the MG 996R has a rotation angle of just 1200, compared to 1800 for the SG90.

The control signal for both of these servos is a PWM signal with a period of 20ms (50 Hz), and the pulse duration must be between 1ms and 2ms, according to the datasheets.

Servo-PWM-Period

The servo is in its “middle” position when the pulse duration is 1.5 milliseconds. A 1ms pulse causes the servo to move completely to the left, whereas a 2ms pulse causes the servo to move completely to the right.

NOTE: Because it is more readily available and used, I will use SG90 Servo Motors in all projects.

ESP32 Servo Control

As previously indicated, we will be using the LEDC PWM Controller to set the control signal of the Servo rather than “Servo” libraries. The wonderful thing about the LEDC PWM Controller is that you have total control over the frequency, resolution, and duty cycle of the PWM signal generation.

The PWM Signal’s frequency is set at 50 Hz in order to meet the requirements of the servo motor. It uses a typical 8-bit resolution. The setting of the duty cycle is crucial.

The duty cycle of the PWM signal, which runs between 1 ms for the extreme left, 2 ms for the extreme right, and 1.5 ms for center positions, defines the position of the servo.

Components Required

  • ESP32 DevKit Development Board
  • Servo Motor
  • 10 KΩ Potentiometer
  • Breadboard
  • Connecting Wires

Circuit Diagram

The connections between the ESP32 and the servo motor are depicted in the next illustration. The SG90 and MG 996R servo motors’ working voltage is 4.8V. Therefore, join the VCC (Red) wire to the ESP32’s VIN. The input from the USB is called VIN. Thus, it will be close to 5V. The GND (Brown) wire should be connected to one of the ESP32’s GND pins.

ESP32-Servo-Control-Circuit

The PWM Control Wire is the last (Orange). This wire should be connected to one of the ESP32’s PWM pins. I attached the control wire of the servo to GPIO 16 because the ESP32 does not have any dedicated PWM pins and you can effectively designate any GPIO Pin as a PWM Pin (marked as RX2 on the board).

Controlling Servo Motor using Serial

Let’s look at the first project’s “Duty cycle” data entry method for controlling the servo motor. The sole purpose of this project is to determine the “Duty cycleextreme “‘s values for a servo’s full rotation.

Code

  const int servoPin = 16;  /* GPIO16 */
   
  int dutyCycle = 0;
   
  /* Setting PWM properties */
  const int PWMFreq = 50;
  const int PWMChannel = 0;
  const int PWMResolution = 8;
  //const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) – 1);
   
  void setup()
  { 
  Serial.begin(115200);
  ledcSetup(PWMChannel, PWMFreq, PWMResolution);
  /* Attach the LED PWM Channel to the GPIO Pin */
  ledcAttachPin(servoPin, PWMChannel);
  ledcWrite(PWMChannel, dutyCycle);
  }
  void loop()
  {
  while(Serial.available())
  {
    String in_char = Serial.readStringUntil(‘\n’);
    dutyCycle = in_char.toInt();
    Serial.println(dutyCycle);
    ledcWrite(PWMChannel, dutyCycle);
    delay(10);
  }
  }

The duty cycle’s extreme values in my situation are 5 for the far left and 32 for the far right. These are the duty cycle restrictions that I must adhere to in extreme circumstances. Given that every Servo is unique, these settings might be different for you.

Therefore, after creating the connections, upload the code to the ESP32, open the serial monitor, enter different duty cycle values to test, and note the extremes to determine the limits.

ESP32 Servo Sweep

We may create a Servo Sweep programme that continuously oscillates between the extremes of left and right using the duty cycle restrictions mentioned above. This code is for that.

Code

  /* ESP32 Servo Sweep */
  const int servoPin = 16;  /* GPIO16 */
   
  int dutyCycle = 0;
   
  /* Setting PWM properties */
  const int PWMFreq = 50;
  const int PWMChannel = 0;
  const int PWMResolution = 8;
  //const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) – 1);
   
  void setup()
  { 
  Serial.begin(115200);
  ledcSetup(PWMChannel, PWMFreq, PWMResolution);
  /* Attach the LED PWM Channel to the GPIO Pin */
  ledcAttachPin(servoPin, PWMChannel);
  ledcWrite(PWMChannel, dutyCycle);
  }
  void loop()
  {
  for(dutyCycle = 5; dutyCycle <= 32; dutyCycle++)
  {
    ledcWrite(PWMChannel, dutyCycle);
    delay(70);   
  }
  for(dutyCycle = 32; dutyCycle >= 5; dutyCycle–)
  {
    ledcWrite(PWMChannel, dutyCycle);
    delay(70);   
  }
  }
Serial-Control-of-Servo-ESP32

Adjust Position of Servo using POT

Making accurate adjustments to the Servo Motor’s position with a Potentiometer is another valuable endeavour. An ESP32 ADC Pin is connected to a 10 K potentiometer. On the Development Board, the ADC1 CH0 is designated as VP, and I used that.

Due to the 12-bit ADC, the digital values from the output are in the 0–4095 range, and they are mapped to the duty cycle’s extremes (5 and 32).

Circuit Diagram

ESP32-Servo-Control-Potentiometer-Circuit

Code

  #define ADCPIN A0
   
  const int redLEDPin = 16;  /* GPIO16 */
   
  int dutyCycle = 0;
   
  int adcValue;
   
  /* Setting PWM properties */
  const int PWMFreq = 50;
  const int PWMChannel = 0;
  const int PWMResolution = 8;
  //const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) – 1);
   
  void setup()
  { 
  Serial.begin(115200);
  ledcSetup(PWMChannel, PWMFreq, PWMResolution);
  /* Attach the LED PWM Channel to the GPIO Pin */
  ledcAttachPin(redLEDPin, PWMChannel);
  ledcWrite(PWMChannel, dutyCycle);
  }
  void loop()
  {
  adcValue = analogRead(ADCPIN);
  dutyCycle = map(adcValue, 0, 4095, 5, 32);
  Serial.print(adcValue);
  Serial.print(”  “);
  Serial.println(dutyCycle);
  ledcWrite(PWMChannel, dutyCycle);
  delay(10);
  }
Adjust-Servo-POT-ESP32

ESP32 Web Controlled Servo

The Web Controlled Servo is the last project for ESP32 Servo Control. The procedure for building a web server with a website is the same as what we saw in the tutorial for the ESP32 web server.

I choose to have a Slider visible on the web page in order to adjust the Servo’s position. Adjusting the slider determines the SG90 Servo’s angle, and its range is, well, 0 to 180 because it may be placed anywhere between 00 and 1800.

The server receives a ‘GET’ request when we move the slider, and the requested angle is also included in the request. In order to relate the angle to the previously recorded duty cycle numbers, we must decode the angle from this request (5 and 32).

Code

All of the code’s significant portions were commented. Change the code to suit your needs (CSS Styling, Slider, Servo Duty Cycle range etc.). Change the code’s SSID and password as well (lines 5 and 6).

  #include <WiFi.h>
   
  const int servoPin = 16;  /* GPIO16 */
   
  const char* ssid = “ESP32-WiFi”; /* Add your router’s SSID */
  const char* password = “12345678”; /*Add the password */
   
  int dutyCycle = 0;
  //int position1 = 0;
   
  /* Setting PWM properties */
  const int PWMFreq = 50;
  const int PWMChannel = 0;
  const int PWMResolution = 8;
  const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) – 1);
   
  WiFiServer espServer(80); /* Instance of WiFiServer with port number 80 */
  /* 80 is the Port Number for HTTP Web Server */
   
  /* A String to capture the incoming HTTP GET Request */
  String request;
   
  void setup()
  { 
  Serial.begin(115200);
  ledcSetup(PWMChannel, PWMFreq, PWMResolution);
  /* Attach the LED PWM Channel to the GPIO Pin */
  ledcAttachPin(servoPin, PWMChannel);
  ledcWrite(PWMChannel, dutyCycle);
   
  Serial.print(“\n”);
  Serial.print(“Connecting to: “);
  Serial.println(ssid);
  WiFi.mode(WIFI_STA); /* Configure ESP32 in STA Mode */
  WiFi.begin(ssid, password); /* Connect to Wi-Fi based on the above SSID and Password */
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.print(“*”);
    delay(100);
  }
  Serial.print(“\n”);
  Serial.print(“Connected to Wi-Fi: “);
  Serial.println(WiFi.SSID());
  delay(100);
  /* The next four lines of Code are used for assigning Static IP to ESP32 */
  /* Do this only if you know what you are doing */
  /* You have to check for free IP Addresses from your Router and */
  /* assign it to ESP32 */
  /* If you are comfortable with this step, */
  /* please un-comment the next four lines and make necessary changes */
  /* If not, leave it as it is and proceed */
  //IPAddress ip(192,168,1,6);  
  //IPAddress gateway(192,168,1,1);  
  //IPAddress subnet(255,255,255,0);  
  //WiFi.config(ip, gateway, subnet);
  delay(2000);
  Serial.print(“\n”);
  Serial.println(“Starting ESP32 Web Server for Servo Control…”);
  espServer.begin(); /* Start the HTTP web Server */
  Serial.println(“ESP32 Servo Web Server Started”);
  Serial.print(“\n”);
  Serial.print(“The URL of ESP32 Servo Web Server is: “);
  Serial.print(“http://”);
  Serial.println(WiFi.localIP());
  Serial.print(“\n”);
  Serial.println(“Use the above URL in your Browser to access ESP32 Servo Web Server\n”);
  }
  void loop()
  {
  WiFiClient client = espServer.available(); /* Check if a client is available */
  if(!client)
  {
    return;
  }
   
  Serial.println(“New Client!!!”);
  boolean currentLineIsBlank = true;
  while (client.connected())
  {
    if (client.available())
    {
      char c = client.read();
      request += c;
      Serial.write(c);
        /* If you’ve gotten to the end of the line (received a newline */
        /* character) and the line is blank, the http request has ended, */
        /* so you can send a reply */
      if (c == ‘\n’ && currentLineIsBlank)
      {
        client.println(“HTTP/1.1 200 OK”);
        client.println(“Content-type:text/html”);
        client.println(“Connection: close”);
        client.println();
   
        client.println(“<!DOCTYPE html>”);
        client.println(“<html>”);
        
        client.println(“<head><meta name=\”viewport\” content=\”width=device-width, initial-scale=1\”>”);
        client.println(“<link rel=\”icon\” href=\”data:,\”>”);
   
        /* CSS Styling for Text and Slider */
        
        client.println(“<style>body { font-family: \”Courier New\”; margin-left:auto; margin-right:auto; text-align:center;}”);
        
        client.println(“.slidecontainer { width: 100%;}”);
        client.println(“.slider { -webkit-appearance: none;”);
        client.println(“width: 30%; height: 20px; background: #d3d3d3;”);
        client.println(“outline: none; opacity: 0.7; -webkit-transition: .2s; transition: opacity .2s;}”);
        client.println(“.slider:hover { opacity: 1; }”);
   
        client.println(“.slider::-webkit-slider-thumb { -webkit-appearance: none;”);
        client.println(“appearance: none; width: 15px; height: 28px;”);
        client.println(“border-radius: 30%; background: #4CAF50; cursor: pointer;}”);
        client.println(“.slider::-moz-range-thumb { width: 25px; height: 25px; background: #4CAF50; cursor: pointer;}</style>”);
        
        client.println(“<script src=\”https://code.jquery.com/jquery-3.6.0.min.js\”></script>”);
        /*Actual Web Page */
        client.println(“</head><body><h2>ESP32 Web Controlled Servo</h2>”);
        client.println(“<p>Drag the slider to rotate the Servo.</p>”);
        
        client.println(“<input type=\”range\” min=\”0\” max=\”180\” class=\”slider\” id=\”servoRange\” onchange=\”servo(this.value)\”/>”);
        client.println(“<p>Angle: <span id=\”servoPos\”></span></p>”);
        client.println(“<script>”);
        client.println(“var slider = document.getElementById(\”servoRange\”);”);
        client.println(“var output = document.getElementById(\”servoPos\”);”);
        client.println(“output.innerHTML = slider.value;”);
        client.println(“slider.oninput = function(){output.innerHTML = this.value;}”);
        client.println(“$.ajaxSetup({timeout:1000}); function servo(angle) { “);
        client.println(“$.get(\”/servovalue=\” + angle); {Connection: close};}</script>”);
                
        client.println(“</body></html>”);  
        
        /* The request will be in the form of
          * GET /servovalue=143 /HTTP/1.1*/
        if(request.indexOf(“GET /servovalue=”) != -1)
        {
          int position1 = request.indexOf(‘=’); /* Find out the position of ‘=’ in the request string */
          String angleStr = request.substring(position1+1); /* Next 2/3 characters inform the desired angle */
          int angleValue = angleStr.toInt();
          dutyCycle = map(angleValue, 0, 180, 5, 32);
          ledcWrite(PWMChannel, dutyCycle);
        }
        client.println();
        break;
      }
   
        if(c == ‘\n’)
        {
          currentLineIsBlank = true;
        }
        else if(c != ‘\r’)
        {
          currentLineIsBlank = false;
        }
        //client.print(“\n”);
    }
  }
   
  delay(1);
  request = “”;
  //client.flush();
  client.stop();
  Serial.println(“Client disconnected”);
  Serial.print(“\n”);
  }

The web page for the ESP32’s Web Controlled Servo was viewed using a laptop’s Chrome browser in the screenshot that follows.

Web-Controlled-Servo-Page

The ESP32 Web Server receives a request whenever we move the slider, and the request is shown on the serial monitor in the screen capture that follows.

ESP32-Web-Servo-Request

The following image is a screenshot of a web page accessed on a mobile phone; you may also visit the web page on a mobile as long as both ESP32 and the mobile phone are linked to the same Wi-Fi network.

ESP32-Web-Servo-Mobile

Conclusion

`I hope all of you have become familiar about driving the servo motor with the ESP32 Development Board. We MATHA ELECTRONICS will be back soon with more informative blogs soon.

Leave a Reply

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