Arduino điều khiển ô tô qua web

Hướng dẫn này chỉ cho bạn cách điều khiển một chiếc ô tô robot từ xa bằng Arduino từ trình duyệt web trên điện thoại thông minh hoặc máy tính của bạn qua WiFi. Việc điều khiển được quản lý thông qua một giao diện người dùng web đồ họa sử dụng công nghệ WebSocket, giúp ô tô vận hành mượt mà và linh hoạt.

Arduino điều khiển xe robot qua web

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

1×Arduino UNO R4 WiFi
1×Alternatively, DIYables STEM V4 IoT
1×(Tùy chọn) DIYables STEM V4 IoT
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 Arduino and Car)
1×dây jumper
1×breadboard
1×(Khuyến nghị) Screw Terminal Block Shield for Arduino UNO R4
1×(Khuyến nghị) Breadboard Shield for Arduino UNO R4
1×(Khuyến nghị) Enclosure for Arduino UNO R4
1×(Khuyến nghị) Power Splitter for Arduino UNO R4
1×(Khuyến nghị) Prototyping Base Plate & Breadboard Kit for Arduino UNO

Or you can buy the following kits:

1×DIYables STEM V4 IoT Starter Kit (Arduino included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)

Giới thiệu về Xe RC 2WD và WebSocket

Bây giờ, tại sao chọn WebSocket? Dưới đây là các lý do:

  • Không có WebSocket, bạn sẽ phải tải lại trang mỗi khi muốn thay đổi hướng của xe. Điều này không hiệu quả!
  • Với WebSocket, một kết nối đặc biệt được thiết lập giữa trang web và Arduino. Điều này cho phép bạn gửi các lệnh tới Arduino mà không cần tải lại trang. Kết quả? Xe robot phản hồi một cách mượt mà và ngay lập tức. Thật ấn tượng, phải không?

Tóm lại, WebSocket hỗ trợ điều khiển robot một cách mượt mà và theo thời gian thực.

Chúng tôi có các bài hướng dẫn cụ thể về ô tô điều khiển từ xa 2 bánh (2WD RC Car) và WebSocket. Mỗi bà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 (pinout), nguyên lý hoạt động, cách kết nối dây với Arduino, mã Arduino... Tìm hiểu thêm về chúng tại các liên kết sau:

Cách hoạt động

Mã Arduino thiết lập cả máy chủ web và máy chủ WebSocket. Đây là cách nó hoạt động:

  • Khi bạn nhập địa chỉ IP của Arduino vào trình duyệt web, nó sẽ gửi một yêu cầu cho trang web (Giao diện người dùng) từ Arduino.
  • Máy chủ web của Arduino trả lời bằng cách cung cấp 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 này.
  • Bên trong trang web, mã JavaScript khởi tạo một kết nối WebSocket với máy chủ WebSocket trên Arduino.
  • Khi kết nối WebSocket này đã hoạt động, bất kỳ lần nhấn hoặc thả nút nào trên trang web sẽ khiến mã JavaScript gửi các lệnh tới Arduino qua kết nối này một cách kín đáo.
  • Máy chủ WebSocket trên Arduino nhận các lệnh này và điều khiển xe robot tương ứng.

Dưới đây là một bảng hiển thị danh sách các lệnh mà trang web gửi tới Arduino 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ơ đồ đấu dây giữa xe RC hai bánh dẫn động và Arduino

sơ đồ đấu dây xe rc Arduino hai bánh dẫn động

This image is created using Fritzing. Click to enlarge image

Thông thường, bạn sẽ cần hai nguồn cấp điện riêng biệt:

  • Một cái dành cho động cơ.
  • Cái khác dành cho cả bảng Arduino và mô-đun L298N (đóng vai trò là bộ điều khiển động cơ).

Tuy nhiên, bạn có thể đơn giản hóa thiết lập này bằng cách chỉ sử dụng một nguồn điện – bốn viên pin 1,5V để tạo tổng điện áp 6V. Đây là cách làm:

  • Kết nối nguồn từ pin cho module L298N theo chỉ dẫn.
  • Loại bỏ hai jumper khỏi các chân ENA và ENB để ngắt kết nối chúng với 5V trên module L298N.
  • Chèn một jumper được dán nhãn 5VEN (được chỉ ra bằng vòng tròn vàng trên sơ đồ).
  • Kết nối chân 12V trên module L298N với chân Vin trên Arduino. Kết nối này sẽ cấp nguồn cho Arduino trực tiếp từ bộ pin.

Xe RC hai bánh dẫn động (2WD) bao gồm một công tắc bật/tắt, cung cấp cho bạn tùy chọn kết nối pin thông qua công tắc. Thiết lập này cho phép bạn bật và tắt nguồn cho xe khi cần. Nếu bạn muốn một cách sắp xếp đơn giản hơn, bạn có thể chọn bỏ qua công tắc hoàn toàn.

Mã Arduino

Nội dung của trang web (HTML, CSS, JavaScript) được lưu riêng biệt 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ã Arduino, tạo một 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

  • Nếu đây là lần đầu bạn sử dụng Arduino Uno R4, hãy xem Cách bắt đầu với Arduino UNO R4.
  • Thực hiện các kết nối như hình ở trên.
  • Kết nối bo mạch Arduino với máy tính của bạn bằng cáp micro USB.
  • Mở Arduino IDE trên máy tính của bạn.
  • Chọn bo mạch Arduino đúng (Arduino Uno R4 WiFi) và cổng COM.
  • Mở Library Manager bằng cách nhấp vào biểu tượng Library Manager trên thanh điều hướng bên trái của Arduino IDE.
  • Tìm kiếm Web Server for Arduino Uno R4 WiFi và xác định vị trí thư viện Web Server do DIYables tạo ra.
  • Nhấn nút Install để cài đặt thư viện Web Server.
