아두이노 우노 R4 - 웹을 통해 자동차 제어

이번 튜토리얼에서는 Arduino Uno R4 WiFi를 사용하여 웹을 통해 2WD RC 로봇 자동차를 제어하는 방법을 안내합니다. 이 가이드에서는 Arduino Uno R4의 강력한 내장 WiFi 기능을 활용하여 원격으로 로봇 자동차를 설정하고 제어하는 단계를 안내합니다. 이 튜토리얼을 마치면 다음을 배우게 됩니다:

아두이노 UNO R4가 웹을 통해 로봇 자동차를 제어합니다.

이 튜토리얼은 로봇 공학 및 웹 기반 제어 시스템에 관심이 있는 취미자, 학생 및 모든 사람에게 완벽합니다. 아두이노에 초보자이든 경험자이든 관계없이, 우리의 단계별 지침은 2WD RC 로봇 자동차를 원격으로 제어하려는 목표를 달성하는 데 도움을 줄 것입니다.

로봇 공학과 웹 기술을 결합하는 이 흥미로운 여정을 시작해 봅시다!

Hardware Preparation

1×Arduino UNO R4 WiFi Amazon
1×USB Cable Type-C 쿠팡 | Amazon
1×2WD RC Car 쿠팡 | Amazon
1×L298N Motor Driver Module 쿠팡 | Amazon
1×IR Remote Controller Kit Amazon
1×CR2025 Battery (for IR Remote controller) Amazon
1×1.5V AA Battery (for Arduino UNO R4 and Car) Amazon
1×Jumper Wires Amazon
1×Breadboard 쿠팡 | Amazon
1×(Recommended) Screw Terminal Block Shield for Arduino UNO R4 쿠팡 | Amazon
1×(Recommended) Breadboard Shield For Arduino UNO R4 쿠팡 | Amazon
1×(Recommended) Enclosure For Arduino UNO R4 Amazon
1×(Recommended) Power Splitter For Arduino UNO R4 Amazon
공개: 이 섹션에서 제공된 링크 중 일부는 제휴 링크입니다. 이 링크를 통해 구매한 경우 추가 비용없이 수수료를 받을 수 있습니다. 지원해 주셔서 감사합니다.

RC 자동차를 제어하는 데 왜 WebSocket이 필요할까요?

  • 웹소켓이 없으면 자동차의 방향을 변경할 때마다 페이지를 새로 고쳐야 합니다. 이 방법은 그다지 효율적이지 않습니다.
  • 웹소켓을 사용하면 웹페이지와 Arduino UNO R4 사이에 전용 연결이 생성됩니다. 이 설정을 통해 페이지를 새로 고칠 필요 없이 Arduino UNO R4에 명령을 보낼 수 있습니다. 그 결과 로봇 자동차는 빠르고 매끄럽게 반응합니다. 놀랍지 않나요?

요약하면, WebSocket은 로봇을 부드럽고 실시간으로 제어할 수 있게 해줍니다.

Arduino UNO R4에서 WebSocket 사용에 대한 자세한 가이드를 제공합니다. 제공된 링크를 방문하여 자세히 알아보세요: Arduino UNO R4 - WebSocket 튜토리얼

작동 방식

Arduino UNO R4 코드는 웹 서버와 WebSocket 서버를 생성합니다. 작동 방식은 다음과 같습니다:

  • Arduino UNO R4의 IP 주소를 웹 브라우저에 입력하면, Arduino UNO R4로부터 사용자 인터페이스 웹페이지를 요청합니다. Arduino UNO R4의 웹 서버는 HTML, CSS, JavaScript로 구성된 웹페이지의 콘텐츠를 보내 응답합니다. 그런 다음 웹 브라우저가 이 웹페이지를 표시합니다. 웹페이지의 JavaScript 코드는 Arduino UNO R4의 WebSocket 서버와 WebSocket 연결을 시작합니다. 이 WebSocket 연결이 작동하면, 웹페이지에서 버튼을 누르거나 놓는 것이 해당 연결을 통해 Arduino UNO R4로 명령을 전송합니다. Arduino UNO R4의 WebSocket 서버는 이러한 명령을 받아 로봇 카를 지시대로 제어합니다.

