webserver控制伺服馬達-ESP32

 webserver控制伺服馬達-ESP32

伺服馬達對於微控板玩家一定是再熟悉不過,也是入門必學的元件之一,只是特別要注意如果要控制2個以上的伺服馬達,一定要使用外接電源或者PCA9685。

伺服馬達有很多款,小型常用的就屬SG-90,它是塑膠齒輪,還有一種是金屬齒輪

SG-90規格


  • 工作電壓:4.8V.
  • 轉矩:1.8kg-cm
  • 運轉速度:0.1秒∕ 60度
  • 轉動角度:最大90°
  • 脈衝寬度範圍:500~2400µs.








MG90S規格


  • 金屬銅齒、空心杯電機、雙滾珠軸承
  • 產品型號:MG90s.
  • 扭力:2.0kg(4.8v)
  • 運轉速度:0.11s(4.8v)
  • 轉動角度:最大90°/180°
  • 舵機類型:數字舵機







  1. 此次實驗以MG-90為主
  2. 要控制伺服馬達有兩種方式,一種是利用PWM,另一種是使用現有的庫包來控制,本次實驗以庫包為主

首先安裝

接線方式

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

進行實驗

  1. #include <ESP32Servo.h>
     
    Servo myservo;
     
    int pos = 20;
    const int pin = 12;
     
    void setup(){
      Serial.begin(115200);
      myservo.attach(pin, 500, 2400);
    }
     
    void loop(){
      for (pos=20; pos<=160; pos+=3){
        myservo.write(pos);
        delay(100);
      }
      for (pos=160; pos>=20; pos-=3){
        myservo.write(pos);
        delay(100);
      }
    }

ESP32網頁伺服器

上面伺服馬達簡單的測試完成後,就可以納入網頁伺服器來控制伺服馬達,這裡我覺得有點難度的是網頁的編寫,因為寫HTML+CSS我沒學過,所以參考網路上教學文的網頁範例。
這是我參考教學網站上的網頁範例
  1. <!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>

使用 script 和 /script 標籤將一些 JavaScript 代碼添加到您的 HTML 文件中。此代碼片段使用當前滑塊位置更新網頁

  1.  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;
        }

接下來的幾行在此特定 URL 路徑 /?value\u003d[SLIDER_POSITION]& 中的 ESP IP 地址上發出 HTTP GET 請求。

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

例如,當滑塊位於 0 時,您在以下 URL 上發出 HTTP GET 請求:

  1. http://192.168.1.135/?value=0&

完整程式碼

  1. #include <ESP32Servo.h>
    #include <WiFi.h>
     
    //定義伺服馬達
    Servo myservo;
     
    //伺服馬達的起始值和腳位
    int pos = 0;
    const int servoPin = 12;
     
    //WIFI
    const char *ssid = "---";
    const char *password = "------";
    //將 Web 服務器端口號設置為 80
    WiFiServer server(80);
     
    //用於存儲 HTTP 請求的變量
    String header;
     
    //解碼 HTTP GET 值
    String valueString = String(0);
    int pos1 = 0;
    int pos2 = 0;
     
    // 當下的時間
    unsigned long currentTime = millis();
    // 之前的時間
    unsigned long previousTime = 0; 
    // 超時
    const long timeoutTime = 2000;
     
    void setup(){
      Serial.begin(115200);
      //指定伺服器上的pin
      myservo.attach(servoPin, 500, 2400);
      //連接wifi
      WiFi.begin(ssid, password);
      while (WiFi.isConnected() == false){
        Serial.print(".");
        delay(1000);
      }
      Serial.println("Connected successful!");
      Serial.print("IP: ");
      Serial.print(WiFi.localIP());
      //連接伺服器
      server.begin();
    }
     
    void loop(){
      //監聽客戶端傳入的資料
      WiFiClient client = server.available();
      //如果有新客戶端連接進來,
      if (client){
        currentTime = millis();
        previousTime = currentTime;
        Serial.println("New Client.");     
        //製作一個字符串來保存來自客戶端的傳入數據
        String currentLine = "";
        while (client.connected() && (currentTime - previousTime <= 2000)){
          currentTime = millis();
          if (client.available()){ //如果有字節要從客戶端讀取,
            char c = client.read(); //讀取字節
            Serial.write(c); //印到序列監測窗口
            header += c;
            if (c == '\n'){ //如果字節是換行符 //如果當前行為空,則表示一行中有兩個換行符。
              //這是客戶端 HTTP 請求的結束,因此發送響應:
              if (currentLine.length() == 0){
                client.println("HTTP/1.1 200 OK");
                client.println("Content-type:text/html; charset=utf-8");
                client.println("Connection: close");
                client.println();
                //接下來就是顯示網頁
                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:,\">");
                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 控制伺服馬達練習</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);
                  
                  //轉換成整數後傳入伺服馬達令其動作
                  myservo.write(valueString.toInt());
                  delay(15);
                  Serial.println(valueString); 
                }         
                // The HTTP response ends with another blank line
                client.println();
                break;
              }else { //如果有一個換行符,就清除 currentLine
                currentLine = "";
              }
            }else if (c != '\r'){ //否則如果除了enter以外還有別的字串,把它加入currentLine末端
              currentLine += c; 
            }
          }
        }
        // 將header清空
        header = "";
        // 關閉連結
        client.stop();
        Serial.println("Client disconnected.");
        Serial.println("");
      }
    }








































留言

這個網誌中的熱門文章