아두이노프로세싱 프로그래밍

Processing 클라이언트 HTTP LED analogWrite

coding art 2018. 6. 26. 15:05
728x90

______________________________________________________________________________________



Processing Java 모드에는 시리얼 인터페이스 기능 외에도 무선 와이파이에 의한 클라이언트 기능도 제공하고 있어 HTTP 프로토콜에 의해 와이파이가 지원되는 아두이노 호환 NodeMVCU/WeMos 보드를 제어할 수 있다.


클라이언트로서 HTTP는 이미 ThingSpeak 응용에서도 해보았지만 하나의 데이터를 보내는데 적어도 수초 정도의 시간이 소요된다. 즉 시리얼 인터페이스에 비해 통신 속도가 느린 편이다.


이미 다루어보았던 시리얼 인터페이스 Processing 코드 중에서 analogWrite() 명령을 사용하여 LED 밝기를 제어하였다.

https://steemit.com/kr/@codingart/51-processing-led


즉 PC상에서 생성한 명암진 Processing 흑백 화면을 마우스로 스캔하여 얻어지는 0∼255 범위의 마우스의 위치 값을 Firmata가 설치된 아두이노 보드에 전송하여 anlogWrite() 명령에 의해 밝기를 조절하였다. 아나로그 제어의 특성을 십분 반영하여 연속적으로 LED 밝기가 변하는 것을 관찰할 수 있다.



한편 이번 블로그에서는 USB 케이블을 사용하는 시리얼인터페이스가 아닌 와이파이에 의해서 HTTP 통신 프로토콜에 의해 LED 밝기를 제어해 보자. HTTP 프로토콜을 사용함에 있어서 어려운 점은 PC상에서 명암진 Processing  화면을 생성한 후 마우스를 스캔하여 얻어지는 0∼255 범위의 마우스의 위치 값을 적절한 속도로 NodeMCU/WeMos 보드로 송신해야 한다. HTTP 통신 속도를 제대로 맞추지 못할 경우 제어가 제대로 되는지 안되는지 파악하기에 혼란스러울 수가 있다. 따라서 NodeMCU/WeMos 보드와 PC Processing 코드 사이의 HTTP 통신 속도를 파악하기 위해서 millis() 명령을 사용하는 특별한 코딩을 추가하였다.

헤더 영역에서 와이파이 지원을 위해 processing.net 라이브러리를 불러 오고 Client 의 클라스 명령 접두어를 간단하게 c 로 정의한다.
setup()에서 그래픽 화면 크기를 가로 256 세로 200으로 정의한다. background(255)는 흰색 바탕을 뜻한다. for looping을 i=0에서 255까지 돌려 수직선을 그래픽 화면 상단 즉 (i,0)에서 아래쪽으로 (i,150)까지 긋는다. 이때 stroke(255,i,i) 는 붉은 색으로서  i = 255 가 되면 stroke(255,255,255) 는 RGB  빛의 합성이므로 백색이 된다. 즉 왼쪽은 순수 100% 빨간색이고 오른쪽은 백색이며 그 사이는 점차 색이 옅어지는 gradient 가 된다.



HTTP 통신 속도는 사용자가 사용하는 PC 하드웨어의 영향도 있을 수 있으므로 확인해 볼 필요가 있다. 통신 속도가 확인되면 이 값을 최종적으로 Processing  코드에서 한번씩 스캔하여 데이터를 보낸 후 적절한 시간 지연 값으로 사용하도록 한다. 이 시간 지연 값이 적절하다면 정확하게 LED 의 밝기를 조절할 수 있게 된다.

스캔용 화면 생성은 꼭 흑백일 필요는 없으며 빨간색 LED를 사용하는 경우 빨간색 명암을 생성하도록하자. 아울러 화면을 나누어서 윗부분은 명암 생성 아랫부분은 스캔한 값에 해당하는 색상을 포현하자. 아래 그림은 stroke 명령 코딩을 바꿔 본 결과로서 Stroke(255, 255-i, 255-i)를 사용한 결과이다. 밝기가 역전 되었으므로 원래대로 stroke(255,i,i)로 환원하도록 하자.



한편 HTTP 통신 프로토콜을 지원하는 GET 방식에서 ASCII 문자가 아닌 숫자를 넘겨서 아두이노에서 정확하게 복원하여 LED 밝기 제어에 사용해야 한다.
Processing에서 0∼255까지의 숫자를 처리하도록 하자. 한자리 숫자는 “0”+“0”+“숫자” 로 처리한다.
GET에 의해 넘겨줄 숫자의 위치는 GET / 바로 다음 위치로서 6번째부터 세자리 정수형 값으로 넘겨주게 된다.


