2015년 9월 6일 일요일

에너지 절약 캠패인을 위한 스마트 홈 원리에서 응용한 프로세싱(Processing) 및 아두이노

이 글은 스마트 홈 원리 교육을 위한 프로세싱(Processing)와 아두이노 활용 방법에 대해서 다룬다. 이 내용은 다음 글을 참고하였다.
실제로 에너지 절약 캠페인을 위해, 스마트 홈이란 주제로 전시한 메이커 페어 참가 프로젝트의 상세 내용은 다음 링크를 참고하길 바란다. 메이커 페어 때 작업한 스마트 홈 관련 디자인, 소스코드 및 관련 참고 자료가 포함되어 있다 (전체 구현 내용은 매우 많으므로, 이 글에서 제공하지 않는다).

1. 프로세싱 개요
프로세싱은 미디어아트에 많이 활용되는 저작 도구이다. Java기반으로 스크립트를 개발하여, 데이터를 가시화한다. 매우 많은 수의 라이브러리와 예제를 프로세싱 홈페이지 및 관련 사이트에서 제공한다. processing.js를 사용하면, 웹기반으로 동작한다.

2. 프로세싱 사용 사례
프로세싱으로 개발한 작품을 확인해 보자.


이와 같이 전문가적인 컴퓨터 그래픽스를 만들 수 있다.

3. 프로세싱 코딩
프로세싱을 이용해, 센서 데이터를 취득하고, 이를 가시화하는 다음 그림과 같은 데쉬보드를 개발해 본다.


센서 데이터는 serial 통신으로 부터 획득한다. 조도, 온도, 습도, 전류 센서를 아두이노에 연결하여, 초당 2회씩 데이터를 프로세싱으로 보낸다. 이를 가시화한다.

데이터베이스에 센서 데이터를 저장하는 원리를 간단히 보여주기 위해, sensor.txt, energy.txt 파일 두개를 사용하였다(물론, MySQL과 같은 DB를 사용할 수 있으나, 교육적 원리를 전달해 주면 충분하므로 작업이 쉬운 방법으로 처리한다). 아울러, 센서 저장 및 그래픽 출력 간격을 교육적 효과를 얻을 수 있도록 매우 짧게 설정하였다.

다음은 관련 주요 코드이다(bar chart, pie chart 및 building 그래픽은 소스에 포함하지 않았음. 앞의 링크 참고.).

/** 
 * Smart home
 */ 
import java.util.Iterator;

PFont font = createFont("Arial", 30, true);
Chart[] charts = new Chart[2];
Bar[] bars = new Bar[2];
building[] buildingz; 

PApplet pg;

void setup() {
  size(1024, 768, P3D);
  smooth();
  noStroke();
  colorMode(RGB);  // colorMode(HSB, TWO_PI, 1, 1, 1);
  
  setup_arduino();  
  
  for(int i = 0; i < charts.length; i++)
    charts[i] = new Chart();
  charts[0].initChart("Year", width * 0.8, height * 0.2, 180.0);  
  charts[1].initChart("Month", width * 0.8, height * 0.5, 180.0);  

  for(int i = 0; i < bars.length; i++)
    bars[i] = new Bar();
  bars[0].initBar("Sensor", "sensor.txt", "sensor_data.txt", width * 0.05, height * 0.62, 400, 300);
  bars[1].initBar("Energy", "energy.txt", "energy_data.txt", width * 0.55, height * 0.62, 400, 300);

  initBuilding();  
}

void draw() {
  update_arduino();
  
  background(230, 150, 30);  
  
  textFont(font);  
  String str = "Smart Home Dashboard";
  fill(0);
  text(str, width / 2, 50);  
  
  for(int i = 0; i < charts.length; i++)
    charts[i].drawChart();

  for(int i = 0; i < bars.length; i++)
    bars[i].drawBar();
    
  fill(32, 128, 32, 128);
  house(20, 300, 250, 150);
  fill(32, 128, 32, 196);  
  house(220, 200, 320, 250);  
  
  translate(90, -20);  
  for(int a=0;a<buildingz.length;a++){
    buildingz[a].dessine( );
  }  
  translate(0, 0);  
}

void initBuilding()
{
  buildingz = new building[0];  
  float decx = 270; 
  float decy = 270;
  
  float bx = 270;
  for (int b = 0; b < 4; b++){
    float mindy = 0;
    for (int a = 0; a < 4;a++){
      float x = decx; 
      float y = decy + mindy;
      new building(x, y);

      decx = decx - 76;
      mindy += 25;
    }
    decy = decy + 30;
    decx = bx + 30; 
    bx = decx;
  } 
}

void house(float x, float y, float W, float H) {
  noStroke();
  rect(x, y, W, H);
  triangle(x, y, x + W / 2, y - H / 2, x + W, y);
}

웹서버에 개발된 코드를 동작시키려면, 다음과 같이 시도해 본다.
1. 웹서버를 설치한다 (python 서버, locally).
2. processing.js 등을 다운로드 받는다.
3. index.html 파일을 다음과 같이 만든다.
<html>
<head>
<title>Hello Web</title>
<script src="processing.js"></script>
</head>
<body>
<h1>Processing.js</h1>
<p>web-based sketch:</p>
<canvas data-processing-sources="your_processing-1.pde your_processing-2.pde ..."></canvas>
</body>
</html>

