在 Arduino筆記(15):控制伺服馬達 Servo 這篇實作中,使用可變電阻控制伺服馬達的轉動,購入 ESP8266 相關的NodeMCU或 ESP32都具備無線網路的功能。我想讓多個伺服馬達動作,讓機器手臂可以夾取物品,屆時可透過網頁控制手臂各關節。這一篇要來實作,透過操控網頁上的滑桿,操控一個伺服馬達在 0 ~ 180間轉動。您可將伺服軸定位在 0 到 180º 的各個角度。使用脈衝寬度調製(PWM)信號控制伺服系統。這意味著發送到電機的PWM信號將決定軸的位置。
實作時,使用類似 SG90 小型伺服馬達時,可以直接從 NodeMCU 供電,但如果使用像是 MG996R 或多個伺服馬達時,就需要接外部電源為伺服馬達供應電源。
在HTML創建一個滑桿(slider)時,可使用<input>標記,這個<input>標籤指定一個欄位可讓用戶輸入數值。有好幾種輸入類型來定義滑桿,可使用「type」屬性和「range」值。在滑桿中,另需指定「min」和「max」屬性來定義最小和最大範圍。
▸ 滑桿風格的 class
▸ 用於更新網頁上顯示的當前位置的ID
▸ 當滑塊移動時,onchange 屬性將調用伺服函數以向NodeMCU發送HTTP請求。
另外還需要將 JavaScript 添加到 HTML文件中,需要使用<script>和</ script >標記將 JavaScript 代碼添加到 HTML文件中,此段程式讓當前滑桿位置更新網頁:
以下是完成程式,上傳到 NodeMCU後就可以透過網頁控制伺服馬達。
實作時,使用類似 SG90 小型伺服馬達時,可以直接從 NodeMCU 供電,但如果使用像是 MG996R 或多個伺服馬達時,就需要接外部電源為伺服馬達供應電源。
[安裝ESP32-Arduino-Servo-Library Library]
本實作需要安裝以下程式庫:
程式庫(Library)安裝方法請參考另一篇文章: Arduino筆記:安裝 Arduino IDE 程式庫(Library)。
[材料]
- NodeMCU ESP-8266 x 1
- MG996R 伺服馬達 x 1
- 電壓轉換模組 x 1
- 18650 電池盒 x 1
- 18650 電池 x 2
- 連接線 x n
- 麵包板 x 1
[線路圖]
伺服馬達我使用型號是MG996R,因NodeMCU的電力無法推動馬達,改為外接5V電源提供。[程式]
NodeMCU 的 D7等同 GPIO 13,程式中指定控制 Pin 為 13。在HTML創建一個滑桿(slider)時,可使用<input>標記,這個<input>標籤指定一個欄位可讓用戶輸入數值。有好幾種輸入類型來定義滑桿,可使用「type」屬性和「range」值。在滑桿中,另需指定「min」和「max」屬性來定義最小和最大範圍。
<input type="range" min="0" max="180" class="slider" id="servoSlider" onchange="servo(this.value)"/>您還需要定義其他屬性,例如:
▸ 滑桿風格的 class
▸ 用於更新網頁上顯示的當前位置的ID
▸ 當滑塊移動時,onchange 屬性將調用伺服函數以向NodeMCU發送HTTP請求。
另外還需要將 JavaScript 添加到 HTML文件中,需要使用<script>和</ script >標記將 JavaScript 代碼添加到 HTML文件中,此段程式讓當前滑桿位置更新網頁:
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; }
以下是完成程式,上傳到 NodeMCU後就可以透過網頁控制伺服馬達。
#include <ESP8266WiFi.h> #include <Servo.h> Servo myservo; // 建立伺服馬達控制 // 伺服馬達的連接 GPIO static const int servoPin = 13; // 設定無線基地台SSID跟密碼 char ssid[] = "MyHome"; char password[] = "12345678"; // 設定 web server port number 80 WiFiServer server(80); // 儲存 HTTP request 的變數 String header; // Decode HTTP GET value String valueString = String(5); int pos1 = 0; int pos2 = 0; void setup() { myservo.attach(servoPin); // 將伺服馬達連接的GPIO pin連接伺服物件 Serial.begin(115200); // 使用SSID 跟 password 連線基地台 Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // 使用COM Port 列出取得的IP address Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); server.begin(); } void loop(){ WiFiClient client = server.available(); // 等待 clients 連線 if (client) { // 假使新的用戶端連線 Serial.println("New Client."); // 從序列 Port印出訊息內容 String currentLine = ""; // 清空這行的內容 while (client.connected()) { // 當 client連線持續執行迴圈 if (client.available()) { // 假使從 client 有讀到字元 char c = client.read(); // 讀取這個字元 Serial.write(c); // 印出這個字元在串列視窗 header += c; if (c == '\n') { // 假使是換行符號 // 假使目前的一行是空白且有兩個新行,就結束 client HTTP 的要求 if (currentLine.length() == 0) { // HTTP 表頭開始時,會有回應碼 response code (如: HTTP/1.1 200 OK) client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); // 顯示 HTML 網頁 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:,\">"); // 設定 on/off 按鈕的CSS 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>"); // 網頁表頭 client.println("</head><body><h1>ESP8266 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); // 旋轉伺服主機 myservo.write(valueString.toInt()); Serial.println(valueString); } // 使用空白行結束 HTTP回應 client.println(); break; } else { // 假使有新的一行, 清除目前這一行 currentLine = ""; } } else if (c != '\r') { // 讀取到的不是換行符號 currentLine += c; // 增加一個字元在本行最後 } } } // 清除表頭變數 header = ""; // 關閉連線 connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } }
[結果]
[參考資料]
- Randomnerdtutorials:ESP32 Servo Motor Web Server with Arduino IDE
你好 請問一下 我照你的接法接了以後 拉動BAR從0~180 但是馬達卻只轉了90度 是什麼原因
回覆刪除張貼留言