아두이노에서는 처리는 다음과 같다. 클라이언트로부터의 입력 버퍼를 읽기 바로 전에 HTTP 통신 시간 간격을 계산할 수 있도록 millis() 명령을 실행한다. millis() 명령은 아두이노 보드에 전원이 들어와 코드가 실행되는 시점에서부터 시간을 msec 단위로 체크한다. 따라서 Processing  코드로부터 request 가 들어오게 되면 loop()가 한번 실행되는 구조이므로 입력 버퍼 체크 지점에서 매번 loop() 실행 소요 시간을 계산하도록 한다.

입력 버퍼에서 Processing에서 보내는 request를 검출하기 위해서는 ’\r’ 즉 리턴 키 입력 데이터를 체크해야 한다.  즉 Processing 코드의 "  HTTP/1.0\r\n"에서 빨간색 부분에 해당한다. ASCII 문자로 이루어진 입력 버퍼 내용물을 문자열 변수 request에 담은 후 6,7,8번째 문자를 request.substring(5,8) 명령에 의해 추출하여 문자열 변수 result에 할당한다. 마지막으로 문자열 데이터를 result.toInt() 명령에 의해 정수로 변환 후 brightness 로 두어 이 값을 가지고 analogWrite(ledPin,brightness) 명령을 실행하여 LED 의 밝기를 제어한다.

analogWrite() 명령 이후의 코딩 내용이 웹서버 영역인데 현재 클라이언트가 웹이 아닌 Java 모드의 Processing 코드이므로 아두이노에서 HTML 또는 HTML+Java Script 로 이루어진 코드를 보낼 수 없다.



NodeMCU/WeMos 시리얼 모니터에서 마우스 커서를 5초에 한번 정도로 좌측에서 우측으로 스캔하면서 HTTP 통신 속도 측정 결과를 살펴보도록 하자. 4800 msec 면 적절한 값으로 판단된다.


//Client_analogWrite_LED_01

import processing.net.*;
Client c;

void setup() {
size(256, 200);
background(255);
 for (int i = 0; i < 256; i++) {
 stroke(255,i,i);
 line(i, 0, i, 150);
 }
}

void draw() {
   c = new Client(this, "192.168.0.11", 80);
   String s = "";
   s += "GET /";
   if( mouseX < 10 ) {
     s += "0";s += "0";
     s += str(mouseX);
   }
   else if( mouseX >= 10 && mouseX < 100 ) {
     s += "0";
     s += str(mouseX);
   }
   else if( mouseX >= 100 ) {
     s += str(mouseX);
   }
   else  {
   }
   s += "  HTTP/1.0\r\n";
   c.write(s);
   c.write("\r\n");

   for (int i = 0; i < 256; i++) {
    stroke(255,mouseX,mouseX);
    line(i, 150, i, 200);
   }
   delay(4800);
}//End


//WeMos_IOT_LED_ON_OFF_01

#include <ESP8266WiFi.h>

 const char* ssid = "android1234";//무선 공유기 id로 수정
 const char* password = "dddddddddd";//무선 공유기 비빌번호

 int ledPin = D3; //
 long current_Millis = 0;
 long previous_Millis = 0;
 long del_T = 0;
 WiFiServer server(80);

 void setup() {
   Serial.begin(115200);
   delay(10);

   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH);

   // Set WiFi to station mode and disconnect from an AP if it was previously connected
   WiFi.mode(WIFI_STA);
   WiFi.disconnect();
   delay(100);

   Serial.println("Setup done");

   // Connect to WiFi network
   Serial.println();
   Serial.println();
   Serial.print("Connecting to ");
   Serial.println(ssid);

   WiFi.begin(ssid, password);

   while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     Serial.print(".");
   }
   Serial.println("");
   Serial.println("WiFi connected");

   // Start the server
   server.begin();
   Serial.println("Server started");

   // Print the IP address
   Serial.print("Use this URL to connect: ");
   Serial.print("http://");
   Serial.print(WiFi.localIP());
   Serial.println("/");

 }

void loop() {
  
   WiFiClient client = server.available();
   if (!client) {
     return;
   }

   Serial.print("new client: ");
   while(!client.available())  {
     delay(1);
   }
   current_Millis = millis();
   del_T =current_Millis - previous_Millis;
   previous_Millis = current_Millis;
  
   String request = client.readStringUntil('\r');
   Serial.println(request);

  String result = request.substring(5,8);
//  Serial.println(result);
  int brightness = result.toInt();
  Serial.println(brightness);

   Serial.println(del_T);
   client.flush();

   analogWrite(ledPin, brightness);

   client.println("HTTP/1.1 200 OK");  // Return the response
   client.println("Content-Type: text/html");
   client.println("");             //  do not forget this one
   client.println("<!DOCTYPE HTML>");
   client.println("<html>");
   client.println("<body>");
// 웹서버 코드를 넣는 공간
   client.println("</body>");
   client.println("</html>");

   delay(1);
  
   Serial.println("Client disonnected");
   Serial.println("");

 }//끝