ESP32 - 웹을 통해 서보 모터 제어 | ESP32 - Control Servo Motor via Web

이 튜토리얼은 스마트폰이나 PC의 브라우저에서 웹을 통해 서보 모터를 제어하는 방법에 대해 ESP32를 사용하는 방법을 안내합니다. 그래픽 웹 사용자 인터페이스를 통해 서보 모터를 부드럽고 동적으로 제어하기 위해 WebSocket이라는 것을 사용할 것입니다.

아래 비디오는 시연입니다:

이제, 왜 WebSocket을 사용할까요? 아이디어는 다음과 같습니다:

시작합시다!

준비물

1×ESP-WROOM-32 Dev Module 쿠팡 | Amazon
1×USB Cable Type-C 쿠팡 | Amazon
1×Servo Motor 쿠팡 | Amazon
1×Breadboard 쿠팡 | Amazon
1×Jumper Wires Amazon
1×(Optional) DC Power Jack 쿠팡 | Amazon
1×(Recommended) Screw Terminal Expansion Board for ESP32 쿠팡 | Amazon
공개: 이 섹션에서 제공된 링크 중 일부는 제휴 링크입니다. 이 링크를 통해 구매한 경우 추가 비용없이 수수료를 받을 수 있습니다. 지원해 주셔서 감사합니다.

서보 모터 및 WebSocket에 대하여

우리는 서보 모터와 WebSocket에 대한 구체적인 튜토리얼을 가지고 있습니다. 각 튜토리얼에는 하드웨어 핀 아웃, 작동 원리, ESP32에 대한 배선 연결, ESP32 코드에 대한 자세한 정보와 단계별 지침이 포함되어 있습니다... 다음 링크에서 자세히 알아보세요:

작동 원리

ESP32 코드는 웹 서버와 WebSocket 서버를 모두 생성합니다. 작동 원리는 다음과 같습니다:

  • 웹 브라우저에 ESP32의 IP 주소를 입력하면, 웹 브라우저는 ESP32에서 웹페이지(사용자 인터페이스)를 요청합니다.
  • ESP32의 웹 서버는 웹페이지의 내용(HTML, CSS, JavaScript)을 보내며 응답합니다.
  • 그러면 웹 브라우저가 웹페이지를 표시합니다.
  • 웹페이지 내의 JavaScript 코드는 ESP32의 WebSocket 서버에 WebSocket 연결을 설정합니다.
  • 이 WebSocket 연결이 설정되면, 웹페이지의 손잡이를 돌리면 JavaScript 코드가 배경에서 이 WebSocket 연결을 통해 각도 값을 ESP32로 조용히 보냅니다.
  • ESP32의 WebSocket 서버는 각도 값을 받은 후에, 서보 모터를 그에 따라 제어합니다.

간단히 말해서, WebSocket 연결은 서보 모터 각도의 원활하고 실시간 제어를 가능하게 합니다.

서보 모터와 ESP32 간의 배선도

ESP32 Servo Motor Wiring Diagram

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

ESP32 및 다른 구성 요소에 전원을 공급하는 방법에 대해 잘 알지 못하는 경우, 다음 튜토리얼에서 안내를 찾을 수 있습니다: ESP32 전원 공급 방법.

간단함을 위해, 위의 배선도는 테스트나 학습 목적, 그리고 소형 토크 서보 모터를 위해 사용됩니다. 실제로, 서보 모터를 위해 외부 전원 공급 장치를 사용하는 것이 좋습니다. 아래 배선도는 서보 모터를 외부 전원원에 연결하는 방법을 보여줍니다.

ESP32 servo motor external power supply wiring diagram

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

아래는 서보 모터와 ESP32 사이의 실제 연결을 보여줍니다.

ESP32 servo motor power supply wiring diagram

ESP32 코드

웹페이지의 내용(HTML, CSS, JavaScript)은 index.h 파일에 따로 저장됩니다. 그래서 우리는 Arduino IDE에 두 개의 코드 파일을 가지게 될 것입니다.

  • ESP32 코드인 .ino 파일로 웹 서버와 WebSocket 서버를 생성하고 서보 모터를 제어합니다.
  • 웹페이지의 내용이 포함된 .h 파일입니다.

사용 방법

  • 만약 이게 ESP32를 처음 사용하는 거라면, Arduino IDE에서 ESP32 환경 설정하기를 참조하세요.
  • 위 이미지와 같이 배선하세요.
  • ESP32 보드를 마이크로 USB 케이블을 사용하여 PC에 연결하세요.
  • PC에서 Arduino IDE를 엽니다.
  • 올바른 ESP32 보드(예: ESP32 Dev Module)와 COM 포트를 선택하세요.
  • Arduino IDE의 왼쪽 네비게이션 바에 있는 Library Manager 아이콘을 클릭하여 라이브러리 관리자를 엽니다.
  • “ESPAsyncWebServer”을 검색하고, lacamera가 만든 ESPAsyncWebServer를 찾습니다.
  • Install 버튼을 클릭하여 ESPAsyncWebServer 라이브러리를 설치하세요.
ESP32 ESPAsyncWebServer library

