ESP8266 Điều khiển động cơ servo qua web

Các hướng dẫn chi tiết, mã nguồn, sơ đồ mạch, video hướng dẫn và lời giải thích mã theo từng dòng được cung cấp để giúp bạn nhanh chóng bắt đầu với ESP8266.

Tìm bài viết này và các bài hướng dẫn ESP8266 khác tại newbiely.com.

Hướng dẫn này chỉ cho bạn cách sử dụng ESP8266 để điều khiển động cơ servo qua web từ trình duyệt trên điện thoại thông minh hoặc máy tính của bạn. Chúng ta sẽ sử dụng một thứ được gọi là WebSocket để điều khiển động cơ servo một cách mượt mà và linh hoạt thông qua một giao diện người dùng web đồ họa.

ESP8266 NodeMCU điều khiển động cơ servo qua web

Vậy tại sao lại dùng WebSocket? Đây là ý tưởng:

Hãy bắt đầu!

Phần cứng cần chuẩn bị

1×ESP8266 NodeMCU ESP-12E
1×Recommended: ESP8266 NodeMCU ESP-12E (Uno-form)
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×động cơ servo
1×breadboard
1×dây jumper
1×(Tùy chọn) DC Power Jack
1×(Khuyến nghị) Screw Terminal Expansion Board for ESP8266
1×(Khuyến nghị) Power Splitter for ESP8266 Type-C

Or you can buy the following kits:

1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)

Giới thiệu về động cơ servo và WebSocket

Chúng tôi có các bài hướng dẫn riêng về động cơ servo và WebSocket. Mỗi bài hướng dẫn chứa thông tin chi tiết và các chỉ dẫn từng bước về sơ đồ chân phần cứng, nguyên lý hoạt động, kết nối dây với ESP8266, mã ESP8266... Tìm hiểu thêm về chúng tại các liên kết sau:

Cách hoạt động

Mã ESP8266 tạo ra cả máy chủ web và máy chủ WebSocket. Dưới đây là cách nó hoạt động:

  • Khi bạn nhập địa chỉ IP của ESP8266 vào trình duyệt web, nó yêu cầu trang web (Giao diện người dùng) từ ESP8266.
  • Máy chủ web của ESP8266 phản hồi bằng cách gửi nội dung của trang web (HTML, CSS, JavaScript).
  • Trình duyệt web của bạn sau đó hiển thị trang web.
  • Mã JavaScript trong trang web thiết lập một kết nối WebSocket tới máy chủ WebSocket trên ESP8266.
  • Khi kết nối WebSocket này được thiết lập, nếu bạn xoay cần điều khiển trên trang web, mã JavaScript sẽ âm thầm gửi giá trị góc tới ESP8266 thông qua kết nối WebSocket này ở chế độ nền.
  • Máy chủ WebSocket trên ESP8266 khi nhận được giá trị góc sẽ điều khiển động cơ servo tương ứng.

Tóm lại, kết nối WebSocket cho phép điều khiển mượt mà và theo thời gian thực góc quay của động cơ servo.

Sơ đồ đấu dây giữa động cơ servo và ESP8266

sơ đồ đấu dây động cơ servo ESP8266 NodeMCU

This image is created using Fritzing. Click to enlarge image

Xem thêm Sơ đồ chân ESP8266Cách cấp nguồn cho ESP8266.

Để đơn giản hóa, sơ đồ nối ở trên được sử dụng cho mục đích thử nghiệm hoặc học tập và dành cho động cơ servo có mô-men xoắn nhỏ. Trong thực tế, chúng tôi đặc biệt khuyến nghị sử dụng nguồn cấp ngoài cho động cơ servo. Sơ đồ nối bên dưới cho thấy cách kết nối động cơ servo với nguồn điện bên ngoài.

sơ đồ đấu dây nguồn cấp ngoài cho động cơ servo ESP8266 NodeMCU

This image is created using Fritzing. Click to enlarge image

Mã ESP8266

Nội dung của trang web (HTML, CSS, JavaScript) được lưu riêng trong một tệp index.h. Vì vậy, chúng ta sẽ có hai tệp mã nguồn trong Arduino IDE:

  • Một tệp .ino chứa mã ESP8266, tạo máy chủ web và máy chủ WebSocket, và điều khiển động cơ servo
  • Một tệp .h chứa nội dung của trang web.

Hướng dẫn từng bước

Để bắt đầu với ESP8266 trên Arduino IDE, hãy làm theo các bước sau:

  • Xem hướng dẫn ESP8266 - Cài đặt phần mềm nếu đây là lần đầu bạn sử dụng ESP8266.
  • Nối các linh kiện như được mô tả trong sơ đồ.
  • Kết nối bảng ESP8266 với máy tính của bạn bằng cáp USB.
  • Mở Arduino IDE trên máy tính của bạn.
  • Chọn bo mạch ESP8266 phù hợp, ví dụ: NodeMCU 1.0 (ESP-12E Module), và cổng COM tương ứng của nó.
  • Nhấp vào biểu tượng Trình quản lý thư viện ở thanh điều hướng bên trái của Arduino IDE.
  • Tìm kiếm “WebSockets”, rồi tìm thư viện WebSockets được tạo bởi Markus Sattler.
  • Nhấn nút Cài đặt để cài đặt thư viện WebSockets.
