(defun org-xor (a b)
   "Exclusive or."
   (if a (not b) b))

준비물

$ tar xvfz pyserial-2.5.tar.gz
$ cd pyserial-2.5
$ sudo python setup.py install

피지컬 컴퓨팅?

피지컬 컴퓨팅 (물질의 계산?)

물질이 가지는 에너지도 미디어다!

전기 에너지는 여러 에너지를 상호 변환할 수 있는 에너지이다. 일종의 유니버설 에너지. 전기 에너지는 에너지계의 로제타석 이다.

그래서 전기를 컴퓨팅하는 마이크로 콘트롤러(예를 들어 아두이노)를 이용하면 물리적인 에너지도 컴퓨팅 할 수 있게 된다.

인터렉티션 정의

상호간에 듣고, 생각하고, 대답하는 과정. –크리스 크랙포드 (게임프로그래머)

모든 피지컬 컴퓨팅 프로젝트는 역시 '듣기, 생각하기, 대답하기'로 나눌 수 있다. 컴퓨터 용어로 입력, 프로세싱, 출력

해보기

  • 미디어 아트 프로젝트를 선택하여 입력, 프로세싱, 출력으로 구분해서 분석해보자!

1. LED와 전원

LED와 전원(코인건전지 3V)을 연결해보자. LED는 전기 에너지를 빛에너지로 바꾸는 소자이다.

해보기:

  • 질문: LED와 건전지를 연결하여 불이 켜질때, 입력은 무엇이고, 출력은 무엇이고, 프로세싱은 무엇일까?

2. LED와 USB전원

  1. 아두이노의 전원으로 사용해보자.
  2. 질문: LED를 5V(+), GND(-) 에 연결하면 잘 동작할까요? (가정-결과관찰-비교-학습)

3. 아두이노에서 LED켜기 (입력)

LED의 +를 아두이노의 D13번에 연결 합시다! 전에 LED 터뜨리셨으면 어쩔 수 없습니다! 앞으로 머리속에서 불을 키는겁니다. ㅎㅎㅎㅎ (H 옆에 LED 보이시죠? 이 LED는 D13에 연결되어 있는 LED 입니다.)

그리고 아래의 코드를 아두이노에 프로그래밍 하자.

준비물

LED 켜기

int ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);      
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(1000);
}

해보기:

  • LED를 1초에 한번씩 깜빡이도록 만드세요!

힌트: digitalWrite(ledPin, LOW);

우리는 프로그래밍을 통해 물리적 스위치 없이도 LED를 제어할 수 있습니다 (controlable). 프로그램의 무한루프는 장치가 살이 있는 것처럼 만들수 있지요 (liveness).


스위치 사용 (입력)

int buttonPin = 4;
int ledPin = 13;
boolean value;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);      
}

void loop() {
  value = digitalRead(buttonPin);
  if (value == HIGH) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
}

해보기:

  • 버튼의 입력을 받아서 LED를 켜보기에서 '프로세싱' 에 해당하는 것은 무엇일까요?

4. 모터 (출력)

LED대신 모터를 연결할 수 있습니다. 모터는 전기에너지를 운동에너지로 바꾸는 장치입니다. 멋지지 않습니까!! 19세기 전기공학자의 승리이지요! 아하하. 모터는 마이클 패러데이가 발명했군요. 네? 패럿이 좀 익숙하시다구요?

int buttonPin = 4;
int ledPin = 13;
int motorAPin = 3;
int motorBPin = 5;
boolean value;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, INPUT);
  pinMode(motorAPin, OUTPUT);   
  pinMode(motorBPin, OUTPUT);   
}

void loop() {
  value = digitalRead(buttonPin);
  if (value == LOW) {
    digitalWrite(motorAPin, HIGH);
    digitalWrite(motorBPin, LOW);
    digitalWrite(ledPin,HIGH);
  } else {
    digitalWrite(motorAPin, LOW);
    digitalWrite(motorBPin, LOW);
    digitalWrite(ledPin,LOW);
  }
}

