ESP32 Servo: Điều khiển qua Internet bằng Web Server
Trong bài hướng dẫn này, mình sẽ hướng dẫn bạn làm việc với ESP32 Servo nhé! Cụ thể, chúng ta sẽ tạo một Web Server có thể điều khiển Servo bằng thanh trượt (slider).
Để dễ hơn cho bạn thì đầu tiên IoTZone sẽ giới thiệu nhanh về cách điều khiển Servo qua ESP 32, rồi chúng ta mới đi xây dựng Web Server.
Chuẩn bị phần cứng
- Mạch ESP32 (mình dùng loại ESP32 DOIT DEVKIT V1 Board)
- Động cơ Servo (mình dùng loại Micro Servo S0009 hoăc Servo S0003)
- Dây cắm Jumper
Kết nối
Servo có 3 dây cắm khác nhau: dây nguồn (power), dây nối đất (ground) và dây tín hiệu (signal). Mỗi dây có mỗi màu như hình:
Đôi khi, dây tín hiệu có thể là màu trắng hoặc màu vàng, màu cam. Nếu bạn dùng Servo S0009 như của mình, bạn có thể nối Servo trực tiếp vào mạch ESP32 nhé!
Còn trong trường hợp sử dụng Servo loại khác, đôi khi bạn sẽ cần thêm nguồn cấp điện bên ngoài, tùy vào loại Servo bạn dùng.
Thứ tự kết nối dây Servo đến mạch ESP32 như sau:
- Dây GND của Servo -> Cổng GND của ESP32
- Dây nguồn của Servo -> Cổng VIN của ESP32
- Dây tín hiệu của Servo -> GPIO 13 (hoặc bất kỳ cổng xuất PWM nào khác)
Lưu ý: Bạn có thể sử dụng bất kỳ cổng GPIO nào trên mạch ESP 32 trong trường hợp này, vì GPIO đa phần đều hỗ trợ xuất tín hiệu PWM. Tuy nhiên, IoTZone không khuyến khích bạn sử dụng cổng GPIO 9, 10 và 11; vì các cổng này thông thường đều đã được kết nối tới đèn Flash SPI tích hợp sẵn trên mạch.
Hướng dẫn cách điều khiển Servo
Các loại Servo thông thường sẽ hỗ trợ quay từ 0º đến 180º, và chúng được điều khiển bằng tín hiệu PWM. Nhờ vào đó, chúng có thể quay tới một góc chính xác.
Để điều khiển Servo, chúng ta chỉ cần lập trình ESP32 gửi xung tín hiệu 50Hz với độ rộng phù hợp. Bây giờ đã có khá nhiều thư viện trong ESP32 hỗ trợ việc này. Cùng xem qua hướng dẫn điều khiển Servo bên dưới nhé!
Nạp chương trình bằng Arduino IDE
Chuẩn bị
Nếu Arduino IDE của bạn chưa hỗ trợ mạch ESP32, bạn hãy cài tiện ích ESP32 trong phần mềm theo hướng dẫn sau nhé: Cách lập trình ESP32 bằng Arduino IDE (Windows, Linux, Mac OS X)
Cài thư viện ESP32_Arduino_Servo_LIbrary
Như mình đã giới thiệu phía trên, đây là thư viện giúp chúng ta dễ dàng điều khiển Servo hơn. Bạn hãy cài thư viện theo hướng dẫn bên dưới:
- Tải thư viện qua đường link sau: ESP32_Arduino_Servo_Library
- Giải nén thư mục vừa tải về
- Đổi tên thư mục thành ESP32_Arduino_Servo_Library
- Di chuyển thư mục vào folder thư viện của Arduino IDE
- Tắt và mở lại Arduino IDE
Link chương trình full
Trong thư viện đã có sẵn đoạn chương trình điều khiển Servo, bạn hãy nhấn vào File >> Examples >> ServoESP32 >> Simple Servo nhé:
#include <Servo.h> Servo myservo; // create servo object to control a servo // twelve servo objects can be created on most boards int pos = 0; // variable to store the servo position void setup() { myservo.attach(13); // attaches the servo on pin 13 to the servo object } void loop() { 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 } } 1
Chương trình trên giúp cho Servo quay sang góc 0 độ rồi quay tới góc 180 độ, lặp lại liên tục.
Vậy là đã xong, giờ IoTZone sẽ hướng dẫn bạn cách xây dựng Web Server nhé!
Giới thiệu về Web Server ESP32
Để điều khiển ESP32 Servo, chúng ta sẽ làm một Web Server như sau:
- Có 1 thanh trượt từ 0 đến 180 để điều chỉnh góc quay Servo
- Giá trị thanh trượt này sẽ tự động cập nhật liên tục mà không cần người dùng F5 lại trang Web
- Việc F5 trang Web không làm thay đổi giá trị góc trên thanh trượt đang có
Cách tạo Web Server điều khiển ESP32 Servo
Tạo trang HTML
<!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> 1
Tạo thanh trượt
Để tạo thanh trượt trong Web HTML, chúng ta sử dụng thẻ <input>, đây là thẻ cho phép người dùng thay đổi giá trị dữ liệu.
Mình sẽ sử dụng thuộc tính type và range để cấu hình tạo một thanh trượt. Ngoài ra, chúng ta cũng cần dùng min (0) và max (180) để xác định góc quay tối đa cho ESP32 Servo:
<input type="range" min="0" max="180" class="slider" id="servoSlider" onchange="servo(this.value)"/>
Ngoài ra thì cũng có một số thuộc tính phụ như:
- class điều khiển thanh trưọt
- id xác định vị trí hiển thị của thanh trượt trên Web Server hiện tại
- onchange gọi hàm Servo để gửi yêu cầu HTTP đến mạch ESP32 mỗi khi người dùng thay đổi giá trị của thanh trượt
Thêm JavaScript
Bước tiếp theo là chúng ta cần dùng code Javascript để cập nhật vị trí mới nhất của Slider:
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; }
Gửi yêu cầu HTTP GET trên địa chỉ IP ESP, theo một URL cụ thể:
$.ajaxSetup({timeout:1000}); function servo(pos) { $.get("/?value=" + pos + "&"); }
Ví dụ, khi slider ở vị trí 0, bạn sẽ nhận được yêu cầu HTTP GET qua URL như sau:
http://192.168.1.135/?value=0&
Tương tự với 180 độ. Mỗi khi ESP32 nhận được yêu cầu này, chúng sẽ điều khiển Servo đến đúng giá trị như trong URL đã hướng dẫn.
Chương trình lập trình cho ESP32 Servo
Bây giờ, chúng ta cần tích hợp Web HTML đã tạo vào chương trình điều khiển ESP32 Servo, để các thiết bị phần cứng này hoạt động sao cho phù hợp.
Dưới đây là code mẫu full:
/********* Rui Santos Complete project details at http://randomnerdtutorials.com *********/ #include <WiFi.h> #include <Servo.h> Servo myservo; // create servo object to control a servo // twelve servo objects can be created on most boards // GPIO the servo is attached to static const int servoPin = 13; // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Set web server port number to 80 WiFiServer server(80); // Variable to store the HTTP request String header; // Decode HTTP GET value String valueString = String(5); int pos1 = 0; int pos2 = 0; // Current time unsigned long currentTime = millis(); // Previous time unsigned long previousTime = 0; // Define timeout time in milliseconds (example: 2000ms = 2s) const long timeoutTime = 2000; void setup() { Serial.begin(115200); myservo.attach(servoPin); // attaches the servo on the servoPin to the servo object // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Print local IP address and start web server Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); server.begin(); } void loop(){ WiFiClient client = server.available(); // Listen for incoming clients if (client) { // If a new client connects, currentTime = millis(); previousTime = currentTime; Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor header += c; if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); // Display the HTML web page 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:,\">"); // CSS to style the on/off buttons // Feel free to change the background-color and font-size attributes to fit your preferences 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 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); //Rotate the servo myservo.write(valueString.toInt()); Serial.println(valueString); } // The HTTP response ends with another blank line client.println(); // Break out of the while loop break; } else { // if you got a newline, then clear currentLine currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } } } // Clear the header variable header = ""; // Close the connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } } 1
Giải thích chương trình
Khai báo thư viện và tạo đối tượng là myservo:
#include <Servo.h> Servo myservo; // create servo object to control a servo
Tạo biến để khai báo cổng mà Servo đang kết nối (GPIO 13):
const int servoPin = 13;
Sửa đổi thông tin đăng nhập vào mạng WiFi của bạn sao cho phù hợp:
// Replace with your network credentials const char* ssid = ""; const char* password = "";
Tạo biến để theo dõi vị trí của thanh trượt, dựa trên yêu cầu HTTP
// Decode HTTP GET value String valueString = String(5); int pos1 = 0; int pos2 = 0;
Setting()
Gắn Servo vào chân GPIO tương ứng:
myservo.attach(servoPin); // attaches the servo on the servoPin to the servo object
loop()
Tạo Web Server và gửi HTML để trang Web có thể hiển thị. Sau đó, lấy giá trị của thanh trượt:
//GET /?value=180& HTTP/1.1 if(tiêu đề.indexOf("GET /?value=")>=0) { pos1 = tiêu đề.indexOf('= 39;); pos2 = tiêu đề.indexOf('&'); valueString = tiêu đề.chuỗi con(pos1+1, pos2);
Khi thanh trượt thay đổi, yêu cầu HTTP được gửi qua URL:
http://your-esp-ip-address/?value=[SLIDER_POSITION]&
Giá trị thanh trượt được lưu trong biến valueString.
Điều khiển ESP32 Servo đến vị trí cụ thể:
myservo.write(valueString.toInt());
Nạp chương trình và xem demo
Bây giờ, bạn hãy upload code vào mạch ESP32 của mình nhé! Sau đó bật Serial Monitor ở tốc độ 115200 để theo dõi.
Bước tiếp theo bạn hãy khởi động lại ESP32 và lấy địa chỉ IP trên Serial Monitor. Dán IP này vào trình duyệt trên điện thoại, bạn sẽ thấy Web Server đã tạo:
Bạn hãy thử kéo thanh trượt qua lại và xem phản ứng của Servo nhé!
Chúng ta cũng có thể theo dõi yêu cầu HTTP được gửi đi như thế nào khi di chuyển thanh trượt.
Lời kết
Trong hướng dẫn này, mình đã giới thiệu cách điều khiển ESP32 Servo thông qua Web Server, dựa trên mạng Internet. Đây chỉ là một hướng dẫn cơ bản, bạn có thể sáng tạo và biến tấu nâng cao hơn tùy thích, ví dụ như sử dụng khung nhập văn bản thay vì thanh trượt. Chúc các bạn thành công.