ESP8266 Điều khiển Xe qua Web

Tutorial này hướng dẫn bạn cách sử dụng ESP8266 để điều khiển xe robot từ xa bằng trình duyệt web trên điện thoại thông minh hoặc máy tính của bạn thông qua WiFi. Việc điều khiển được thực hiện thông qua một giao diện người dùng web đồ họa, được gọi là WebSocket, cho phép điều khiển xe một cách mượt mà và linh hoạt.

ESP8266 NodeMCU điều khiển xe robot thông qua web

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×2WD RC Car
1×L298N Motor Driver Module
1×IR Remote Controller Kit
1×CR2025 Battery (for IR Remote controller)
1×1.5V AA Battery (for ESP8266 and Car)
1×dây jumper
1×breadboard
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ề Ô tô điều khiển từ xa 2 bánh dẫn động và WebSocket

Vậy tại sao lại chọn WebSocket? Đây là những thông tin chi tiết.

  • Không có WebSocket, việc thay đổi hướng của xe sẽ yêu cầu tải lại trang mỗi lần. Không tối ưu!
  • Tuy nhiên, với WebSocket, chúng ta thiết lập một kết nối đặc biệt giữa trang web và ESP8266. Điều này cho phép gửi lệnh tới ESP8266 ở chế độ nền, mà không cần tải lại trang. Kết quả? Xe robot di chuyển mượt mà và theo thời gian thực. Thật tuyệt phải không?

Tóm lại, kết nối WebSocket cho phép điều khiển robot một cách mượt mà và thời gian thực.

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

Cách thức hoạt động

Mã ESP8266 tạo cả một máy chủ web và một 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ó sẽ yêu cầu trang web (Giao diện người dùng) từ ESP8266.
  • Máy chủ web của ESP8266 trả về 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 bên trong trang web thiết lập kết nối WebSocket tới máy chủ WebSocket trên ESP8266.
  • Ngay khi kết nối WebSocket này được thiết lập, nếu bạn nhấn/thả các nút trên trang web, mã JavaScript sẽ âm thầm gửi các lệnh 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 các lệnh, sẽ điều khiển xe robot theo các lệnh đó.

Bảng dưới đây cho thấy danh sách các lệnh mà trang web gửi đến ESP8266 dựa trên hành động của người dùng:

User's Action Button Command Car Action
PRESS UP 1 MOVE FORWARD
PRESS DOWN 2 MOVE BACKWARD
PRESS LEFT 4 TURN LEFT
PRESS RIGHT 8 TURN RIGHT
PRESS STOP 0 STOP
RELEASE UP 0 STOP
RELEASE DOWN 0 STOP
RELEASE LEFT 0 STOP
RELEASE RIGHT 0 STOP
RELEASE STOP 0 STOP

Sơ đồ nối dây giữa xe RC 2WD và ESP8266

sơ đồ đấu nối ESP8266 NodeMCU cho xe rc dẫn động hai bánh

This image is created using Fritzing. Click to enlarge image

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

Thông thường, bạn cần hai nguồn cấp điện:

  • Một cái dành cho động cơ thông qua module L298N.
  • Một cái khác cho bảng ESP8266, module L298N (bộ điều khiển động cơ).

Nhưng bạn có thể đơn giản hóa mọi thứ bằng chỉ một nguồn cấp điện duy nhất cho mọi thứ – bốn pin 1,5V (tổng cộng 6V). Đây là cách làm:

  • Kết nối nguồn pin cho module L298N như hình.
  • Đặt hai jumper từ các chân ENA và ENB tới nguồn 5V trên module L298N.
  • Gỡ một jumper có nhãn 5VEN (vòng màu vàng trên sơ đồ).
  • Thực hiện phần dây còn lại theo sơ đồ ở trên.

Vì xe RC hai bánh dẫn động có công tắc bật/tắt, bạn có thể tùy ý kết nối pin qua công tắc để bật/tắt nguồn cho xe. Nếu bạn muốn đơn giản hóa, hãy bỏ qua công tắc.

