산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

아두이노 우노 웹 기반 서보 제어 - PHPoC WiFi 실드 활용

부품 및 소모품

아두이노 우노 (Arduino UNO) 1개
PHPoC WiFi 실드 (PHPoC WiFi Shield for Arduino) 1개
씨드 서보 모터 (Seeed Servo motor) 1개
점퍼 와이어 1세트

프로젝트 개요

소개

초보자라면 아두이노 - 서보 모터와 아두이노 - WiFi 관련 자료를 먼저 읽어보시길 권장합니다.

아두이노를 인터넷에 연결하려면 이더넷 실드, WiFi 실드, PHPoC 실드, PHPoC WiFi 실드 같은 인터넷 실드가 필요합니다.

PHPoC 실드의 뛰어난 점은 이더넷/WiFi 실드처럼 인터넷 연결을 제공할 뿐만 아니라, 내장 웹 서버를 통해 웹 브라우저에서 아두이노를 제어/모니터링할 수 있다는 것입니다. 또한 WebSocket을 지원해 웹페이지 새로고침 없이 실시간 제어/모니터링이 가능합니다.

PHPoC 실드에는 몇 가지 내장 웹 애플리케이션이 있습니다. 자세한 내용은 이 링크를 참조하세요.

이 프로젝트에서는 웹 원격 제어/슬라이드(Web Remote Control/Slide) 웹 애플리케이션의 UI를 변경하고, 웹 브라우저에서 수신한 각도에 따라 서보 모터를 회전시키는 아두이노 코드를 작성했습니다.

배선

아두이노 우노 웹 기반 서보 제어 - PHPoC WiFi 실드 활용

데이터 흐름

웹 브라우저 → PHPoC 실드 → 아두이노

웹 앱에서 터치/마우스 이벤트 기반으로 각도 계산 → WebSocket으로 PHPoC 실드 전송 → PHPoC 실드가 아두이노로 전달 → 아두이노가 서보 모터를 해당 각도로 회전

해야 할 작업

PHPoC 실드 WiFi 정보 설정

설명서 참조: https://www.phpoc.com/support/manual/p4s-347_user_manual/contents.php?id=network_first_setup

PHPoC 실드에 새 UI 업로드

아두이노 코드 작성

테스트

초보자를 위한 최고의 아두이노 스타터 키트

아두이노 키트를 찾고 있다면 초보자를 위한 최고의 아두이노 키트를 참고하세요.

함수 레퍼런스

코드