다음은 사용자가 수행하는 작업에 따라 웹페이지에서 Arduino UNO R4로 전송된 명령어를 표시하는 표입니다:

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

2WD RC 자동차와 Arduino UNO R4 간의 배선도

아두이노 UNO R4 2WD RC 자동차 배선도

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

일반적으로 두 가지 다른 전력원을 필요로 합니다:

  • 하나는 모터용입니다.
  • 다른 하나는 Arduino UNO R4 보드와 모터 드라이버로 사용되는 L298N 모듈용입니다.

이 설정을 더 간단하게 만들려면 한 개의 전원, 즉 네 개의 1.5V 배터리를 사용하여 총 6V를 만드세요. 방법은 다음과 같습니다:

  • 설명서에 표시된 대로 L298N 모듈에 배터리를 연결합니다.
  • ENA와 ENB 핀에서 두 개의 점퍼를 제거합니다.
  • 5VEN으로 표시된 점퍼를 장착합니다 (도면에서 노란색 원으로 표시됨).
  • L298N 모듈의 12V 핀을 Arduino UNO R4의 Vin 핀에 연결합니다. 이렇게 하면 배터리를 사용하여 Arduino UNO R4에 전원을 공급할 수 있습니다.

2WD RC 자동차에는 전원 스위치가 있습니다. 이를 사용하여 배터리를 연결하거나 연결 해제할 수 있어 필요할 때 자동차의 전원을 켜거나 끌 수 있습니다. 더 간단한 것을 원한다면 스위치는 사용하지 않을 수 있습니다.

아두이노 UNO R4 코드

웹 페이지의 내용(HTML, CSS, JavaScript)은 index.h라는 별도의 파일에 저장됩니다. 따라서 우리는 Arduino IDE에서 두 개의 코드 파일을 사용할 것입니다.

  • ino 파일은 자동차를 제어하기 위해 웹 서버와 WebSocket 서버를 생성하는 Arduino UNO R4 코드입니다.
  • h 파일은 웹페이지의 내용을 저장합니다.

Detailed Instructions

다음 지침을 단계별로 따르세요:

  • Arduino Uno R4 WiFi/Minima를 처음 사용하는 경우 Arduino IDE에서 Arduino Uno R4 WiFi/Minima 환경 설정 튜토리얼을 참조하세요.
  • USB 케이블을 사용하여 Arduino Uno R4 보드를 컴퓨터에 연결합니다.
  • 컴퓨터에서 Arduino IDE를 실행합니다.
  • 적절한 Arduino Uno R4 보드(예: Arduino Uno R4 WiFi) 및 COM 포트를 선택합니다.
  • Arduino IDE의 왼쪽에 있는 Library Manager 아이콘을 클릭하여 라이브러리 관리자를 엽니다.
  • 라이브러리 관리자에서 “mWebSockets”를 검색하고 Dawid Kurek의 버전을 찾습니다.
  • MWebSockets 라이브러리를 설치하려면 Install 버튼을 클릭합니다.
아두이노 UNO R4 mWebSockets 라이브러리
  • Arduino IDE에서 새 스케치를 시작하고, 예를 들어 newbiely.com.ino 이라고 이름을 지정합니다.
  • 다음 코드를 복사하여 Arduino IDE에서 엽니다.