Mã nguồn 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ã trên Arduino IDE:

  • Một tệp .ino chứa mã ESP8266, tạo ra máy chủ web và máy chủ WebSocket, và điều khiển xe ô tô.
  • 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:

  • Hãy tham khảo bài 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 thành phần như được trình bày trong sơ đồ.
  • Kết nối bo mạch 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.
  • Mở Library Manager bằng cách nhấp vào biểu tượng Library Manager ở thanh điều hướng bên trái của Arduino IDE.
  • Tìm “WebSockets”, sau đó tìm WebSockets do Markus Sattler phát triển.
  • Nhấp nút Install để 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 cái tên, ví dụ, newbiely.com.ino
  • Sao chép mã dưới đây 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-car-via-web */ #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include "index.h" #define CMD_STOP 0 #define CMD_FORWARD 1 #define CMD_BACKWARD 2 #define CMD_LEFT 4 #define CMD_RIGHT 8 #define IN1_PIN D2 // The ESP8266 pin connected to the IN1 pin L298N #define IN2_PIN D5 // The ESP8266 pin connected to the IN2 pin L298N #define IN3_PIN D6 // The ESP8266 pin connected to the IN3 pin L298N #define IN4_PIN D7 // The ESP8266 pin connected to the IN4 pin L298N 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 command = angle.toInt(); Serial.print("command: "); Serial.println(command); switch (command) { case CMD_STOP: Serial.println("Stop"); CAR_stop(); break; case CMD_FORWARD: Serial.println("Move Forward"); CAR_moveForward(); break; case CMD_BACKWARD: Serial.println("Move Backward"); CAR_moveBackward(); break; case CMD_LEFT: Serial.println("Turn Left"); CAR_turnLeft(); break; case CMD_RIGHT: Serial.println("Turn Right"); CAR_turnRight(); break; default: Serial.println("Unknown command"); } break; } } void setup() { Serial.begin(9600); pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); pinMode(IN3_PIN, OUTPUT); pinMode(IN4_PIN, OUTPUT); // 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 servo_html.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(); // TO DO: Your code here } void CAR_moveForward() { digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); digitalWrite(IN3_PIN, HIGH); digitalWrite(IN4_PIN, LOW); } void CAR_moveBackward() { digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, HIGH); digitalWrite(IN3_PIN, LOW); digitalWrite(IN4_PIN, HIGH); } void CAR_turnLeft() { digitalWrite(IN1_PIN, HIGH); digitalWrite(IN2_PIN, LOW); digitalWrite(IN3_PIN, LOW); digitalWrite(IN4_PIN, LOW); } void CAR_turnRight() { digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, LOW); digitalWrite(IN3_PIN, HIGH); digitalWrite(IN4_PIN, LOW); } void CAR_stop() { digitalWrite(IN1_PIN, LOW); digitalWrite(IN2_PIN, LOW); digitalWrite(IN3_PIN, LOW); digitalWrite(IN4_PIN, LOW); }
  • Tạo tập tin index.h trên Arduino IDE bằng cách:
    • Hoặc nhấp vào nút ngay 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.
    • Hãy đặt tên cho file 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 nó vào 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-car-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>ESP8266 Control Car via Web</title> <meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=1, user-scalable=no"> <style type="text/css"> body { text-align: center; font-size: 24px;} button { text-align: center; font-size: 24px;} #container { margin-right: auto; margin-left: auto; width: 400px; height: 400px; position: relative; margin-bottom: 10px; } div[class^='button'] { position: absolute; } .button_up, .button_down { width:214px; height:104px;} .button_left, .button_right { width:104px; height:214px;} .button_stop { width:178px; height:178px;} .button_up { background: url('https://newbiely.com/images/tutorial/up_inactive.png') no-repeat; background-size: contain; left: 200px; top: 0px; transform: translateX(-50%); } .button_down { background: url('https://newbiely.com/images/tutorial/down_inactive.png') no-repeat; background-size: contain; left:200px; bottom: 0px; transform: translateX(-50%); } .button_right { background: url('https://newbiely.com/images/tutorial/right_inactive.png') no-repeat; background-size: contain; right: 0px; top: 200px; transform: translateY(-50%); } .button_left { background: url('https://newbiely.com/images/tutorial/left_inactive.png') no-repeat; background-size: contain; left:0px; top: 200px; transform: translateY(-50%); } .button_stop { background: url('https://newbiely.com/images/tutorial/stop_inactive.png') no-repeat; background-size: contain; left:200px; top: 200px; transform: translate(-50%, -50%); } </style> <script> var CMD_STOP = 0; var CMD_FORWARD = 1; var CMD_BACKWARD = 2; var CMD_LEFT = 4; var CMD_RIGHT = 8; var img_name_lookup = { [CMD_STOP]: "stop", [CMD_FORWARD]: "up", [CMD_BACKWARD]: "down", [CMD_LEFT]: "left", [CMD_RIGHT]: "right" } var ws = null; function init() { var container = document.querySelector("#container"); container.addEventListener("touchstart", mouse_down); container.addEventListener("touchend", mouse_up); container.addEventListener("touchcancel", mouse_up); container.addEventListener("mousedown", mouse_down); container.addEventListener("mouseup", mouse_up); container.addEventListener("mouseout", mouse_up); } function ws_onmessage(e_msg) { e_msg = e_msg || window.event; // MessageEvent //alert("msg : " + e_msg.data); } function ws_onopen() { document.getElementById("ws_state").innerHTML = "OPEN"; document.getElementById("wc_conn").innerHTML = "Disconnect"; } function ws_onclose() { document.getElementById("ws_state").innerHTML = "CLOSED"; document.getElementById("wc_conn").innerHTML = "Connect"; console.log("socket was closed"); ws.onopen = null; ws.onclose = null; ws.onmessage = null; ws = null; } function wc_onclick() { if(ws == null) { ws = new WebSocket("ws://" + window.location.host + ":81"); document.getElementById("ws_state").innerHTML = "CONNECTING"; ws.onopen = ws_onopen; ws.onclose = ws_onclose; ws.onmessage = ws_onmessage; } else ws.close(); } function mouse_down(event) { if (event.target !== event.currentTarget) { var id = event.target.id; send_command(id); event.target.style.backgroundImage = "url('https://newbiely.com/images/tutorial/" + img_name_lookup[id] + "_active.png')"; } event.stopPropagation(); event.preventDefault(); } function mouse_up(event) { if (event.target !== event.currentTarget) { var id = event.target.id; send_command(CMD_STOP); event.target.style.backgroundImage = "url('https://newbiely.com/images/tutorial/" + img_name_lookup[id] + "_inactive.png')"; } event.stopPropagation(); event.preventDefault(); } function send_command(cmd) { if(ws != null) if(ws.readyState == 1) ws.send(cmd + "\r\n"); } window.onload = init; </script> </head> <body> <h2>ESP8266 - RC Car via Web</h2> <div id="container"> <div id="0" class="button_stop"></div> <div id="1" class="button_up"></div> <div id="2" class="button_down"></div> <div id="8" class="button_right"></div> <div id="4" class="button_left"></div> </div> <p> WebSocket : <span id="ws_state" style="color:blue">closed</span><br> </p> <button id="wc_conn" type="button" onclick="wc_onclick();">Connect</button> <br> <br> <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 tin: newbiely.com.inoindex.h
    • Nhấn nút Upload 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 lại đị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ủa bạn.
    • Bạn sẽ thấy trang web như dưới đây:
    ESP8266 NodeMCU điều khiển ô tô 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 xe quay trái/quay phải và di chuyển tiến lên/lùi thông qua giao diện web.

    Để tiết kiệm bộ nhớ của ESP8266, hình ảnh của các nút điều khiển KHÔNG được lưu 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 web.

    ※ Lưu ý:

    • Nếu bạn chỉnh sửa nội dung HTML trong index.h và không sửa đổi bất cứ điều gì trong tệp newbiely.com.ino, 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 tệp newbiely.com.ino (ví dụ thêm một dòng trống, thêm một chú thích....)

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

    Đoạn mã ESP8266 ở trên đi kèm với lời giải thích cho từng dòng. Xin hãy đọc các chú thích trong mã.