thư viện máy chủ web cho Arduino UNO R4
  • Trên Arduino IDE, tạo một sketch mới, đặt cho nó một tên, ví dụ, ArduinoGetStarted.com.ino
  • Sao chép mã dưới đây và mở bằng Arduino IDE
/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino 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/arduino/arduino-controls-car-via-web */ #include <UnoR4WiFi_WebServer.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 ENA_PIN 7 // The Arduino pin connected to the ENA pin L298N #define IN1_PIN 6 // The Arduino pin connected to the IN1 pin L298N #define IN2_PIN 5 // The Arduino pin connected to the IN2 pin L298N #define IN3_PIN 4 // The Arduino pin connected to the IN3 pin L298N #define IN4_PIN 3 // The Arduino pin connected to the IN4 pin L298N #define ENB_PIN 2 // The Arduino pin connected to the ENB pin L298N // WiFi credentials const char WIFI_SSID[] = "YOUR_WIFI_SSID"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD"; // Create web server instance UnoR4WiFi_WebServer server(80); UnoR4WiFi_WebSocket *webSocket; // Page handlers void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { server.sendResponse(client, HTML_CONTENT); } // WebSocket event handlers void onWebSocketOpen(net::WebSocket& ws) { Serial.println("New WebSocket connection"); } void onWebSocketMessage(net::WebSocket& ws, const net::WebSocket::DataType dataType, const char* message, uint16_t length) { String cmd_str = String((char*)message); int command = cmd_str.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"); } } void onWebSocketClose(net::WebSocket& ws, const net::WebSocket::CloseCode code, const char* reason, uint16_t length) { Serial.println("WebSocket client disconnected"); } void setup() { Serial.begin(9600); delay(1000); pinMode(ENA_PIN, OUTPUT); pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); pinMode(IN3_PIN, OUTPUT); pinMode(IN4_PIN, OUTPUT); pinMode(ENB_PIN, OUTPUT); digitalWrite(ENA_PIN, HIGH); // set full speed digitalWrite(ENB_PIN, HIGH); // set full speed Serial.println("Arduino Uno R4 WiFi - WebSocket Server"); // Configure web server routes server.addRoute("/", handleHome); // Start web server with WiFi connection server.begin(WIFI_SSID, WIFI_PASSWORD); // Enable WebSocket functionality webSocket = server.enableWebSocket(81); if (webSocket != nullptr) { // Set up WebSocket event handlers webSocket->onOpen(onWebSocketOpen); webSocket->onMessage(onWebSocketMessage); webSocket->onClose(onWebSocketClose); } else { Serial.println("Failed to start WebSocket server"); } } void loop() { // Handle HTTP requests and WebSocket connections using the library server.handleClient(); server.handleWebSocket(); delay(10); } 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); }
  • Chỉnh sửa thông tin WiFi (SSID và mật khẩu) trong mã để phù hợp với thông tin mạng của bạn.
  • Tạo file index.h trên Arduino IDE bằng cách:
    • Nhấp vào nút ngay dưới biểu tượng Serial Monitor và chọn Tab Mới, hoặc sử dụng tổ hợp phím Ctrl+Shift+N.
    Arduino ide 2 thêm tệp
    • Hãy đặt tên cho tệp là index.h và nhấn nút OK
    Arduino ide 2 thêm file index.h
    • Sao chép đoạn mã dưới đây và dán nó vào index.h.
    /* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino 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/arduino/arduino-controls-car-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>Arduino 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://esp32io.com/images/tutorial/up_inactive.png') no-repeat; background-size: contain; left: 200px; top: 0px; transform: translateX(-50%); } .button_down { background: url('https://esp32io.com/images/tutorial/down_inactive.png') no-repeat; background-size: contain; left:200px; bottom: 0px; transform: translateX(-50%); } .button_right { background: url('https://esp32io.com/images/tutorial/right_inactive.png') no-repeat; background-size: contain; right: 0px; top: 200px; transform: translateY(-50%); } .button_left { background: url('https://esp32io.com/images/tutorial/left_inactive.png') no-repeat; background-size: contain; left:0px; top: 200px; transform: translateY(-50%); } .button_stop { background: url('https://esp32io.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://esp32io.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://esp32io.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>Arduino - 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ã nguồn trong hai tệp tin: ArduinoGetStarted.com.inoindex.h
    • Nhấp vào nút Tải lên trên Arduino IDE để nạp mã vào Arduino.
    • Mở Serial Monitor
    • Xem kết quả trên Serial Monitor.
    COM6
    Send
    Arduino Uno R4 WiFi - WebSocket Server Connected! IP Address: 192.168.0.254 SSID: YOUR_WIFI_SSID IP Address: 192.168.0.254 Signal strength (RSSI): -44 dBm WebSocket server started on port 81 WebSocket URL: ws://192.168.0.254:81 WebSocket server enabled successfully
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Ghi chú đị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 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:
    Arduino điều khiển ô tô qua trình duyệt web
    • Nhấn nút CONNECT để kết nối trang web với Arduino qua WebSocket.
    • Bây giờ bạn có thể điều khiển xe để rẽ trái/phải, tiến lên/lùi thông qua giao diện web.

    Để tiết kiệm bộ nhớ của Arduino, hình ảnh của các nút điều khiển KHÔNG được lưu trên Arduino. Thay vào đó, chúng được lưu trên Internet, vì vậy đ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 động vào bất kỳ thứ gì trong tệp ArduinoGetStarted.com.ino, khi bạn biên dịch và tải mã lên Arduino, 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 ArduinoGetStarted.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ã Arduino ở 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ã.