아두이노와 Processing

Processing(프로세싱) 와이파이에 의한 아두이노 weMos 전송 값 읽기

coding art 2018. 4. 2. 17:31
728x90

이 한권의 책으로 아두이노 엘렉트로닉스 코딩에서 시작하여 와이파이 코딩을 넘어 흥미로운 앱인벤터 코딩으로 넘어가보자. 특별한 컴퓨터 과학의 지식이 없어도 누구든지 코딩의 세계로 초대 받을 수 있습니다. 교보문고에서 판매 중입니다.



















__________________________________________________________________________________________________________________________________

본문 시작


아두이노 weMos 보드에서 일정한 시간 간격으로 데이터를 발생 시키고 이 데이터 값을 데스크 톱 PC 의 Processing 코드에서 읽어 보기로 하자.


아두이노 weMos 코드에서 전송할 데이터를 발생시키는 코드 작성을 위해 필요한 변수들을 선언하자. 시간을 나타내는 실수형 변수 t, sine 함수를 사용하여 계산한 실수 데이터를 정수형으로 변환하여 SensorData 로 둔다. SensorCharMsg[4]는 SensorData를 문자열로 변환하여 저장할 어레이이다.
⚫⚫⚫
int SensorData
char SensorCharMsg[4]
float t = 0;
◾◾◾

loop()에서 이 정수 데이터를  C 명령인 itoa(SensorData, SensorCharMsg,10)를 사용하여 전송에 적합한 문자열로 바꾼다. itoa(  ,  , 10) 명령에서 10은 10진수를 의미한다. 2라면 2진수가 되는 셈이다. 반면에 실수 데이터를 생성하여 보낼 경우에는 dtorst() 명령이 사용된다.
sine  함수를 사용하여 일정 시간 간격으로 지연을 주어 함수 값을 실수로 계산하기로 한다. 이렇게 계산된 실수 값을 정수형으로 변환 후 Processing 코드로 전송하기 위해서 itoa() 명령을 사용하여 문자열(string)로 변환하자. 아래의 itoa() 명령 사용 사례에서 정수형 변수 SensorData 값을 입력하면 10진법으로 문자열 데이터 SensorCharMsg로 변환시켜 준다.