4. 웹서버를 실행한다.
5. chrome에서 localhost:8080을 입력한다.

만약, 프로세싱 스케치가 로딩되지 않아, 그래픽이 표시되지 않으면, 프로세싱 파일을 하나로 합쳐본다. 이렇게 해도 로딩이 잘 안되면, 다른 종류의 웹서버를 설치해 시도해 본다.


4. 아두이노 연결
아두이노에서는 센서 데이터를 취득하거나, 릴레이와 같은 액추에이터를 제어한다.

릴레이에는 5V LED가 연결되어 있어, 간단한 스마트 전등을 구현하고 있다.
에너지 소모 데이터는 전류센서로 부터 얻도록 되어 있다. 기타, 스마트 홈에서 가전기기 조절에 필요한 온도, 습도, 조도 센서도 아두이노와 연결한다.

이렇게 연결된 센서 데이터는 energy.txt, sensor.txt로 구분해 파일로 저장하고, 이 데이터를 정해진 시간 단위로 읽어, 앞의 프로세싱으로 코딩한 스마트 홈 데쉬보드에 컴퓨터 그래픽으로 출력한다. 이런 방식으로 스마트 홈의 기본적인 기능들을 만들고, 보기 쉬운 그래픽으로 표현하여, 에너지의 중요성에 대한 교육적인 효과를 전달한다.

아래 코드의 적색 부분에서 센서값을 프로세싱과 시리얼포트로 주고 받는다.
참고로, 아두이노에서 사용한 코드들은 앞의 압축파일 링크에서 '1.공부'폴더에 저장된 참고자료들을 사용해, 적절히 조합한 것이다.

상세 코드는 다음과 같다.

// include the library code:
#include <LiquidCrystal.h>
#include <DHT.h>

// Relay pin
const int relay_pin = 7;
boolean relay_state = false;

// Define measurement variables
float amplitude_current;
float effective_value;
float effective_voltage = 230; // Set voltage to 230V (Europe) or 110V (US)
float zero_sensor;

// DHT instance
#define DHTPIN 6
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(10, 11, 2, 8, 4, 9);

// Variables to be exposed to the API
int temperature;
int humidity;
int light;
int effective_power;

void setup() {
  // Start Serial
  Serial.begin(9600); // 115200);
  
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  pinMode(relay_pin, OUTPUT);
  zero_sensor = getSensorValue(A1);
}

void loop() {
  // Measure from DHT
  temperature = dht.readTemperature(); // / 30.0;  // 4.7k Ohm. Calibration factor.
  humidity = dht.readHumidity(); // / 20.0;
  
  // Measure light level
  float sensor_reading = analogRead(A0);
  light = sensor_reading / 1024*100;

  // Perform power measurement
  float sensor_value = getSensorValue(A1) - zero_sensor; 

  // Convert to current. (ACS712T). http://arduinosensors.com/index.php/tag/allegro-acs712/
  float sensor_voltage = sensor_value * 10.0 / 1023.0;
  amplitude_current = (sensor_voltage - 2.5) / 0.186;
  effective_value = amplitude_current / 1.414;
  effective_power = abs(effective_value * effective_voltage / 1000); 

  String data;
  data = data + temperature + ", " + humidity + ", " + light + ", " + effective_power;
  Serial.println(data);

  // If the light level is less than 50 %, switch the lights off
  if (light < 50) 
  {
    digitalWrite(relay_pin, HIGH);
    relay_state = true;  
    lcd.begin(16, 2);
  }
  else
  {
    digitalWrite(relay_pin, LOW);
    relay_state = false; 
    lcd.begin(16, 2);
  }  
  
  // Display temperature
  lcd.setCursor(0,0);
  lcd.print("T:");
  lcd.print((int)temperature);
  lcd.print((char)223);

  lcd.setCursor(6,0);
  lcd.print("P:");
  lcd.print(effective_power);
  lcd.print("W     "); 

  lcd.setCursor(11,0);
  lcd.print("");
  lcd.print(sensor_voltage);
  lcd.print("V   "); 

  // Display humidity
  lcd.setCursor(0,1);
  lcd.print("H:");
  lcd.print(humidity);
  lcd.print("%");
  // Display light level
  lcd.setCursor(6,1);
  lcd.print("L:");
  lcd.print(light);
  lcd.print("%");  


  delay(200);
}

// Get the reading from the current sensor
float getSensorValue(int pin)
{
  int sensorValue;
  float avgSensor = 0;
  int nb_measurements = 100;
  for (int i = 0; i < nb_measurements; i++) {
    sensorValue = analogRead(pin);
    avgSensor = avgSensor + float(sensorValue);
  }
  avgSensor = avgSensor / float(nb_measurements);
  return avgSensor;
}


5. 마무리
프로세싱은 시리얼 장치, 센서, 카메라, 키텍트 등과 같은 다양한 입출력 장치 및 관련 라이브러리를 지원할 뿐만 아니라, javascript기반 node.js를 이용해, 웹 상에서 스마트폰 같은 다양한 장치를 통해, 작품을 렌더링할 수 있는 강력한 도구이다. 이를 잘 활용하면, 매력적인 그래픽스 영상을 개발할 수 있다.

댓글 없음:

댓글 쓰기