ESP8266 Webserver Controller Servo Motor





ESP8266 is commonly use in all types of IoT projects, Automation, Robot, Hacking, DIY projects and many more. But I will be creating a simple webpage for access in laptop, smartphone, other device to send the data to NodeMCU for control the motors.  

In this post, I am gonna show you how to control a Servo or Stepper motor using ESP8266 NodeMCU module with a webpage which includes:-

>>ESP8266 Webserver and how it’s Work…?

>>Servo Motor

>>Parts Requirements

>>Circuit Diagram

>>Software, Library and Code

>> Final

 

ESP8266 Webserver and how its work….?

A Webserver is a system which stores, processes and send websites or webpages to Web clients. Our devices browsers are web client like Google Chrome, Firefox, Microsoft Edge and etc. The Server and client use a protocol to communicate with each other’s which called Hypertext Transfer Protocol (HTTP) where web client make a request for information from the server using HTTP. An ESP8266 NodeMCU can be programmed and use as a Webserver at all. It can set up its own network and allow all devices to connect with it by Access Point. An ESP8266 Server must have a web page in the form of HTML Hyper Text Mark-up Language, When a Web Client send a request in smartphone, Laptop, Tablet web browser over HTTP by clicking the button, sliding and etc, the ESP8266 server will respond with their GPIO pins.

 ESP8266 has 2 most common and famous feature webserver projects are:-

1.     Station Mode (STA)

In this mode, ESP8266 can connects to an existing network which has created with your smartphone Hotspot or Wireless Router but after connected ESP8266 gets an IP address from your wireless connection which you can type into your browser and its deliver a Web Pages.

2.     Soft Access Point Mode (AP)

In this mode, ESP8266 can creates its own Wi-Fi Network for one or more Stations but it only connects 5 station at a time. In AP Mode, it’s create a new Wi-Fi Network and sets SSID, Password and IP address where it can deliver web pages to all connected device.

Simply in this project I am using this Access Point Mode for controlling The Motors.


Servo Motor

Servo Motors are commonly used in Robotics, Electronics, Automations and more. Normally a Servo Motors are used in Arduino with a pot for adjusting the servo angle.

Parts Requirements

ESP8266 NodeMCU Module

Servo Motor

Breadboard

Jumper Wire and LED

Circuit Diagram

Here is the simple diagram for connection.



First Connect the Servo motor 5V+ with the NodeMCU VCC Pin

Second Connect the Servo Motor GND with the NodeMCU GND Pin.

The Third and Last Servo PWM connect with the NodeMCU D1 Pin.

Here In Diagram I have added a LED for signal indicator in Digital Pin 5 and GND.

Software, Library and Code

Open Arduino IDE Copy the Code from Here Rename it ESP8266 Servo Webserver and paste on it.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <Servo.h>  //Include the Servo Library

#include "PageIndex.h"; //--> Include the contents of the User Interface Web page from website, stored in the same folder as the .ino file  

#define ServoPort D1   //--> Defining Servo Port

#define LED1  D5   //-->Defining a Simple LED

//Make a wifi name and password as access point

const char* ssid = "ESPServo";  // your SSID

const char* password = "12345678"; //WIFI Password


Servo myservo;  //--> create servo object to control a servo

ESP8266WebServer server(80);  //--> Server on port 80

String SERstate1 = "OFF";

//This routine is executed when you open NodeMCU ESP8266 IP Address in browser

void handleRoot() {

  String s = MAIN_page; //Read HTML contents

  server.send(200, "text/html", s); //Send web page

}

//Procedure for handling servo control

void handleServo() {
  String POS = server.arg("servoPOS");
  int pos = POS.toInt();
  myservo.write(pos);   //--> Move the servo motor according to the POS value
  delay(15);
  Serial.print("Servo Angle:");
  Serial.println(pos);
  server.send(200, "text/plane", "");
}

void controlServo() {
  String t_state = server.arg("SERstate1");
  Serial.println(t_state);
  int pos;
  if (t_state == "1") {
    SERstate1 = pos;
    controlLED1();
    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
    }
    controlLED1();
  }
  else if (t_state == "2") {
    SERstate1 = pos;
    myservo.write(45);
    controlLED1();
  }
  else if (t_state == "3") {
    SERstate1 = pos;
    myservo.write(90);
    controlLED1();
  }
  else if (t_state == "4") {
    SERstate1 = pos;
    myservo.write(180);
    controlLED1();
  }
  else {
    SERstate1 = "OFF";
  }
  server.send(200, "text/plane", SERstate1);
}