void loop()  {
◾◾◾
t = t + 0.2;
int SensorData = 128*sin(t)+128+20;
itoa(SensorData,SensorCharMsg,10);
⚫⚫⚫


전송해야할 데이터가 준비 되었으면 HTTP1.1 을 필두로 하여 아래와 같이 문자열을 구성한다. ThingSpeak을 비롯한 대부분의 사물 인터넷 통신에서 흔히 html 언어를 사용하고 있음에 유의하자.


s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPEHTML>
\r\n<html> ";
s += "<br>Volt(0-1024): ";
s += SensorCharMsg;
s += " ";
s += "</html>";


최종적으로 준비된 문자열을 시리얼 모니터에서 출력해 보면 아래와 같다.



한편 Processing  코드에서 전송받은 내용을 출력해 보면 다음과 같은 결과를 볼 수 있다.



아두이노 weMos 와 Processing 코드를 같이 실행 시키면서 전송되는 내용을 관찰하면 약간의 시간차를 두고 정확하게 전송됨을 확인할 수 있다. 한편 전송되는 내용이 아닌데 Processing에서 추가되는 “Client got end-of-stream” 메시지가 있는데 에러는 아닌 듯하다. 전송 과정에서 데이터 전송 속도 변동에 다른 메시지일지 모르겠으나 데이터 수신 자체에는 아무런 문제가 없다.

이와같은 무선 와이파이 방식의 데이터 전송에서 보내고 받는 데이터를 혼동할 우려가 없다면 불필요한 정보를 삭제하고 필요한 데이터만 보내도록 아래와 같이 간략화하기로 한다.


s = "";
s += SensorCharMsg;
s += "\n\r";


아래의 그림에서 그 결과를 참고해 보기로 하자. 대략 전송 시간 차는 1초 이내이다.



이와 같이 간략화하여 전송하면 전송받은 정보에서 데이터를 추출하기 위한 작업이 필요 없어지며 단지 문자열에서 정수나 실수로 한번 변환해 주면 된다.


데이터를 수신하는 Processing 코드를 살펴 보자.  setup() 에 new Client(⚫⚫⚫) 가 아두이노와 한번 연결이 되기 시작하면 draw() 로 넘어가서 계속적으로 연결이 이루어진다.

draw()에서 버퍼의 입력 내용을 출력하고 다시 new Client(⚫⚫⚫)가 나타나는데 이렇게 하지 않으면 코드 실행이 안 됨에 유의하자.









비슷한 코드 구조를 아두이노에서도 관찰할 수 있다. loop()를 돌 때 마다 한번씩 server 의 버퍼를 체크하여 Client를 선언한다.










1초에 1회 꼴로 sine 함수를 계산 후 전송하여 그래프로 그려본 결과이다. 전송 속도가 그다지 빠른 편은 아니므로 온습도 센서 데이터와 같은 다소 낮은 속도로 변동되는 데이터를 전송하기에 적합한 통신 성능을 보여 준다.






Webserver_weMos_Processing_sine_01


#include <ESP8266WiFi.h>

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

 String s;
 String strVolt;
 
 int ledPin = 12;
 int measurePin = 0; //A0 pin
 float t = 0;
 char SensorCharMsg[4];
 WiFiServer server(80);

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

  // prepare GPIO2
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, LOW);
    
  // 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.println(WiFi.localIP());
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
 
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
 
  // Match the request

  int val;
  if (req.indexOf("OFF") != -1)
    val = 0;
  else if (req.indexOf("GET / HTTP/1.0") != -1)  {
    val = 1;
  t = t + 0.2;
  int SensorData = 128*sin(t)+128+20;
  itoa(SensorData, SensorCharMsg, 10);
  }
  else {
    Serial.println("invalid request");
//    client.stop();
    return;
  }

  // Set GPIO2 according to the request
  digitalWrite(ledPin, val);
  client.flush();

  // Prepare the response
//  s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html> ";
//  s += "<br>Volt(0-1024): ";
//  s += SensorCharMsg;
//  s += " ";
//  s += "</html>";
  s = "";
  s += SensorCharMsg;
  s +="\n\r";
  Serial.print(s);
  client.print(s);
  delay(50);

  Serial.println("Client disonnected");

}//끝


HTTPClient_weMos_sine_01


// Graph Decoration //
int xPos = 1;         // horizontal position of the graph

//Variables to draw a continuous line.
int lastxPos=1;
int lastheight=0;

import processing.net.*;

Client c;
String data;

void setup() {
 
  size(600, 400);
  background(50);
  fill(200);
  c = new Client(this, "192.168.0.11", 80);
  c.write("GET / HTTP/1.0\r\n");
  delay(50);
}

void draw() {

  if (c.available() > 0) { // If there's incoming data from the client...
    data = c.readString(); // ...then grab it and print it
    println(data);//    c.clear();
  }
 
  if (data != null) {
//    data = trim(data);                // trim off whitespaces.
    float inByte = float(data);           // convert to a number.
    inByte = map(inByte, 0, 300, 0, height); //map to the screen height.

    //Drawing a line from Last inByte to the new one.
    stroke(127,34,255);     //stroke color
    strokeWeight(4);        //stroke wider
    line(lastxPos, lastheight, xPos, height - inByte);
    lastxPos= xPos;
    lastheight= int(height-inByte);

    // at the edge of the window, go back to the beginning:
    if (xPos >= width) {
      xPos = 0;
      lastxPos= 0;
      background(0);  //Clear the screen.
    }
    else {
      // increment the horizontal position:
      xPos++;
    }
  }
 
  c = new Client(this, "192.168.0.11", 80);
  c.write("GET / HTTP/1.0\r\n");
  delay(1000);
}