thư viện websockets cho ESP8266 NodeMCU
  • Trên Arduino IDE, tạo một sketch mới, đặt cho nó một tên, ví dụ, newbiely.com.ino
  • Sao chép đoạn mã bên dưới và mở bằng Arduino IDE
/* * Mã ESP8266 NodeMCU này được phát triển bởi newbiely.vn * Mã ESP8266 NodeMCU này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/esp8266/esp8266-controls-servo-motor-via-web */ #include <Servo.h> #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include "index.h" #define SERVO_PIN D7 // The ESP8266 pin D7 connected to servo motor Servo servo; const char* ssid = "YOUR_WIFI_SSID"; // CHANGE IT const char* password = "YOUR_WIFI_PASSWORD"; // CHANGE IT ESP8266WebServer server(80); // Web server on port 80 DIYables_ESP32_WebSocket* webSocket; void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) { switch (type) { case WStype_DISCONNECTED: Serial.printf("[%u] Disconnected!\n", num); break; case WStype_CONNECTED: { IPAddress ip = webSocket.remoteIP(num); Serial.printf("[%u] Connected from %d.%d.%d.%d\n", num, ip[0], ip[1], ip[2], ip[3]); } break; case WStype_TEXT: //Serial.printf("[%u] Received text: %s\n", num, payload); String angle = String((char*)payload); int angle_value = angle.toInt(); Serial.println(angle_value); servo.write(angle_value); break; } } void setup() { Serial.begin(9600); servo.attach(SERVO_PIN); // attaches the servo on ESP8266 pin // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); // Initialize WebSocket server webSocket.begin(); webSocket.onEvent(webSocketEvent); // Serve a basic HTML page with JavaScript to create the WebSocket connection server.on("/", HTTP_GET, []() { Serial.println("Web Server: received a web page request"); String html = HTML_CONTENT; // Use the HTML content from the index.h file server.send(200, "text/html", html); }); server.begin(); Serial.print("ESP8266 Web Server's IP address: "); Serial.println(WiFi.localIP()); } void loop() { // Handle client requests server.handleClient(); // Handle WebSocket events webSocket.loop(); }
  • Tạo tệp index.h trên Arduino IDE bằng cách:
    • Hoặc nhấp vào nút ngay bên dưới biểu tượng Serial Monitor và chọn Tab Mới, hoặc dùng phím Ctrl+Shift+N.
    Arduino ide 2 thêm tệp tin
    • Đặt tên cho tệp tin index.h và nhấn nút OK
    Arduino ide 2 thêm tệp index.h
    • Sao chép đoạn mã dưới đây và dán vào tập tin index.h.
    /* * Mã ESP8266 NodeMCU này được phát triển bởi newbiely.vn * Mã ESP8266 NodeMCU này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/esp8266/esp8266-controls-servo-motor-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>ESP8266 Controls Servo Motor via Web</title> <meta name="viewport" content="width=device-width, initial-scale=0.7"> <style> body { text-align: center; } canvas { background-color: #ffffff; } </style> <script> var canvas_width = 401, canvas_height = 466; var pivot_x = 200, pivot_y = 200; var bracket_radius = 160, bracket_angle = 0; var bracket_img = new Image(); var click_state = 0; var last_angle = 0; var mouse_xyra = {x:0, y:0, r:0.0, a:0.0}; var ws; bracket_img.src = "https://esp32io.com/images/tutorial/servo-bracket.png"; function init() { var servo = document.getElementById("servo"); servo.width = canvas_width; servo.height = canvas_height; servo.style.backgroundImage = "url('https://esp32io.com/images/tutorial/servo-body.png')"; servo.style.backgroundPosition = "center"; servo.style.backgroundSize = "contain"; servo.addEventListener("touchstart", mouse_down); servo.addEventListener("touchend", mouse_up); servo.addEventListener("touchmove", mouse_move); servo.addEventListener("mousedown", mouse_down); servo.addEventListener("mouseup", mouse_up); servo.addEventListener("mousemove", mouse_move); var ctx = servo.getContext("2d"); ctx.translate(pivot_x, pivot_y); rotate_bracket(0); ws = new WebSocket("ws://" + window.location.host + ":81"); document.getElementById("ws_state").innerHTML = "CONNECTING"; ws.onopen = function(){ document.getElementById("ws_state").innerHTML = "CONNECTED" }; ws.onclose = function(){ document.getElementById("ws_state").innerHTML = "CLOSED"}; ws.onerror = function(){ alert("websocket error " + this.url) }; ws.onmessage = ws_onmessage; } function ws_onmessage(e_msg) { e_msg = e_msg || window.event; // MessageEvent alert("msg : " + e_msg.data); } function rotate_bracket(angle) { var servo = document.getElementById("servo"); var ctx = servo.getContext("2d"); ctx.clearRect(-pivot_x, -pivot_y, canvas_width, canvas_height); ctx.rotate(angle / 180 * Math.PI); ctx.drawImage(bracket_img, -pivot_x, -pivot_y); ctx.rotate(-angle / 180 * Math.PI); } function check_range_xyra(event, mouse_xyra) { var x, y, r, a, rc_x, rc_y, radian; var min_r, max_r, width; if(event.touches) { var touches = event.touches; x = (touches[0].pageX - touches[0].target.offsetLeft) - pivot_x; y = pivot_y - (touches[0].pageY - touches[0].target.offsetTop); min_r = 60; max_r = pivot_x; width = 40; } else { x = event.offsetX - pivot_x; y = pivot_y - event.offsetY; min_r = 60; max_r = bracket_radius; width = 20; } /* cartesian to polar coordinate conversion */ r = Math.sqrt(x * x + y * y); a = Math.atan2(y, x); mouse_xyra.x = x; mouse_xyra.y = y; mouse_xyra.r = r; mouse_xyra.a = a; radian = bracket_angle / 180 * Math.PI; /* rotate coordinate */ rc_x = x * Math.cos(radian) - y * Math.sin(radian); rc_y = x * Math.sin(radian) + y * Math.cos(radian); if((r < min_r) || (r > max_r)) return false; if((rc_y < -width) || (rc_y > width)) return false; return true; } function mouse_down() { if(event.touches && (event.touches.length > 1)) click_state = event.touches.length; if(click_state > 1) return; if(check_range_xyra(event, mouse_xyra)) { click_state = 1; last_angle = mouse_xyra.a / Math.PI * 180.0; } } function mouse_up() { click_state = 0; } function mouse_move() { var angle; if(event.touches && (event.touches.length > 1)) click_state = event.touches.length; if(click_state > 1) return; if(!click_state) return; if(!check_range_xyra(event, mouse_xyra)) { click_state = 0; return; } angle = mouse_xyra.a / Math.PI * 180.0; if((Math.abs(angle) > 90) && (angle * last_angle < 0)) { if(last_angle > 0) last_angle = -180; else last_angle = 180; } bracket_angle += (last_angle - angle); last_angle = angle; if(bracket_angle > 90) bracket_angle = 90; if(bracket_angle < -90) bracket_angle = -90; rotate_bracket(bracket_angle); if(ws.readyState == 1) ws.send(Math.floor(90 - bracket_angle) + "\r\n"); debug = document.getElementById("debug"); debug.innerHTML = Math.floor(90 - bracket_angle); event.preventDefault(); } window.onload = init; </script> </head> <body> <h2> ESP8266 - Servo Motor via Web<br> <canvas id="servo"></canvas> <p> WebSocket : <span id="ws_state" style="color:blue">null</span><br> Angle : <span id="debug" style="color:blue">90</span> </p> </h2> <div class="sponsor">Sponsored by <a href="https://amazon.com/diyables">DIYables</a></div> </body> </html> )=====";
    • Bây giờ bạn có mã trong hai tệp: newbiely.com.ino và index.h
    • Nhấn nút Tải lên trên Arduino IDE để tải mã lên ESP8266
    • Mở Serial Monitor
    • Xem kết quả trên Serial Monitor.
    COM6
    Send
    Connecting to WiFi... Connected to WiFi ESP8266 Web Server's IP address IP address: 192.168.0.5
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Ghi nhận địa chỉ IP được hiển thị và nhập địa chỉ này vào thanh địa chỉ của trình duyệt web trên điện thoại thông minh hoặc máy tính cá nhân của bạn.
    • Bạn sẽ thấy trang web như dưới đây:
    ESP8266 NodeMCU điều khiển động cơ servo qua trình duyệt web
    • Mã JavaScript của trang web tự động thiết lập kết nối WebSocket với ESP8266.
    • Bây giờ bạn có thể điều khiển góc của động cơ servo thông qua giao diện web.

    Để tiết kiệm bộ nhớ cho ESP8266, hình ảnh của động cơ servo không được lưu trữ trên ESP8266. Thay vào đó, chúng được lưu trên Internet, nên điện thoại hoặc máy tính của bạn cần có kết nối Internet để tải hình ảnh cho trang điều khiển trên web.

    ※ Lưu ý:

    • Nếu bạn chỉnh sửa nội dung HTML trong index.h và không chạm vào bất cứ thứ gì trong newbiely.com.ino file, khi bạn biên dịch và tải mã lên ESP8266, Arduino IDE sẽ không cập nhật nội dung HTML.
    • Để Arduino IDE cập nhật nội dung HTML trong trường hợp này, hãy thực hiện một thay đổi trong newbiely.com.ino file (ví dụ: thêm một dòng trống, thêm một chú thích....)

    Giải thích mã nguồn theo từng dòng

    Đoạn mã ESP8266 ở trên chứa lời giải thích theo từng dòng. Vui lòng đọc các chú thích trong mã.