void statusSER() {
  server.send(200, "text/plane", SERstate1);
}
void controlLED1() {
  digitalWrite(LED1, HIGH);
  delay(200);
  digitalWrite(LED1, LOW);
  delay(200);
}


void setup() {

  Serial.begin(115200);
  delay(500);
  myservo.attach(ServoPort); //--> attaches the servo on D1 to the servo object
  pinMode(LED1, OUTPUT);
  Serial.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);


  //Initialize Webserver
  server.on("/", handleRoot); //--> Routine to handle at root location. This is to display web page.
  server.on("/setPOS", handleServo); //--> Sets servo position from Web request
  server.on("/setSER1", controlServo);
  server.on("/readSER1", statusSER);
  server.begin();

  Serial.println("HTTP server started");

}


void loop() {

  server.handleClient();

}

After the main code Press Crtl+Shift+N for new tab and rename it PageIndex.h and press Enter then copy the this HTML code from here and again paste on it and Save it.

//Press Crtl+Shift+N for new tab and name it PageIndex.h and paste here
//Copy the HTML Code and paste in it

const char MAIN_page[] PROGMEM = R"=====(

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      html {
        font-family: Arial;
        display: inline-block;
        margin: 0px auto;
        text-align: center;
      }

      .slidecontainer {
        width: 100%;
      }

      .slider {
        -webkit-appearance: none;
        width: 50%;
        height: 15px;
        border-radius: 5px;
        background: rgb(102, 230, 17);
        outline: none;
        opacity: 0.5;
        -webkit-transition: .2s;
        transition: opacity .2s;
      }

      .slider:hover {
        opacity: 2;

      }
      
      .slider::-webkit-slider-thumb {
        -webkit-appearance: none;
        appearance: none;
        width: 25px;
        height: 25px;
        border-radius: 50%;
        background: rgb(26, 182, 202);
        cursor: pointer;
      }
      
      .slider::-moz-range-thumb {
        width: 25px;
        height: 25px;
        border-radius: 50%;
        background: #4CAF50;
        cursor: pointer;
      }
     
         /* Style the botton start stop */
   .btn{
   /* position: relative;
    border-radius: 15px 15px 15px 15px;
    width: 8%;
    height: 25px;
    border: none;
    outline: none;
    cursor: pointer;
    background: #fa1cb7;
    color: rgb(255, 255, 255);
    */
     background-color: #fa1cb7;
  color: white;
  padding: 14px 25px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
   }

   a:link, a:visited {
  background-color: #f44336;
  color: white;
  padding: 14px 25px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
}

a:hover, a:active {
  background-color: red;
}
       
        /* Style the footer */
   footer {
      background-color: rgb(43, 57, 255);
      padding: 8px;
      text-align: center;
      color: rgb(0, 255, 21);
      font-family: Comic Sans MS;
   }

    </style>
  </head>
  
  <body>
    <h1>ESP8266 NodeMCU Web Server Controlled Servo Motor</h1>
    <br><br>
    <div class="slidecontainer">
      <input type="range" min="0" max="180" value="50" class="slider" id="myRange">
      <p>Servo angle: <span id="demo"></span></p>
       <br><br>
      <label> Servo Sweep </label>
       <button type="button" onclick="sendData2(1)" class="btn">Start</button>
        <br><br>
        <label> 45 Degree Angle </label>
        <button type="button" onclick="sendData2(2)" class="btn">45 Degree</button>
         <br><br>
        <label> 90 Degree Angle </label>
        <button type="button" onclick="sendData2(3)" class="btn">90 Degree</button>
        <br><br>
        <label> 180 Degree Angle </label>
        <button type="button" onclick="sendData2(4)" class="btn">180 Degree</button>

      <label><span id="isiStatusSER1"></span></label>

    </div>
    
    <script>
      function sendData(pos) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
          if (this.readyState == 4 && this.status == 200) {
            console.log(this.responseText);
          }
        };
        xhttp.open("GET", "setPOS?servoPOS="+pos, true);
        xhttp.send();
      } 
        /* fungsi send data on/off */
        function sendData2(StatusSer1) { 
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
          if (this.readyState == 4 && this.status == 200) { 
            document.getElementById("SERstate1").innerHTML = this.responseText;     
          }
        };
        
        xhttp.open("GET", "setSER1?;SERstate1=" + StatusSer1, true);   
        xhttp.send();
        }

    /* fungsi read data on/off */
        function getDataSER1() {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
          if (this.readyState == 4 && this.status == 200) {
            document.getElementById("isiStatusSER1").innerHTML = this.responseText;
          }
        };
        xhttp.open("put", "readSER1", true);    
        xhttp.send();
        }
      var slider = document.getElementById("myRange");
      var output = document.getElementById("demo");
      output.innerHTML = slider.value;
      slider.oninput = function() {
        output.innerHTML = this.value;
        sendData(output.innerHTML);
      }

    </script>
     <br><br><br><br>
     <footer>
     <p>
       By ElecoTecoz</br>
      </p>
     <p>Pls Subscribe my Channel</p>
     <a href="https://www.youtube.com/channel/UCdGUOMS_ufSE8xVxVRf8SGg" target="_blank">Subscribe</a>

    </footer>

  </body>