/* * 이 Arduino UNO R4 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino UNO R4 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-uno-r4/arduino-uno-r4-controls-car-via-web */ #include <WiFiS3.h> #include <WebSocketServer.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 UNO R4 pin connected to the ENA pin L298N #define IN1_PIN 6 // The Arduino UNO R4 pin connected to the IN1 pin L298N #define IN2_PIN 5 // The Arduino UNO R4 pin connected to the IN2 pin L298N #define IN3_PIN 4 // The Arduino UNO R4 pin connected to the IN3 pin L298N #define IN4_PIN 3 // The Arduino UNO R4 pin connected to the IN4 pin L298N #define ENB_PIN 2 // The Arduino UNO R4 pin connected to the ENB pin L298N const char *ssid = "YOUR_WIFI_SSID"; // CHANGE IT const char *password = "YOUR_WIFI_PASSWORD"; // CHANGE IT using namespace net; WebSocketServer webSocket(81); WiFiServer server(80); int status = WL_IDLE_STATUS; void setup() { Serial.begin(9600); 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 //Initialize serial and wait for port to open: Serial.begin(9600); String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) Serial.println("Please upgrade the firmware"); // attempt to connect to WiFi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(password); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, password); // wait 4 seconds for connection: delay(4000); } // print your board's IP address: Serial.print("IP Address: "); Serial.println(WiFi.localIP()); server.begin(); webSocket.onConnection([](WebSocket &ws) { const auto protocol = ws.getProtocol(); if (protocol) { Serial.print(F("Client protocol: ")); Serial.println(protocol); } ws.onMessage([](WebSocket &ws, const 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 (dataType) { case WebSocket::DataType::TEXT: 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; case WebSocket::DataType::BINARY: Serial.println(F("Received binary data")); break; } }); ws.onClose([](WebSocket &, const WebSocket::CloseCode, const char *, uint16_t) { Serial.println(F("Disconnected")); }); Serial.print(F("New WebSocket Connnection from client: ")); Serial.println(ws.getRemoteIP()); }); webSocket.begin(); } void loop() { webSocket.listen(); // listen for incoming clients WiFiClient client = server.available(); if (client) { // read the HTTP request header line by line while (client.connected()) { if (client.available()) { String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request if (HTTP_header.equals("\r")) // the end of HTTP request break; Serial.print("<< "); Serial.println(HTTP_header); // print HTTP request to Serial Monitor } } // send the HTTP response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println(); // the separator between HTTP header and body String html = String(HTML_CONTENT); client.println(html); client.flush(); // give the web browser time to receive the data delay(100); // close the connection: client.stop(); } } 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); }
  • 프로그램에서 WiFi 세부사항 (SSID 및 비밀번호)을 변경하여 네트워크 정보를 사용하십시오.
  • Arduino IDE에서 index.h 라는 이름의 파일을 생성하려면 다음 중 하나를 수행하십시오:
    • 시리얼 모니터 아이콘 아래에 위치한 버튼을 클릭하여 새 탭을 선택하거나, 키보드에서 Ctrl+Shift+N을 누르십시오.
    Arduino IDE 2 파일 추가
    • 파일 이름을 index.h로 지정하고 OK 버튼을 누르세요.
    아두이노 IDE 2에 파일 index.h가 추가됨
    • 다음 코드를 복사하여 index.h 파일에 붙여넣습니다.
    /* * 이 Arduino UNO R4 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino UNO R4 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-uno-r4/arduino-uno-r4-controls-car-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>Arduino Uno R4 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 Uno R4 - 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> )=====";
    • 이제 코드가 newbiely.com.inoindex.h라는 두 파일에 있습니다. 코드를 Arduino UNO R4에 업로드하려면 Arduino IDE에서 Upload 버튼을 클릭하세요.

    아래와 같은 오류가 표시됩니다:

    In file included from c:\Users\YOU_ACCOUNT\Documents\Arduino\libraries\mWebSockets\src/utility.h:3:0, from c:\Users\YOU_ACCOUNT\Documents\Arduino\libraries\mWebSockets\src/WebSocket.h:5, from c:\Users\YOU_ACCOUNT\Documents\Arduino\libraries\mWebSockets\src/WebSocketServer.h:5, from C:\Users\YOU_ACCOUNT\Documents\Arduino\newbiely.com\newbiely.com.ino:2: C:\Users\YOU_ACCOUNT\Documents\Arduino\libraries\mWebSockets\src/platform.h:54:12: fatal error: Ethernet.h: No such file or directory # include <Ethernet.h> ^~~~~~~~~~~~ compilation terminated. exit status 1

    이 오류를 수정하려면:

    • 폴더로 이동: C:\Users\YOUR_ACCOUNT\Documents\Arduino\libraries\mWebSockets\src/
    • Config.h라는 이름의 파일을 찾아 텍스트 편집기로 엽니다.
    • 26번째 줄로 이동하면 다음과 같이 표시됩니다:
    #define NETWORK_CONTROLLER ETHERNET_CONTROLLER_W5X00
    • 다음을 다음과 같이 변경하고 저장하십시오:
    #define NETWORK_CONTROLLER NETWORK_CONTROLLER_WIFI
    • Arduino IDE에서 Upload 버튼을 클릭하여 코드를 Arduino UNO R4에 로드합니다.
    • 시리얼 모니터를 엽니다.
    • 시리얼 모니터에 표시된 결과를 확인합니다.
    COM6
    Send
    Connecting to WiFi... Connected to WiFi Arduino UNO R4 Web Server's IP address IP address: 192.168.0.2
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • 표시된 IP 주소를 적어 스마트폰이나 컴퓨터의 웹 브라우저 주소창에 입력하세요.
    • 웹페이지는 다음과 같이 나타납니다:
    아두이노 UNO R4가 웹 브라우저를 통해 자동차를 제어합니다.
    • 웹페이지를 Arduino UNO R4와 WebSocket으로 연결하려면 CONNECT 버튼을 누르세요.
    • 이제 웹 인터페이스를 사용하여 차를 왼쪽 또는 오른쪽으로 회전시키고, 앞으로 또는 뒤로 이동할 수 있습니다.

    제어 버튼 이미지는 Arduino UNO R4에 저장되어 있지 않아서 메모리를 절약합니다. 대신, 이미지들은 온라인에 저장됩니다. 따라서, 웹 제어 페이지에서 이 이미지를 로드하려면 휴대폰이나 컴퓨터가 인터넷에 연결되어 있어야 합니다.

    ※ NOTE THAT:

    파일 이름이 index.h인 파일의 HTML을 변경했지만 newbiely.com.ino이라는 이름의 파일에서는 아무것도 변경하지 않으면, 이 코드를 Arduino UNO R4에 컴파일하고 업로드할 때 Arduino IDE는 HTML 콘텐츠를 업데이트하지 않습니다. Arduino IDE가 HTML 콘텐츠를 업데이트하도록 하려면 newbiely.com.ino 파일에 빈 줄이나 주석을 추가하는 것과 같은 작은 변경을 해야 합니다.

    코드 줄별 설명

    제공된 Arduino UNO R4 코드는 각 줄에 대한 설명을 포함하고 있습니다. 코드 내의 주석을 꼭 읽어보세요!

Arduino Uno R4 문제 해결

위의 코드가 작동하면 Arduino UNO R4의 WiFi 모듈 최신 버전을 업데이트해 주세요.

  • Arduino Uno R4 WiFi를 PC에 연결하세요
  • Arduino IDE 2를 엽니다
  • 도구 펌웨어 업데이터로 이동하세요
아두이노 우노 R4 WiFi 펌웨어 업데이트
  • Arduino Uno R4 WiFi 보드와 포트 선택
  • 업데이트 확인 버튼 클릭
  • 사용 가능한 펌웨어 버전 목록이 나타납니다
  • 최신 펌웨어 버전 선택
  • Install 버튼 클릭
  • 완료될 때까지 기다리세요
  • Arduino Uno R4 WiFi를 재부팅
  • 코드를 재컴파일하고 Arduino Uno R4 WiFi에 업로드
  • 결과 확인

※ OUR MESSAGES

  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!