remote_rotate.php (PHP)
<!DOCTYPE html>
<html>
<head>
  <title>PHPoC Shield - Web Remote Control for Arduino</title>
  <meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
  <style>
    body { text-align: center; font-size: 15pt; }
    h1 { font-weight: bold; font-size: 25pt; }
    h2 { font-weight: bold; font-size: 15pt; }
    button { font-weight: bold; font-size: 15pt; }
  </style>
  <script>
    var canvas_width = 400, canvas_height = 400;
    var plate_radius = 160;
    var click_state = 0;
    var last_plate_angle = 0;
    var plate_angle = 0, last_angle = 0;
    var ws;
    function init() {
      var canvas = document.getElementById("remote");
      canvas.addEventListener("touchstart", mouse_down);
      canvas.addEventListener("touchend", mouse_up);
      canvas.addEventListener("touchmove", mouse_move);
      canvas.addEventListener("mousedown", mouse_down);
      canvas.addEventListener("mouseup", mouse_up);
      canvas.addEventListener("mousemove", mouse_move);
      var ctx = canvas.getContext("2d");
      ctx.translate(canvas_width / 2, canvas_height / 2);
      rotate_plate(0);
    }
    function connect_onclick() {
      if (ws == null) {
        var ws_host_addr = "";
        var debug = document.getElementById("debug");
        if ((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "[")) {
          ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
          ws_host_addr = ws_host_addr.replace(/:/g, "-");
          ws_host_addr += ".ipv6-literal.net";
        }
        ws = new WebSocket("ws://" + ws_host_addr + "/remote_slide", "text.phpoc");
        document.getElementById("ws_state").innerHTML = "CONNECTING";
        ws.onopen = ws_onopen;
        ws.onclose = ws_onclose;
        ws.onmessage = ws_onmessage;
      } else {
        ws.close();
      }
    }
    function ws_onopen() {
      document.getElementById("ws_state").innerHTML = "<font color='blue'>CONNECTED</font>";
      document.getElementById("bt_connect").innerHTML = "Disconnect";
    }
    function ws_onclose() {
      document.getElementById("ws_state").innerHTML = "<font color='gray'>CLOSED</font>";
      document.getElementById("bt_connect").innerHTML = "Connect";
      ws.onopen = null; ws.onclose = null; ws.onmessage = null; ws = null;
    }
    function ws_onmessage(e_msg) {
      e_msg = e_msg || window.event;
      alert("msg : " + e_msg.data);
    }
    function rotate_plate(angle) {
      var canvas = document.getElementById("remote");
      var ctx = canvas.getContext("2d");
      ctx.clearRect(-canvas_width / 2, -canvas_height / 2, canvas_width, canvas_height);
      ctx.rotate(angle / 180 * Math.PI);
      ctx.strokeStyle = "red"; ctx.fillStyle = "red";
      ctx.beginPath(); ctx.arc(0, 0, plate_radius, Math.PI, Math.PI * 1.5);
      ctx.lineTo(0, 0); ctx.lineTo(-plate_radius, 0); ctx.fill(); ctx.stroke();
      ctx.strokeStyle = "blue"; ctx.fillStyle = "blue";
      ctx.beginPath(); ctx.arc(0, 0, plate_radius, 0, Math.PI / 2);
      ctx.lineTo(0, 0); ctx.lineTo(plate_radius, 0); ctx.fill(); ctx.stroke();
      ctx.strokeStyle = "black"; ctx.arc(0, 0, plate_radius, 0, Math.PI * 2); ctx.stroke();
      ctx.rotate(-angle / 180 * Math.PI);
    }
    function mouse_down() {
      if (ws == null) return;
      var dist_min, dist_max, dist;
      event.preventDefault();
      if (event.offsetX) {
        x = event.offsetX - canvas_width / 2;
        y = canvas_height / 2 - event.offsetY;
        dist_min = 40; dist_max = plate_radius;
      } else if (event.layerX) {
        x = event.layerX - canvas_width / 2;
        y = canvas_height / 2 - event.layerY;
        dist_min = 40; dist_max = canvas_width / 2;
      } else {
        x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft)) - canvas_width / 2;
        y = canvas_height / 2 - (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
        dist_min = 40; dist_max = canvas_width / 2;
      }
      dist = Math.round(Math.sqrt(x * x + y * y));
      if ((dist > dist_min) && (dist < dist_max)) {
        click_state = 1;
        last_angle = Math.round(Math.atan2(y, x) / Math.PI * 180);
      }
    }
    function mouse_up() {
      if (ws == null) return;
      event.preventDefault();
      click_state = 0;
    }
    function mouse_move() {
      if (ws == null) return;
      var dist_min, dist_max, angle, dist;
      event.preventDefault();
      if (!click_state) return;
      if (event.offsetX) {
        x = event.offsetX - canvas_width / 2;
        y = canvas_height / 2 - event.offsetY;
        dist_min = 40; dist_max = plate_radius;
      } else if (event.layerX) {
        x = event.layerX - canvas_width / 2;
        y = canvas_height / 2 - event.layerY;
        dist_min = 40; dist_max = canvas_width / 2;
      } else {
        x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft)) - canvas_width / 2;
        y = canvas_height / 2 - (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
        dist_min = 40; dist_max = canvas_width / 2;
      }
      angle = Math.round(Math.atan2(y, x) / Math.PI * 180);
      dist = Math.round(Math.sqrt(x * x + y * y));
      if ((dist < dist_min) || (dist > dist_max)) {
        click_state = 0; return;
      }
      if ((Math.abs(angle) > 90) && (angle * last_angle < 0)) {
        if (last_angle > 0) last_angle = -180;
        else last_angle = 180;
      }
      plate_angle += (angle - last_angle);
      last_angle = angle;
      if (plate_angle > 180) plate_angle = 180;
      if (plate_angle < 0) plate_angle = 0;
      rotate_plate(-plate_angle);
      if (plate_angle != last_plate_angle) {
        if (ws && ws.readyState) {
          ws.send("C" + plate_angle.toString() + "\r\n");
          last_plate_angle = plate_angle;
          debug = document.getElementById("debug");
          debug.innerHTML = plate_angle;
        }
      }
    }
    window.onload = init;
  </script>
</head>
<body>
  <p><h1>Web Remote Control / Rotate</h1></p>
  <canvas id="remote" width="400" height="400"></canvas>
  <h2>
    <p>
      WebSocket : <span id="ws_state">null</span><br>
      Angle : <span id="debug">0</span>
    </p>
    <button id="bt_connect" type="button" onclick="connect_onclick();">Connect</button>
  </h2>
</body>
</html>
아두이노 코드 (Arduino)
/* arduino web server - remote control (slide switch) */
#include "SPI.h"
#include "Phpoc.h"
#include <Servo.h>

PhpocServer server(80);
Servo myservo;
char slideName;
int slideValue;

void setup() {
  Serial.begin(9600);
  while (!Serial) ;
  Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
  server.beginWebSocket("remote_slide");
  Serial.print("WebSocket server address : ");
  Serial.println(Phpoc.localIP());
  myservo.attach(9);
  myservo.write(1);
}

void loop() {
  PhpocClient client = server.available();
  if (client) {
    String slideStr = client.readLine();
    if (slideStr) {
      slideValue = slideStr.substring(1).toInt();
      myservo.write(slideValue);
      Serial.print("Angle: ");
      Serial.println(slideValue);
    }
  }
}

제조공정

  1. 웹 제어 DMX 조명 시스템 - 아두이노 마스터 컨트롤러
  2. 블루투스 제어 아두이노 스파이봇(Spybot) 만들기
  3. 스마트 저금통 만들기: 아두이노 나노로 동전 인식기 제어하기
  4. 웹 & 모바일 앱으로 가전제품 제어하는 스마트 홈 시스템
  5. 아두이노 파워 컨트롤 센터: N-FET, P-FET, 릴레이 & RTC 키트
  6. 아두이노 블루투스로 LED 제어하기 - HC-05 & MIT App Inventor 입문 가이드
  7. 아두이노 릴레이 제어 가습기 자동화 – 고전압 안전 설계
  8. 아두이노 나노와 조이스틱으로 2개 스테퍼 모터 제어하기 – 비주이노(Visuino) 튜토리얼
  9. 아두이노 우노 & WiFi 실드로 웹에서 실시간 온도 모니터링 - 시리얼 통신 활용
  10. 아두이노 웹 패턴 언락으로 보안 강화하기 – 간편 설정 및 원격 제어