Hướng dẫn điều khiển Servo Motor với ESP32 qua Web Server (Arduino IDE)

Bài hướng dẫn này giúp bạn xây dựng một web server bằng ESP32 để điều khiển góc quay của động cơ servo thông qua thanh trượt (slider) trên trình duyệt. Trang web cập nhật vị trí slider theo thời gian thực bằng AJAX mà không cần reload.
Linh kiện cần chuẩn bị
- 📦 Board ESP32 DOIT DEVKIT V1 (hoặc tương đương)
- 📦 Động cơ servo Micro SG90 / S0009 hoặc MG996R
- 📦 Dây jumper

Sơ đồ kết nối

| Màu dây servo | Kết nối ESP32 |
|---|---|
| 🔴 Đỏ (VCC) | VIN (5V) |
| ⚫ Đen / Nâu (GND) | GND |
| 🟡 Vàng / Cam (Signal) | GPIO 13 |
Servo hoạt động như thế nào?

Servo được điều khiển bằng tín hiệu PWM 50Hz. Độ rộng xung (duty cycle) quyết định góc quay của trục servo — từ 0° đến 180°. Thư viện ESP32Servo tự động tạo tín hiệu PWM phù hợp.
Cài thư viện ESP32Servo

- Mở Arduino IDE → Sketch → Include Library → Manage Libraries…
- Tìm kiếm
ESP32Servo - Nhấn Install
Code test servo (quét 0–180°)
Trước khi làm web server, hãy test servo quét từ 0° đến 180° và ngược lại:

/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp32-servo-motor-web-server-arduino-ide/
*********/
#include <ESP32Servo.h>
static const int servoPin = 13;
Servo servo1;
void setup() {
Serial.begin(115200);
servo1.attach(servoPin);
}
void loop() {
for(int pos = 0; pos <= 180; pos++) {
servo1.write(pos);
Serial.println(pos);
delay(20);
}
for(int pos = 180; pos >= 0; pos--) {
servo1.write(pos);
Serial.println(pos);
delay(20);
}
}
Xây dựng Web Server điều khiển servo

Web server sẽ hiển thị một thanh trượt từ 0 đến 180°. Khi bạn kéo slider, góc servo thay đổi ngay lập tức thông qua AJAX — không cần refresh trang.
Code đầy đủ
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp32-servo-motor-web-server-arduino-ide/
*********/
#include <WiFi.h>
#include <ESP32Servo.h>
Servo myservo;
static const int servoPin = 13;
const char* ssid = "TEN_WIFI_CUA_BAN";
const char* password = "MAT_KHAU_WIFI";
WiFiServer server(80);
String header;
String valueString = String(90);
int pos1 = 0;
int pos2 = 0;
unsigned long currentTime = millis();
unsigned long previousTime = 0;
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
myservo.attach(servoPin);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("
WiFi connected. IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
currentTime = millis();
previousTime = currentTime;
String currentLine = "";
while (client.connected() && currentTime - previousTime <= timeoutTime) {
currentTime = millis();
if (client.available()) {
char c = client.read();
header += c;
if (c == '
') {
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
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("<style>body{text-align:center;font-family:Arial;} .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>");
client.println("<h1>ESP32 + Servo</h1>");
client.println("<p>Góc hiện tại: <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');");
client.println("servoP.innerHTML=slider.value;");
client.println("slider.oninput=function(){servoP.innerHTML=this.value;}");
client.println("$.ajaxSetup({timeout:1000});");
client.println("function servo(pos){$.get('/?value='+pos+'&');}");
client.println("</script></body></html>");
client.println();
if (header.indexOf("GET /?value=") >= 0) {
pos1 = header.indexOf('=');
pos2 = header.indexOf('&');
valueString = header.substring(pos1+1, pos2);
myservo.write(valueString.toInt());
}
break;
} else { currentLine = ""; }
} else if (c != '
') { currentLine += c; }
}
}
header = "";
client.stop();
}
}
Cách sử dụng

- Thay
TEN_WIFI_CUA_BANvàMAT_KHAU_WIFIbằng thông tin WiFi của bạn - Nạp code lên ESP32
- Mở Serial Monitor (115200 baud) → xem địa chỉ IP
- Mở trình duyệt, nhập địa chỉ IP (ví dụ:
http://192.168.1.100) - Kéo thanh trượt để điều khiển góc servo từ 0° đến 180°

Kết quả Serial Monitor

Mỗi khi kéo slider, Serial Monitor sẽ in ra giá trị góc tương ứng.
Xem thêm
- 🔗 Hướng dẫn PWM với ESP32 và Arduino IDE
- 🔗 Tham khảo sơ đồ chân ESP32 — Nên dùng GPIO nào?
- 🔗 Hướng dẫn làm xe robot ESP32 điều khiển qua Wi-Fi
📖 Nguồn: Random Nerd Tutorials – ESP32 Servo Motor Web Server with Arduino IDE