해보기

  • 모터를 연결하여 동작이 잘되다 멈추지 않나요? 왜 잘 동작 안될까요? 그 이유를 생각해보세요. 힌트: 에너지 보존 법칙!

5. 빛센서로 LED 제어

버튼 대신 빛센서를 사용하여 LED를 제어 해보죠

빛센서와 마이크, 슬라이더는 아날로그 센서이다. 디지털 센서는 0(LOW) 와 1(HIGH)만 가져올 수 있지만, 아날로그 센서는 0부터 1023값까지 가져올 수 있다.

int cdsPin = 1;
int ledPin = 13;
int value;

void setup() {
  pinMode(cdsPin, INPUT);
  pinMode(ledPin, OUTPUT);   
}

void loop() {
  value = analogRead(cdsPin);
  if (value > 512) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
}

해보기:

  • 마이크와 연결해보자. 마이크의 핀번호는 0번이다. analogRead(0);
  • 슬라이더의 핀번호는 2번 이다. 슬라이더를 사용하여 LED를 제어 해보자.

6. 컴퓨터와 아두이노 사이의 통신

arduino는 컴퓨터의 USB를 통해 데이터를 주고 받을 수 있다. 이때 주고받는 통로를 시리얼 포트 라고 한다. 포트는 항구를 의미하여, 데이터를 내리고 받고 하는 곳이다. 주고 받는 데이터는 숫자다!

파이썬으로 프로그램을 버튼으로 사용하여 모터를 제어해보자

아두이노 코드

int ledPin = 13;
int value;

void setup() {
  pinMode(ledPin, OUTPUT);   
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    value = Serial.read();
    if (value == '1') { 
    digitalWrite(ledPin, HIGH);
    } else {
    digitalWrite(ledPin, LOW);
    }
  }
}

해보기:

  • 아두이노의 시리얼 모니터에서 1 또는 0의 숫자를 입력한다. 어떻게 될지 예상해보자.
  • pyserial을 설치하고, 파이썬 인터프리터에서 다음과 같이 입력해보자. 어떻게 될지 예상해보자.

\\ 시리얼포트의 이름: 코드의 '/dev/ttyUSB0' 는 시리얼포트의 이름으로 플래폼 마다 다르다. 윈도우는 'com1' 이런식이고, 맥은 '/dev/tty.usbserial-AXXXX' 이런식이다. 자신의 플랫폼에 맞추어 시리얼 포트의 이름을 바꾸자.

>>> import serial
>>> s = serial.Serial('/dev/ttyUSB0')
>>> s.write('1')
1
>>> s.write('0')
1
>>>

GUI 스위치 만들기

from Tkinter import *
import sys

import serial
port = '/dev/ttyUSB0'  # TODO: change port name
speed = 9600

def send(char):
    ser = serial.Serial(port,speed)
    ser.setDTR()
    ser.flushInput()
    ser.write(char)
    ser.close()

def toggle_switch():
    if switch_button["text"] == "Turn On":
        send('1')
        switch_button["text"] = "Trun Off"
    else:
        send('0')
        switch_button["text"] = "Turn On"

root = Tk()
root.title('Switch')
switch_button = Button(root, text="Turn On",command=toggle_switch)
switch_button.pack()

root.mainloop()

일상에서 유용한 장치 만들기

하이퍼 텍스트 커피포트 조절 장치

http://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol

트위터와 연결

7. 물이 다 끓면 트윗!

사이커피 트위터: http://twitter.com/#!/BYTT2

물이 다 끓면 사이커피 트위터에 트윗이 됩니다!

TODO: 연결 개념도 넣기.

아두이노 코드

int cdsPin = 3;
int ledPin = 13;
int value;

void setup() {
  pinMode(cdsPin, INPUT);
  pinMode(ledPin, OUTPUT);   
  Serial.begin(9600);
}

void loop() {
  value = analogRead(cdsPin);
  if (value > 700) {
    Serial.print('1');
    digitalWrite(ledPin,HIGH);
  } else {
    Serial.print('0');
    digitalWrite(ledPin,LOW);
  }
}

버튼으로 트윗!

int ledPin = 13;
int buttonPin = 4;
int value;