의존성을 설치하라는 요청을 받게 됩니다. Install All 버튼을 클릭하세요.

ESP32 ESPAsyncWebServer dependencies library

“WebSockets”를 검색한 다음, Markus Sattler이 만든 WebSockets를 찾으세요.

WebSockets 라이브러리를 설치하려면 Install 버튼을 클릭하세요.

ESP32 WebSockets library

검색 상자에 ServoESP32를 입력한 다음, Jaroslav Paral의 서보 라이브러리를 찾으십시오. 버전 1.1.1 및 1.1.0 모두 버그에 영향을 받는다는 점을 유의하십시오. 다른 버전을 선택해 주십시오.

ESP32용 서보 모터 라이브러리를 설치하려면 Install 버튼을 클릭하십시오.

ESP32 servo motor library
  • Arduino IDE에서 새 스케치를 생성하세요. 이름을 지정하세요. 예를 들어, newbiely.kr.ino
  • 아래의 코드를 복사하여 Arduino IDE로 열기
/* * 이 ESP32 코드는 newbiely.kr 에서 개발되었습니다 * 이 ESP32 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/esp32/esp32-controls-servo-motor-via-web */ #include <Servo.h> #include <WiFi.h> #include <ESPAsyncWebServer.h> #include <WebSocketsServer.h> #include "index.h" #define SERVO_PIN 26 // ESP32 핀 GPIO26이 서보 모터에 연결됨 Servo servo; const char* ssid = "YOUR_WIFI_SSID"; // 이 부분을 변경하세요 const char* password = "YOUR_WIFI_PASSWORD"; // 이 부분을 변경하세요 AsyncWebServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); // 포트 81에서 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); // ESP32 핀에 서보를 연결함 // Wi-Fi에 연결 WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); // WebSocket 서버 초기화 webSocket.begin(); webSocket.onEvent(webSocketEvent); // WebSocket 연결을 생성하기 위한 JavaScript가 포함된 기본 HTML 페이지를 제공 server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { Serial.println("Web Server: received a web page request"); String html = HTML_CONTENT; // index.h 파일에서 HTML 콘텐츠 사용 request->send(200, "text/html", html); }); server.begin(); Serial.print("ESP32 Web Server's IP address: "); Serial.println(WiFi.localIP()); } void loop() { webSocket.loop(); }
  • 코드 내의 WiFi 정보(SSID 및 비밀번호)를 자신의 네트워크 자격증명과 일치하도록 수정하세요.
  • Arduino IDE에서 index.h 파일 생성 방법:
    • 직렬 모니터 아이콘 바로 아래에 있는 버튼을 클릭한 후 새 탭을 선택하거나, Ctrl+Shift+N 키를 사용하세요.
    Arduino IDE 2 adds file

    파일 이름을 index.h로 지정하고 OK 버튼을 클릭하세요.

    Arduino IDE 2 adds file index.h

    아래 코드를 복사하여 index.h에 붙여넣으세요.

    /* * 이 ESP32 코드는 newbiely.kr 에서 개발되었습니다 * 이 ESP32 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/esp32/esp32-controls-servo-motor-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>ESP32 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> ESP32 - 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> )=====";
    • 이제 두 파일에 코드가 있습니다: newbiely.kr.inoindex.h
    • Arduino IDE에서 Upload 버튼을 클릭하여 ESP32에 코드를 업로드하세요
    • 시리얼 모니터를 열어주세요
    • 시리얼 모니터에서 결과를 확인하세요.
    COM6
    Send
    Connecting to WiFi... Connected to WiFi ESP32 Web Server's IP address IP address: 192.168.0.2
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • 표시된 IP 주소를 기록하고, 이 주소를 스마트폰 또는 PC의 웹 브라우저 주소창에 입력하세요.
    • 아래와 같이 웹페이지가 보일 것입니다:
    ESP32 controls servo motor via web browser
    • 웹 페이지의 자바스크립트 코드는 자동으로 ESP32에 WebSocket 연결을 생성합니다.
    • 이제 웹 인터페이스를 통해 서보 모터의 각도를 제어할 수 있습니다.

    ESP32의 메모리를 절약하기 위해, 서보 모터의 이미지는 ESP32에 저장되지 않습니다. 대신, 인터넷에 저장되어 있으므로, 웹 제어 페이지에 이미지를 로드하기 위해 휴대폰이나 PC가 인터넷 연결을 해야 합니다.

    ※ NOTE THAT:

    • 만약 index.h에서 HTML 내용을 수정하고 newbiely.kr.ino 파일은 만지지 않는다면, ESP32에 코드를 컴파일하고 업로드할 때 Arduino IDE는 HTML 내용을 업데이트하지 않을 것입니다.
    • 이 경우 Arduino IDE에서 HTML 내용을 업데이트하려면 newbiely.kr.ino 파일에 변경을 가해야 합니다 (예를 들어, 빈 줄 추가, 주석 추가...).

    코드 줄마다 설명

    위의 ESP32 코드에는 줄별 설명이 포함되어 있습니다. 코드의 주석을 읽어주세요!

※ 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!