</html>
)=====";

 Check the Board on Tools menu set NodeMCU 1.0 (ESP-12E Module) then Select the COM Port of your USB Connection.


Other Projects:-

Arduino Joystick Controlled Stepper Motor (2 Axis)

MPU6050 Tutorial and Processing IDE

ESP32 Cam Tutorial and Control Wi-Fi Camera using Smartphone



Final



After the Complete Programming open the Wi-Fi on your Device find the ESPServo then press and set the password 12345678 or what you set in the code then connect with it. Now open your Browser and type the IP Address 192.168.4.1 and you will get the webpage.



Comments

  1. Hi Electechoz,

    Thank you for the excellent write up on controlling the servo. How can i add
    a forward and back servo control button for a smaller step 1 or 10 in your code?
    thank you

    ReplyDelete
  2. Obrigado pela partilha do seu trabalho, Eu gostava de saber se podia ter o ip 192.168.2.xxx . e não o ip 192.168.4.1

    ReplyDelete
  3. Thanks for sharing your work, I was wondering if I could have the ip 192.168.2.xxx . and not the ip 192.168.4.1

    ReplyDelete
    Replies
    1. Add the following in your section before the setup()
      // Set your Static IP Address Settings
      IPAddress local_IP(192,168,1,31);
      IPAddress gateway(192,168,1,1);
      IPAddress subnet(255,255,0,0);
      IPAddress primaryDNS(8,8,8,8);
      IPAddress secondaryDNS(8,8,4,4);

      This will make 192.168.1.31 the permanent IP address. Use any number upto 250

      Delete
  4. Can you create a sketch for two servos simultaneously PAN&TIL.Thank you

    ReplyDelete
  5. Bonjour apres avoir essaye pendant plusieurs jour , l'ide arduino n'accepte pas le programme il y a un message d'erreur tres long qui me signifie beaucoup de probleme , et pour la pageindex.h egalement impossible a faire fonctionner.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. MUITO BOM O SEU CODIGO MAS NAO CONSEGUI ACHAR O NUMERO IP DDA MINHA PORTA PODERIA ME AJUDAR POR FAVOR?

    ReplyDelete
  8. consegui resolver o meu problema fiz uma mudança nessa parte e ficou assim:
    void setup() {

    Serial.begin(115200);

    //Conexão na rede WiFi
    Serial.println();
    Serial.print("Conectando a ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi conectado!");

    // Inicia o servidor WEB
    server.begin();
    Serial.println("Server iniciado");

    // Mostra o endereco IP
    Serial.println(WiFi.localIP());
    a parte de cima eu mudei ai me mandou para um numero ip valido e logo

    //Initialize Webserver
    server.on("/", handleRoot); //--> Routine to handle at root location. This is to display web page.
    server.on("/setPOS", handleServo); //--> Sets servo position from Web request
    server.on("/setSER1", controlServo);
    server.on("/readSER1", statusSER);
    server.begin();

    ReplyDelete
  9. A fatal esptool.py error occurred: could not open port 'COM3': FileNotFoundError(2, 'The system cannot find the file specified.', None, 2)
    I'm currently facing this issue when I tries to upload the sketch

    ReplyDelete
  10. It would help your code by changing the line server.send(200, "text/plane", ""); to using the word “plain” which means simple, instead of “plane”, which is short for airplane.

    ReplyDelete
  11. Good work, a few things need attention. First, with several servos i tried, they will not travel the full 180 degrees, until I modified the attach statement to myservo.attach(ServoPort,500,2400);
    Next the slider value doesn't change when buttons are used. I'm looking into that. None the less, great instructional.

    ReplyDelete

Post a Comment