void setup() {
  pinMode(ledPin, OUTPUT); 
  pinMode(buttonPin, INPUT);  
  Serial.begin(9600);
}

void loop() {
  value = digitalRead(buttonPin);
  if (value == LOW) {
    Serial.print('1');
    digitalWrite(ledPin,HIGH);
  } else {
    Serial.print('0');
    digitalWrite(ledPin,LOW);
  }
}

파이썬 코드

# -*- coding: utf-8 -*-

import tweepy
from tweepy.error import *
import serial, os, random
from time import localtime, strftime

port = '/dev/ttyUSB0'
speed = 9600
coffee = '1'

def random_string():
    word = ''
    for i in range(4):
        word += random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
    return word

def receive():
    ser = serial.Serial(port,speed)
    ser.setDTR()
    ser.flushOutput()
    value = ser.read(1)
    ser.close()
    return value

CONSUMER_KEY = 'OMzEiHX57WxDcgBmqg0vzQ'
CONSUMER_SECRET = 'DdaRA8IfrVjDVr9OzxYh6vtAEHn66ECwzPWgr7Zafg'

auth = tweepy.OAuthHandler(CONSUMER_KEY,CONSUMER_SECRET)
print 'Authorization URL: ' + auth.get_authorization_url()
token = raw_input('Token:')
auth.get_access_token(token)
api = tweepy.API(auth)


while True:
  p_coffee = coffee
  coffee = receive()
  if p_coffee == '0' and coffee == '1':
      try:
          api.update_status(u'여러분, 커피가 다 되었습니다. 커피 마시러 오세요~ 장소는 문지문화원 2층 --커피봇' + random_string() + strftime(" %Y-%m-%d %H:%M:%S", localtime()))
          print 'update successed!'
      except TweepError:
          print 'update failed!'

해보기

  • 이 예제를 응용하여, 일상을 풍요롭게 할 수 장치에 대한 아이디어를 내보자! 짝과 이야기 나눠 보세요.

8. 트위터 메시지로 LED 켜기.

트위터에서 #BYTTBOT 해쉬태그로 'On' 이라는 메시지가 포스팅하면 LED가 켜진다.

아두이노 코드

시리얼포트로 '1' 이 들어오면 LED를 깜박거립니다.

int ledPin = 13;
int value;

void setup() {
  pinMode(ledPin, OUTPUT);   
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    value = Serial.read();
    if (value == '1') { 
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    } 
  }
}

파이썬 코드

트위터에서 #BYTTBOT을 검색하여 그 결과 내용에 'On' 문자열이 있으면 시리얼 포트로 '1' 을 보냅니다.

import simplejson, urllib, sys, re, time
import serial
port = '/dev/ttyUSB0'  # TODO: change port name
speed = 9600

def send(char):
    ser = serial.Serial(port,speed)
    ser.setDTR()
    ser.flushInput()
    ser.write(char)
    ser.close()

params = {'q':"#BYTTBOT"}
query = urllib.urlencode(params)

url = "http://search.twitter.com/search.json?%s" % query
timeline = set()

while True:
    time.sleep(0.5)
    results = simplejson.load(urllib.urlopen(url))['results']
    for entry in results:
        r = re.compile(r'((www\.|(http|https|ftp|news|file)+\:\/\/)[_.a-z0-9-]+\.[a-z0-9\/_:@=.+?,##%&~-]*[^.|\'|\# |!|\(|?|,| |>|<|;|\)])',re.I|re.M)
        text = r.sub('<a href="\\1">\\1</a>',entry['text'].encode( "utf-8" ))
        r = re.compile(r'(@)+([_.a-z0-9-]+)', re.I|re.M)
        text = r.sub('<a href="http://twitter.com/\\2">\\1\\2</a>',text)
        from_user = entry['from_user'].encode( "utf-8" )
        if text in timeline:
            continue
        if 'on' in text.lower():
             send('1')
             print text
        else:
             send('0')             
        timeline.add(text)

참고

Author: Donghee Park

Created: 2014-03-23 Sun 10:22

Emacs 24.3.1 (Org mode 8.2.5h)

Validate