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°
- 舵機類型:數字舵機
- 此次實驗以MG-90為主
- 要控制伺服馬達有兩種方式,一種是利用PWM,另一種是使用現有的庫包來控制,本次實驗以庫包為主
首先安裝
接線方式
進行實驗
#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我沒學過,所以參考網路上教學文的網頁範例。
這是我參考教學網站上的網頁範例
<!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 文件中。此代碼片段使用當前滑塊位置更新網頁
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 請求。
$.ajaxSetup({timeout:1000});
function servo(pos) {
$.get("/?value=" + pos + "&");
{Connection: close};
}
例如,當滑塊位於 0 時,您在以下 URL 上發出 HTTP GET 請求:
http://192.168.1.135/?value=0&
完整程式碼
#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("");
}
}