2015년 4월 15일 수요일

WS2812 color LED 사용하기

칼라 LED는 LED 내부에 빛의 3원색에 해당하는 Red, Green, Blue LED가 들어있어 각각의 밝기를 조절하면 원하는 색을 만들어 낼 수 있다. 일반적인 형태의 칼라 LED는 아래 사진과 같은 형태로 4개의 다리가 나와 있다. Common Anode 타입의 LED인 경우 가장 긴 다리가 common anode로 이 다리는 +에 연결되어야 하고 나머지 3개의 다리는 프로세서의 I/O에 연결해 LED를 제어한다. 각 IO핀이 LOW면 해당 LED가 켜지고, HIGH면 LED가 꺼지게 된다. (PWM의 경우 duty가 0%면 가장 밝게 켜지고 100%면 꺼짐)



반대로 common cathode 타입의 LED인 경우, common cathode는 GND에 연결하고 나머지 3개 다리는 프로세서의 I/O에 연결한다. 이 경우 common anode와 반대로 IO핀이 HIGH이면 해당 LED가 켜지고, LOW면 LED가 꺼지게 된다. (PWM의 경우 duty가 100%면 가장 밝게 켜지고 0%면 꺼짐)

아래 그림은 common cathode타입의 컬러 LED를 사용할 때의 연결이다. 



보통 위와 같이 전류제한 용으로 저항이 필요하다. 

이제 LED가 연결되면 컬러 LED를 제어하는 2가지 방법이 있다. 첫번째는 GPIO를 이용하는 것으로, 이 경우 각각 IO핀은 2개의 상태, LOW(0V)/HIGH(Vcc),를 가질 수 있으므로 총 8개의 다른 색(검은색 포함해서)을 낼 수 있다.



다른 방법으로는 각 색깔별 LED의 밝기를 조절하는 것이다. PWM을 사용해 각각의 밝기를 조절하면 매우 다양한 색을 만들어 낼 수가 있게 된다.
아두이노의 경우 6개의 8-bit PWM 채널을 가지고 있기 때문에, 각 PWM은 0~255 사이의 값을 가질 수 있다. 그러므로 칼라 LED에 3개의 PWM 채널이 연결되기 때문에 총 256*256*256=16,777,216가지의 조합이 만들어 질 수 있다. 



이 방법은 원하는 색을 만들어 낼 수 있지만, 단점은 칼라 LED 하나당 3개씩의 PWM 채널이 필요하다는 것이다. 아두이노 우노의 경우 6개, 메가의 경우 14개의 PWM을 가지고 있기 때문에 각각 2개, 4개의 칼라 LED밖에 연결할 수 없다. 물론 쉬프트 레지스터나 멀티플렉서등을 사용해서 더 많은 칼라 LED를 연결하는 방법이 있긴 해도 금새 매우 복잡해진다.

WS2812-based LED

Worldsemi라는 회사에서 이런 문제점을 완전히 해결해주는 새로운 칩을 만들었다. 처음에 만든것은 WS2811이라는 SMD IC로 내부에 시리얼 통신, 3개의 8-bit PWM 채널, 전류제한회로등을 가지고 있다.
다음으로 만든것은 WS2812로 5mm*5mm 정사각형 패키지 안에 WS2811에 추가로 고휘도 RGB LED를 다 집어 넣어 버렸다. 



이 칩의 가장 좋은 점은 단지 4개의 핀(GND, Power(5V), Data In, Data Out)만 있으면 된다는 것이다. 즉 이 칩은 서로 daisy-chain으로 여러개를 연결해 줄 수 있다. 프로세서가 체인의 첫번째 칩의 Data-In을 구동하고, 첫번째 칩의 Data-Out이 두번째 칩의 Data-In을 다시 구동하는 식이다. 다음 그림을 보면 좀 더 이해하기 쉬울 것이다.



이런식으로 체인으로 연결하는데 특별히 칩 갯수 제한은 없다. 
프로세서는 24-bit 값을 연속으로 보내게 되는데, 각 24-bit 값은 3개의 8-bit RGB 값을 나타낸다. 프로세서가 매번 24-bit 값을 보낼때마다 이 값은 체인의 첫번째 LED에 로드된다. 동시에 첫번째 LED는 자신이 가지고 있던 24-bit값을 두번째 LED로 전달한다. 두번째 LED는 세번째 LED로, 세번째 LED는 4번째 LED로 전달해 결국 값은 체인의 맨 마지막까지 전달되게 된다. 이 모든 작업이 매우 빠르게 진행되기 때문에 사람 눈에는 순식간에 일어난 것으로 보이게 된다. 
결과적으로 프로세서의 IO 핀 1개(PWM이 아닌 일반 GPIO핀)만으로 수백개의 칼라 LED를 제어할 수 있게 된다.
여러 회사들이 이 Worldsemi의 WS2812를 사용해 제품을 만들어 판매하고 있다. Adafruit의 경우 NeoPixels라는 이름의 제품군을 만들었다. 이 NeoPixels에는 다양한 형태의 패키지가 있다. 아래는 NeoPixels Ring이다.



위의 NeoPixel Ring은 16개의 WS2812를 가지고 있지만 12, 24, 60개짜리도 판매하고 있다. 

또한 aliexpress에 보면 아래와 같이 띠 형태의 WS2812 LED도 판매하고 있다. 아래 사진은 1m당 30개씩의 WS2812가 붙어있는 제품인데, 1m당 60개 또는 1m당 144개의 WS2812가 붙어있는 제품들도 구할 수 있다.




Feel the power!

보통 LED는 상대적으로 적은 전류를 소모한다고 생각하기 쉽지만, 여러개의 LED를 구동하려면 얼마나 많은 전류가 필요한지 알게되면 놀랄것이다. 각 NeoPixel은 최대 60mA(3개의 LED가 최대밝기일때, 즉 밝은 흰색인 경우)를 소모한다. 즉 프로세서의 전원을 컴퓨터의 USB포트에서 뽑아오거나 작은 아답터를 사용하는 경우 몇개의 WS2812를 구동할 수 있는가가 제한되게 된다. 만일 256개의 WS2812를 사용한다면 최대 15A를 전류를 사용할 수 있기 때문에 전원도 그에 맞게 준비해 줘야만 한다. 

여기서는 두가지 매우 중요한 포인트를 이야기하겠다. 첫번째는 NeoPixel에 전원을 공급하는 파워서플라이의 +와 GND 단자 사이에 1000uF의 전해콘덴서를 연결해 줘야 한다는 것이다. 두번째는 프로세서와 NeoPixel의 첫번째 data in 사이에 300~500오옴 저항을 직렬로 연결해 줘야 한다.  (보통 390오옴을 사용) 

스트립에 WS2812가 몇개 안되는 경우는 다음과 같이 USB에서 전원을 공급받아도 충분하다.


하지만 WS2812의 갯수가 많아지거나 (5~6개 이상), 아두이노 미니 3.3V등을 사용하는 경우는 아래와 같이 별도의 5V 아답터를 사용해 줘야 한다. 아답터의 용량은 충분한 전류를 흘려줄 수 있는 것을 사용해야 한다. (LED 개당 최대 60mA를 사용하므로 WS2812 갯수 * 0.06A 보다 조금 더 큰 용량을 사용한다. 즉 WS2812가 16개 붙어있다고 하면 16*0.06A = 0.96A 가 되므로 최소한 1A 이상의 아답터를 사용하는것이 좋다.)



Timing is everything

WS2812 기반의 LED를 사용하려면 가장 쉬운 방법은 믿을만한 라이브러리를 사용하고 그 중 다른 사람에 의해 테스트 된 함수를 사용하는 것이다. Adafruit NeoPixel 라이브러리를 권장한다.

중요한점은 이 라이브러리는 아두이노 우노와 메가에서 사용될 수 있도록 하드코딩 되었다는 것이다. 여기서 ‘하드코딩’의 믜미는 이 라이브러리 함수는 타이밍을 정확하게 맞추기 위해 어셈블리 코드를 사용하고 있다는 것이다. 그 결과 매우 사용하기 쉬운 라이브러리가 만들어졌지만, 아두이노 패밀리의 다른 보드에 바로 사용할 수 없을수도 있다. 또한 이 라이브러리 함수는 한가지 목적을 가지고 만들어졌기 때문에 NeoPixel 스트링에 새 값을 보내기 위한 함수를 호출하면 가장 먼저 모든 인터럽트를 비활성화 시킨다. 인터럽트를 사용하지 않는 경우는 문제가 없지만, 코드에서 인터럽트를 많이 활용한다면 큰 문제가 될 수도 있다.

Example programs using the Adafruit Library

Ex1) Lighting the pixels one after the other

#include <Adafruit_NeoPixel.h>

#define pinPix 12 // WS2812에 연결하는데 사용하는 pin 번호
#define numPix 16 // 링에 연결되어 있는 WS2812 LED 갯수

// Parameter 1 = 링에 연결되어 있는 WS2812 LED 갯수
// Parameter 2 = WS2812에 연결하는데 사용하는 pin 번호
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

Adafruit_NeoPixel myLeds = Adafruit_NeoPixel(numPix, pinPix, NEO_GRB + NEO_KHZ800);

void setup() {
  myLeds.begin(); // Initialize the NeoPixel array in the Arduino's memory,
  myLeds.show(); // turn all pixels off, and upload to ring or string
}

void loop() {
  int pause = 100;

  for (int i=0; i<numPix; i++) { 
    myLeds.setPixelColor(i,255,255,255);
    myLeds.show();
    delay(pause);
  }

  for (int i=0; i<numPix; i++) {
    myLeds.setPixelColor(i,0,0,0);
    myLeds.show();
    delay(pause);
  }
}

코드의 맨 처음은 Adafruit NeoPixel 라이브러리를 include 하는걸로 시작한다.

#include <Adafruit_NeoPixel.h>

다음은 WS2812에 데이터를 보내기 위해 사용하는 핀 번호와, 링이나 스트립에 몇개의 WS2812 LED가 붙어있는가를 정의한다. 여기서는 각각 12번 핀과 16개의 LED를 사용한다.

#define pinPix 12
#define numPix 16

정의가 끝나면 WS2812 LED 오브젝트를 인스턴스화 해 줘야 한다. 여기서는 인스턴스의 이름을 myLeds로 한다.

Adafruit_NeoPixel myLeds = Adafruit_NeoPixel(numPix, pinPix, NEO_GRB + NEO_KHZ800);

첫번째 파라미터(numPix)는 링/스트립에 붙어있는 WS2812 LED 갯수이다. 두번째 파라미터(pinPix)는 WS2812의 Data In에 연결된 핀 번호이다. 일단 여기서 세번째 파라미터는 신경쓰지 말고 넘어간다.

setup() 함수에서 가장 먼저 begin() 함수를 호출해 아두이노에 스트링을 위한 메모리를 초기화 한다. 그리고 show()를 호출해 스트링을 초기화 해 준다. 

void setup() {
  myLeds.begin();
  myLeds.show();
}

이제 잠시 쉬면서 지금까지의 내용을 정리해 보자. 인스턴스화와 초기화 단계의 일부분으로 Adafruit 라이브러리는 아두이노 메모리에 배열을 만든다. 이 배열은 링/스트링의 WS2812 LED 갯수와 같은 크기가 된다. 아래 그림은 위의 예제에서 16개를 사용한 경우의 배열을 도식화 한 것이다. 



각 24-bit 항목은 3개의 8-bit 서브필드로 구성되어 있고, 각 서브필드가 항목의 R, G, B 값을 나타낸다. Adafruit 라이브러리는 4개의 파라미터를 받아들이는 setPixelColor()라는 함수를 가지고 있다. 첫번째 파라미터는 값을 변경하길 원하는 WS2812 LED의 인덱스(여기서는 0~15 사이의 값)이고 나머지 3개의 파라미터는 원하는 R,G,B 값이다. 또한 중요한 것은 setPixelColor() 함수는 단지 아두이노 메모리에 있는 배열의 값만을 바꿀 뿐이라는 것이다. 값을 변경한 후 show() 함수를 호출해 배열에 들어있는 값들을 실제 WS2812 링/스트립에 전달해 주지 않으면 LED의 색은 바뀌지 않는다.

void loop() {
  int pause = 100;

  for (int i=0;i<numPix;i++) {
    myLeds.setPixelColor(i, 255,255,255);
    myLeds.show();
    delay(pause);
  }

  for (int i=0;i<numPix;i++) {
    myLeds.setPixelColor(i, 0,0,0);
    myLeds.show();
    delay(pause);
  }
}

첫번째 for 루프에서는 각 LED를 100ms 간격으로 하나씩 흰색(255,255,255)으로 켜 준다. setPixelColor로 색을 변경한 후에 show()를 호출하는걸 잊으면 안된다. 
두번째 for 루프에서는 각 LED를 100ms 간격으로 하나씩 검은색(0,0,0)으로 바꿔준다.

Ex2) Lighting all the pixels simultaneosly

#include <Adafruit_NeoPixel.h> // Library for NeoPixels

#define pinPix 12 // Pin driving NeoPixel Ring or String
#define numPix 16 // Number of NeoPixels in the Ring or Strip

Adafruit_NeoPixel myLeds = Adafruit_NeoPixel(numPix, pinPix, NEO_GRB + NEO_KHZ800);

void setup() {
  myLeds.begin(); // Initialize the NeoPixel array in the Arduino's memory,  
  myLeds.show(); // turn all pixels off, and upload to ring or string
}

void loop() {
  for (int i=0; i<numPix; i++) {
    myLeds.setPixelColor(i,255,255,255);
  }
  myLeds.show();
  delay(pause);

  for (int i=0; i<numPix; i++) {
    myLeds.setPixelColor(i,0,0,0);
  }
  myLeds.show();
  delay(pause);
}

1번 예제와 거의 유사하지만 이번에는 show()와 delay() 함수를 for 루프 바깥으로 빼 냈다. 즉 for 루프에서 setPixelColor() 함수로 아두이노 메모리에 있는 모든 배열의 값을 변경한 다음에 show()를 호출해 변경된 값을 한꺼번에 LED에 반영시키는 것이다. 






2015년 4월 10일 금요일

ESP8266 모듈/보드들 (Various kinds of ESP8266 module/board)

ESP8266을 사용해 보려면 여러 종류의 모듈들이 나와 있다.

가장 먼저 나온게 ESP-01(보통 ESP8266 모듈이라고 하면 이걸 말함)인데 시리얼 핀 이외에 GPIO핀이 연결된게 몇개 없어 Wifi-to-Serial 모듈 이외 용도로 사용하기는 좀 불편(?)하다. 

그래서 그 후 GPIO핀이 패드로 많이 나와 있는 모듈들이 나왔다. ESP-12/07같은 모듈이다.





핀헤더 소켓을 땜질할 수 있는 스루홀까지 가지고 있는 센스 덕에 사용하기 편리하다. 

하지만 핀 피치가 일반적으로 만능기판이나 빵판에 사용되는 2.54mm가 아니라 헤더소켓을 뗌질해도 바로 꼽을 수가 없는 단점이 있다. 그래서 이런 컨버젼 기판도 판매되고 있다.




기판 뒤쪽에 땜질은 되어 있지 않지만 3.3V 레귤레이터를 붙일 수 있는 패드까지 나와 있어 레귤레이터를 붙이면 5V에도 바로 사용할 수 있게 되어 있다.

Aliexpress에서 구매하면 ESP-12 모듈이 개당 $2.6~3 정도, 컨버젼 기판은 개당 $1 이하로 구매 가능하다. 

그리고 땜질도 귀찮고 어짜피 실험하려면 빵판에 꼽은 다음 LED라도 연결해야 하는데 그것도 싫으면 이런 테스트 모듈도 판매되고 있다. (대략 $5~6정도)





각 GPIO핀에 LED가 연결되어 있고 3핀에는 PWM 테스트용으로 컬러LED도 연결되어 있다. 그리고 ADC 테스트용 CDS(조도센서)도 붙어있고, 배터리 소켓도 같이 들어있어 AA배터리 3개를 넣어주면 저 자체로 독립적인 센서 모듈로 사용할수도 있다.

ESP8266에 대한 소개는 http://arsviator.blogspot.kr/2015/01/iot-esp8266.html, 테스트 보드에 대한 상세한 사항은 http://arsviator.blogspot.kr/2015/03/esp8266-test-board.html 를 참고하면 된다.

2015년 4월 3일 금요일

파이선에서 *args와 **kwargs

*args는 함수에 임의 갯수의 argument를 넘겨주기 위해 사용된다. '임의의' 라는 단어가 여기서 매우 중요하고 기본적으로 파이선에서 *args의 역할을 이해하는 키가 된다. 
새로운것을 배우는 가장 좋은 방법은 실제로 사용해 보는 것이다. 간단한 예제로 multiply 함수를 만들길 원한다고 가정하자. Multiply 함수는 여러개의 argument를 인자로 받아 모두 곱한 결과를 화면에 출력한다. 하지만 이 함수가 몇개의 argument를 인자로 받는지 모른다. 그러므로 파이선 식으로 이 문제를 어떻게 해결할 수 있을까? *args에 대해 이미 알고 있다면 별로 어렵지 않다. multiply함수를 아래와 같이 정의하면서 *args를 인자로 넘겨주면 된다.

def multiply(*args):
  pass

하지만 multiply 함수를 만들기 전에 파이선 인터프리터 쉘을 열어 다음 코드를 실행해본다. 

def echo_args(*args):
  for arg in args:
    print arg

'*'는 args를 iterable로 만들어주어 for 루프를 실행해 args list 안에 있는 모든 argument를 처리할 수 있다는걸 의미한다. 예를 들어 echo_args 함수에 1,2,3을 argument로 넘겨주면 화면에 다음과 같이 출력되는걸 볼 수 있다.

>>> echo_args(1,2,3)
1
2
3
>>> 

이제 *args에 대해 명확하게 이해했을것이라 생각한다. 마지막으로 multiply 함수를 완성해 본다. operator에서 mul과 functools에서 reduce를 import한다.

from operator import mul
from functools import reduce

def multiply(*args):
  return reduce(mul, args)

* mul과 reduce는 *args와는 아무 관계가 없다. 단지 함수를 만드는걸 도와주는 툴일 뿐이다.

정리하자면 *args는 사용자에 의해 함수에 몇개의 argument가 넘겨질 지 모를때 사용된다. 

def get_arguments(a, *args):
  print "The first argument is ", a
  for arg in args:
    print "This argument come from args: ", arg

다음은 위의 함수 get_argements의 사용 예이다.

>>> get_arguments(13,13,13)
The first argument is 13
This argument come from args: 13
This argument come from args: 13
>>>

이제 elements라는 변수에 몇개의 element를 가지는 tuple을 만들어준다.

>>> elements = (1, 2, 3)
>>>

그리고 elements를 get_arguments에 넣어 호출해 본다.

>>> get_arguments(elements)
The first argument is (1, 2, 3)
>>>

위의 출력 결과에서 볼 수 있는것처럼 elements를 함수에 넘겨주면 elements가 a에 할당된다.
그럼 다음과 같이 하면 어떻게 되는가 보자.

>>> get_arguments(*elements)
The first argument is 1
This argument come from args: 2
This argument come from args: 3

'*'는 튜플 elements를 unpack하기 때문에 get_arguments(1,2,3)을 호출한것과 같은 의미가 된다. 

----------------------

**kwargs는 *args와 마찬가지로 함수 선언에 사용되는 마법 변수지만 차이점은 함수에 keyworded argement를 넘겨줄 수 있는 것이다.

예제를 보도록 하자.

def display_stuff(**kwargs):
  if kwargs is not None:
    print kwargs

이제 다음과 같이 함수를 호출해 본다.

>>> display_stuff(name='Jeff', passion='development', language='python')
{'passion': 'development', 'name': 'Jeff', 'language': 'python'}
>>>

결과에서 볼 수 있는것처럼 **kwargs는 함수에 임의의 keyworded arguemts를 넘겨줘 함수 내에서 dictionary로 억세스 할 수 있게 해 준다. 예를들어 다음의 코드를 사용하면 키 'passion'에 대한 값을 쉽게 출력할 수 있다.

def display_stuff(**kwargs):
  if kwargs is not None:
    print kwargs['passion']

이제 다시 함수를 호출해 본다.

>>> display_stuff(name='Jeff', passion='development', language='python')
development
>>>

하지만 kwargs dictionary에 'passion' 키가 없는 경우는 어떻게 될까? KeyError가 발생하게 된다. 

>>> display_stuff(error='KeyError')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in display_stuff
KeyError: 'passion'
>>>

에러를 피하고 싶으면 kwargs를 확인할 때 억세스하려는 키가 dictionary에 존재하는지 체크할 수 있다.

def display_stuff(**kwargs):
  if kwargs is not None and 'passion' in kwargs:
    print kwargs['passion']

함수를 위와 같이 바꾸면 'passion' 키가 없어도 더 이상 KeyError가 발생하지 않는다. 

dictionary 내의 모든 키와 값을 출력하고 싶으면 다음과 같이 하면 된다.

def display_stuff(**kwargs):
  if kwargs is not None:
    for key, value in kwargs.items():
      print key, '==>', value

이제 실행해 본다.

>>> display_stuff(name='Jeff', passion='development')
passion ==> developer
name ==> Jeff
>>>

지금까지 본 것 처럼 *args와 **kwargs는 둘의 차이점을 이해하고 잘 사용하면 파이선 프로그래밍에 매우 유용하다.

Raspberry Pi를 Tor relay로 사용하기


TOR(The Onion Router)는 온라인상에서 익명성을 보장하기 위한 시스템이다. Tor 클라이언트는 인터넷 트래픽을 직접 보내는 대신 전세계에 퍼져있는 Tor 네트웍을 통해 나눠 보내기 때문에 사용자의 위치나 내용을 감시하거나 분석하기 매우 힘들게 만든다.

그러므로 TOR가 제대로 기능하려면 매우 많은 서버가 필요하고, TOR 네트웍은 상업적 기관이 아니기 때문에 자발적인 지원자를 필요로 한다. 라즈베리 파이를 TOR 릴레이로 동작하게 만들어 자발적인 지원자들중에 한명이 될 수 있다.

먼저 'tor' 어카운트를 만들어 준다.

$ sudo adduser tor
$ sudo passwd tor

위의 명령을 입력해 tor 어카운트의 암호를 설정해준다.

다음은 tor 어카운트를 sudoers 파일에 넣어준다.

$ sudo vi /etc/sudoers

에디터로 파일을 오픈한 다음 맨 마지막에 다음을 추가해준다.

tor ALL = (ALL) ALL

그리고 시스템을 최신 내용으로 업데이트 해 준다.

$ sudo apt-get update
$ sudo apt-get upgrade

다음은 네트웍 설정을 dhcp 대신 static으로 변경해준다.

$ ifconfig
...
eth0 Link encap: Ethernet HWaddr 00:23:54:40:56:dc
        inet addr: 192.168.0.20 Bcast: 192.168.0.255 Mask: 255.255.255.0
...
$

위에서 inet addr과 mask를 어디에 써 놓는다.

그 다음 에디터로 /etc/network/interfaces 파일을 열어 내용을 수정한다.

$ vi /etc/network/interfaces

파일 내용에서 'iface eth0 inet dhcp' 라는 부분을 찾을 수 있을 것이다. 라즈베리 파이가 IP주소를 DHCP 서버에서 받아오도록 설정되어 있는데 이걸 static IP로 바꿔주는 것이다. 'iface eth0 inet dhcp'를 다음 내용으로 바꿔준다.

iface eth0 inet static
address 192.168.0.20
netmask 255.255.255.0
gateway 192.168.0.1

'address' 부분에는 라즈베리 파이가 사용할 IP주소를 써 준다. 원하는 주소를 고르면 되지만 가장 쉬운건 아까 위에서 적어 놓은 주소를 그대로 쓰는 것이다.
'netmask'는 아까 위에서 적은 내용을 그대로 써 준다.
'gateway'는 공유기의 IP주소이다.

 네트웍 설정이 끝났으면 이제 tor를 설치한다.

$ sudo apt-get install tor

설치가 끝나면 TOR 설정파일을 수정해 줄 필요가 있다. 설정파일 위치는 /etc/tor/torrc이다.
에디터로 열어 다음 내용을 필요에 따라 추가/수정해 준다.

SocketPort 0
Log notice file /var/log/tor/notices.log
RunAsDaemon 1
ORPort 9001
DirPort 9030
ExitPolicy reject *:*
Nickname xxx
RelayBandwidthRate 100KB    # Throttle traffic to 100KB/s
RelayBandwidthBurst 200KB   # But allow bursts up to 200KB/s

그리고 거의 모든 사람들이 공유기나 방화벽을 사용하고 있기 때문에, 그 경우는 공유기/방화벽 설정을 조정해 줄 필요가 있다. TOR 네트웍의 다른 노드들이 자신의 TOR 릴레이에 연결할 수 있도록 하려면 9030과 9001 포트를 열어줘야 한다. 9030은 디렉토리 서비스를 위해 필요하고, 9001은 릴레이 동작을 위해 필요하다. 이 부분의 설정은 각자 공유기/방화벽 메뉴얼을 참조해야 한다.

설정이 완료되었으면 tor 서버를 재시동 해 줘야 한다.

$ sudo /etc/init.d/tor restart

TOR가 재시동 되었다. 정상적으로 동작하는지 확인하려면 로그파일(/var/log/tor/log)을 보면 된다. 맨 끝쪽에 다음과 같은 내용이 있으면 모든것이 완료된 것이다.

Oct 18 22:59:21.104 [notice] Tor has successfully opened a circuit. Looks like client functionality is working.

---------------------------------------------------------

브라우져가 TOR를 사용하도록 설정



TOR를 사용하려면 TOR 클라이언트가 필요하다. TOR 클라이언트는 모든 인터넷 트래픽을 Tor 네트웍으로 라우팅 해 준다. 당신의 존재를 인터넷에서 '안 보이게' 하기 위해 트래픽은 랜덤하게 선택된 여러 릴레이를 거친 후 TOR 네트웍을 빠져나가 목적지에 도착한다. 이렇게 하기 때문에 ISP 또는 네트웍을 모니터링 하는 사람이 당신이 어떤 웹사이트를 억세스 하는지 볼 수 없다. 또한 웹사이트가 당신의 실제 위치나 IP주소를 알 수 없게 해 준다. 심지어 릴레이 조차도 현재 전달하는 트래픽이 누가 요청한 것인지 알 수 없다. Tor 네트웍 내의 모든 트래픽은 암호화 된다.

위의 그림이 어떤 식으로 동작하는지 보여준다.

예를 들어 Tor를 통해 instructables.com을 억세스 한다고 해 보자. ISP는 당신이 이 사이트를 억세스 하고 있는걸 알 수 없다. ISP가 볼 수 있는건 단지 암호화 된 Tor 트래픽일 뿐이다. Tor 릴레이는 당신의 트래픽이 마침내 exit node에 도달할 때 까지 트래픽을 계속 전달한다. Exit node가 당신 대신 instructables.com과 통신을 하게 된다. - instructables.com 입장에서 보면 자신을 억세스 한건 당신이 아니고 exit node일 뿐이다. instructables.com에서 응답을 받으면 exit node는 그 응답을 릴레이에게 돌려보내준다. 하지만 릴레이도 돌려보내는 트래픽이 실제로 어디서 끝나는지는 알 수가 없다.

이런식으로 Tor는 익명성을 보장해 검열에서 자유롭게 해 준다.

하지만 이 모든 훌륭한 기능에는 댓가가 따른다. Tor를 사용하면 인터넷 억세스 속도가 느려진다. 그러므로 유튜브 접근을 막아놓은 나라에서도 유튜브 비디오를 볼 수는 있더라도, 비디오가 로드될 때 까지 상당한 시간이 걸릴 수 있다.

각 OS별 Tor 클라이언트는 다음 주소에서 받을 수 있다.

Windows: https://www.torproject.org/docs/tor-doc-windows.html.en

Linux/Unix/BSD: https://www.torproject.org/docs/tor-doc-unix.html.en

Debian/Ubuntu: https://www.torproject.org/docs/debian.html.en

Mac OSX: https://www.torproject.org/docs/tor-doc-osx.html.en

Android: https://www.torproject.org/docs/android.html.en



2015년 4월 2일 목요일

파이선으로 만들어보는 간단한 MQTT 클라이언트

MQTT 브로커는 mosquitto나 rsmb같이 무료로 쉽게 구해 설치할 수 있다. 하지만 아직 설치하지 않았다면 테스트를 위해 공개되어 있는 브로커를 사용해도 된다.
공개 브로커 목록은 http://mqtt.org/wiki/doku.php/public_brokers 에서 확인할 수 있다.

MQTT 클라이언트는 publisher이건 subscriber이건 모두 다 브로커에 연결해야 한다. 브로커를 누구나 글을 붙이거나 읽을 수 있는 일종의 공개 게시판이라고 생각하면 된다.

여기서는 파이선 2.7을 사용해 간단한 MQTT 클라이언트를 만들어 MQTT 프로토콜을 직접 사용해 보도록 한다.



1. 인스톨

pip가 설치되어 있어야 한다. pip는 파이선 모듈을 설치하는데 귀찮은 문제들을 손쉽게 해결해주는 툴이다. 만일 설치되어 있지 않다면 아래 명령으로 pip를 설치한다.

$ sudo apt-get install python-pip

다음은 MQTT broker Mosquitto (지금은 Paho로 이름이 바뀌었음)

$ pip install paho-mqtt

2. Subscribe

아래는 로컬 머신에서 실행되고 있는 브로커에 토픽을 구독(subscribe)하기 위한 파이선 코드이다.

$ cat sub.py
import paho.mqtt.client as mqtt

# 클라이언트가 서버에게서 CONNACK 응답을 받을 때 호출되는 콜백
def on_connect(client, userdata, flags, rc):
  print ("Connected with result coe " + str(rc))
  client.subscribe("hello/world")

# 서버에게서 PUBLISH 메시지를 받을 때 호출되는 콜백
def on_message(client, userdata, msg):
  print "Topic: ", msg.topic + '\nMessage: ' + str(msg.payload)

client = mqtt.Client()        # MQTT Client 오브젝트 생성
client.on_connect = on_connect     # on_connect callback 설정
client.on_message = on_message   # on_message callback 설정

client.connect("test.mosquitto.org", 1883, 60)   # MQTT 서버에 연결

# 네트웍 트래픽을 처리, 콜백 디스패치, 재접속 등을 수행하는 블러킹 함수
# 멀티스레드 인터페이스나 수동 인터페이스를 위한 다른 loop*() 함수도 있음
client.loop_forever()
$


3. Publish

이제 /hello/world 토픽을 구독(subscribe)해서 해당 토픽의 메시지가 publish(발행)되기를 기다리는 노드를 만들었다. 아래 코드는 /hello/world 토픽으로 메시지를 발행하는 간단한 코드이다.

$ cat pub.py
import paho.mqtt.client as mqtt

mqttc = mqtt.Client("python_pub")      # MQTT Client 오브젝트 생성
mqttc.connect("test.mosquitto.org", 1883)    # MQTT 서버에 연결
mqttc.publish("hello/world", "Hello World!")  # 'hello/world' 토픽에 "Hello World!"라는 메시지 발행
mqttc.loop(2)        # timeout = 2초
$

4. 테스트

2번의 코드를 'sub.py'라는 이름으로 저장하고 3번의 코드를 'pub.py'라는 이름으로 저장했다면 터미널 창에서 'python sub.py'로 sub.py를 실행하고, 다른 터미널 창에서 'python pub.py'로 pub.py를 실행해 보면 sub.py를 실행한 창에 수신된 메시지가 표시되는걸 확인할 수 있을 것이다.

MQTT는 클라이언트/서버 모델처럼 publisher와 subscriber간에 1:1 연결이 아니기 때문에 여러 창에서 'sub.py'를 실행하고 난 후 'pub.py'를 실행하면 'sub.py'를 실행한 모든 창에 메시지가 수신되게 된다.

Raspberry Pi gpio 유틸리티

WiringPi는 gpio라는 이름의 유틸리티를 포함하고 있다. 이 프로그램은 GPIO 핀을 조작하기 위한 스크립트에도 사용될 수 있다. 심지어 쉘 스크립트로 gpio 명령을 사용해 전체 프로그램을 작성할 수도 있다. 물론 이 방법은 효율적이지 않아 크게 권장하는 방법은 아니다. 또한 C/C++에서 system() 함수를 사용해 gpio 프로그램을 호출할 수도 있다.

* gpio 명령은 setuid 프로그램으로 설치되도록 만들어져 있기 때문에 일반 사용자가 sudo 명령 없이 (또는 root 권한 없이) 실행할 수 있다.

gpio 프로그램을 사용하면 GPIO 핀을 제어하는것 뿐 아니고 다음의 기능들을 수행할 수 있다.

* /sys/class/gpio 인터페이스를 통한 핀들의 export/unexport
* /sys/class/gpio 인터페이스를 통해 edge-trigger 인터럽트를 활성화
* SPI, I2C 모듈을 로드하여 read/write
* SPI 버퍼 사이즈나 I2C 속도를 설정
* Gertboard DAC로 값 출력
* Gertboard ADC 값 입력
* Raspberry Pi 보드 하드웨어 리비젼 확인

기본 사용법

$ gpio -v

버젼을 출력한다

$ gpio -g ...

-g 플래그를 사용하면 핀 번호를 wiringPi의 핀 번호 대신 BCM_GPIO 핀 번호로 인식하게 함

표준 입/출력 명령

$ gpio mode <pin> in/out/pwm/up/down/tri

핀의 모드를 설정한다. 설정 가능한 모드는 입력(in), 출력(out), PWM(pwm)이고 추가로 내부 저항의 풀업(up), 풀다운(down), Tri-state(tri) 설정이 가능하다.

$ gpio write <pin> 0/1

핀의 출력 레벨을 HIGH(1) 또는 LOW(0)으로 설정한다.

$ gpio read <pin>

핀의 레벨을 읽어 화면에 출력해준다. LOW면 '0', HIGH면 '1'이 출력된다.

$ gpio readall

정상적으로 억세스 가능한 모든 핀들을 읽어 테이블 형태로 핀 번호(wiringPi 번호 및 BCM_GPIO)와 모드, 현 입력값을 화면에 출력해 준다.

모듈 로드 명령

$ gpio load spi [buffer size in KB]

SPI 커널 모듈을 로드하고 옵션으로 내부 버퍼 사이즈를 KB 단위로 설정한다. 디폴트 사이즈는 4KB이고 거의 대부분의 경우 충분한 크기이다.
/dev/spi* 엔트리는 gpio 프로그램을 사용하는 사람이 소유한것으로 설정되기 때문에 다음 프로그램을 실행할 때 root 권한이 필요하지 않다.

$ gpio load i2c [baud rate in Kb/sec]

I2C 커널 모듈을 로드하고 옵션으로 Kb/sec 단위로 통신속도를 지정한다. 디폴트는 100Kb/sec이다.
/dev/i2c* 엔트리는 gpio 프로그램을 사용하는 사람이 소유한것으로 설정되기 때문에 다음 프로그램을 실행할 때 root 권한이 필요하지 않다.

/sys/class/gpio 모드 명령

$ gpio export <pin> in/out

주어진 핀 번호(BCM_GPIO 핀 번호)를 input 또는 output으로 export한다.

$ gpio unexport <pin>

주어진 핀 번호의 export를 제거한다.

$ gpio unexportall

/sys/class/gpio의 모든 export를 제거한다.

$ gpio exports

/sys/class/gpio 인터페이스를 통해 export 된 모든 gpio 핀의 목록과 모드를 화면에 출력한다.

$ gpio edge <pin> rising/falling/both/none

주어진 핀의 인터럽트 트리거를 활성화 시킨다. 

주의) sys 모드 명령의 핀 번호는 항상 BCM_GPIO 핀 번호이다.

예제

$ gpio mode 0 out
$ gpio write 0 1

위의 명령은 wiringPi 핀번호 0번 핀을 출력으로 설정하고 출력값을 HIGH로 설정한다.

$ gpio -g mode 0 in
$ gpio -g read 0

위의 명령은 BCM_GPIO 핀번호 0번을 입력으로 설정하고 핀의 입력값을 읽는다.

Internal pull up/down

GPIO 핀은 내부 풀업/풀다운 저항을 가지고 있어 핀이 입력모드인 경우 소프트웨어로 어떤 저항을 사용할 지 제어할 수 있다.

$ gpio mode 0 up
$ gpio mode 0 down
$ gpio mode 0 tri

위의 명령은 각각 순서대로 WiringPi 0번 핀의 저항을 풀업, 풀다운, 둘 다 사용하지 않는걸로 설정한다.







BusPirate로 TinyRTC 사용해보기



BusPirate를 TinyRTC와 연결(3.3V, GND, SCL, SDA) 한 다음 시리얼 터미널을 열어준다. 통신 파라미터는 115200-N81이다.



HiZ>#
RESET

Bus Pirate v3b
Firmware v5.10 (r559) Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com
HiZ>?
General.....Protocol interaction
---------------------------------------------------------------------------
?.This help...(0).List current macros
=X/|X.Converts X/reverse X..(x).Macro x
~.Selftest...[.Start
#.Reset....].Stop
$.Jump to bootloader..{.Start with read
&/%.Delay 1 us/ms...}.Stop
a/A/@.AUXPIN (low/HI/READ).."abc".Send string
b.Set baudrate...123
c/C.AUX assignment (aux/CS)..0x123
d/D.Measure ADC (once/CONT.).0b110.Send value
f.Measure frequency..r.Read
g/S.Generate PWM/Servo../.CLK hi
h.Commandhistory...\.CLK lo
i.Versioninfo/statusinfo..^.CLK tick
l/L.Bitorder (msb/LSB)..-.DAT hi
m.Change mode..._.DAT lo
o.Set output type.....DAT read
p/P.Pullup resistors (off/ON).!.Bit read
s.Script engine...:.Repeat e.g. r:10
v.Show volts/states....Bits to read/write e.g. 0x55.2
w/W.PSU (off/ON)..<x>/<x= >/<0>.Usermacro x/assign x/list all
HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>4
Set speed:
1. ~5KHz
2. ~50KHz
3. ~100KHz
4. ~400KHz

(1)>4
Ready
I2C>(1)
Searching I2C address space. Found devices at:
Warning: *Short or no pull-up

I2C>W
Power supplies ON
I2C>(1)
Searching I2C address space. Found devices at:
0xA0(0x50 W) 0xA1(0x50 R) 0xD0(0x68 W) 0xD1(0x68 R)

I2C를 스캔한 결과 2개의 I2C주소를 사용하고 있는걸 확인할 수 있다. (0x50, 0x68)
하지만 주소 각각에 대해 R, W 주소가 다르게 나온건 I2C는 7비트 주소를 사용하고, 그 주소가 b7~b1까지에 들어가고 b0가 R/W를 나타내기 때문에 0x68인 경우 0b11010000(0xd0)이 0x68에 대한 write, 0b11010001(0xd1)이 0x68에 대한 read가 된다. Realtime Clock칩인 DS1307의 주소는 0x68이다.

DS1307의 레지스터 맵은 다음과 같다.



이제 TinyRTC에 시간을 설정해 보도록 하겠다. 2014년 4월 2일 (목) 오전 11:23:36으로 설정한다.
그러면 실제 레지스터에 넣어줘야 하는 값은 다음과 같다. (바탕이 회색인 부분은 설정에 사용되지 않으므로 무시, 바탕이 노란색인 부분의 볼드체 숫자는 바이너리 값이 아니고 BCD 값임)

AddressB7B6B5B4B3B2B1B0Hex ValueMeaning
0x0
0
3
6
0x3636 (sec), Clock enabled
0x1
0
2
3
0x2323 (min)
0x2
0
1
0
1
1
0x5111 (Hour), 12-hour mode, AM
0x3
0
0
0
0
0
4
0x044th day of the week
0x4
0
0
0
2
0x022 (date)
0x5
0
0
0
0
4
0x044 (month)
0x6
1
4
0x142014 (year)
0x7
0
0
0
0
0
0
0
0
0x00Square-wave disabled
0x8~0x3f









56 bytes RAM
즉 주소 0번지부터 0x36, 0x23, 0x51, 0x04, 0x02, 0x04, 0x14, 0x00을 넣어주면 되는 것이다.
BusPirate에서 다음 명령으로 값을 써 줄 수 있다. 데이터를 write하는 것이기 때문에 I2C 주소로 0xd0를 사용한다.

I2C>[0xd0 0x0 0x36 0x23 0x51 0x04 0x02 0x04 0x14 0x0]
I2C START BIT
WRITE: 0xD0 ACK
WRITE: 0x00 ACK
WRITE: 0x36 ACK
WRITE: 0x23 ACK
WRITE: 0x51 ACK
WRITE: 0x04 ACK
WRITE: 0x02 ACK
WRITE: 0x04 ACK
WRITE: 0x14 ACK
WRITE: 0x00 ACK
I2C STOP BIT

이제 원하는 시간이 설정이 되었고 클럭을 enabled 시켜줬기 때문에 시간이 계속 진행된다. 조금 후 현재 시간을 확인해 보도록 한다. 주소 0x0에서부터 7 바이트를 읽어보면 된다. 주소를 지정하기 위해 0x0을 쓸때는 I2C 주소로 0xd0를 사용하고, 데이터를 읽을때는 I2C 주소로 0xd1을 사용한걸 주의해라.

I2C>[0xd0 0x0]
I2C START BIT
WRITE: 0xD0 ACK
WRITE: 0x00 ACK
I2C STOP BIT
I2C>[0xd1 r r r r r r r]
I2C START BIT
WRITE: 0xD1 ACK
READ: 0x07
READ: ACK 0x25
READ: ACK 0x51
READ: ACK 0x04
READ: ACK 0x02
READ: ACK 0x04
READ: ACK 0x14
NACK
I2C STOP BIT

위의 결과를 분석해 보면 2014년 4월 2일 (목) 오전 11:25:07 이 된다. 설정된 시간에서 약 1분 30초 정도 지난걸 확인할 수 있다.

AddressB7B6B5B4B3B2B1B0Hex ValueMeaning
0x0
0
0
7
0x0707 (sec), Clock enabled
0x1
0
2
5
0x2525 (min)
0x2
0
1
0
1
1
0x5111 (Hour), 12-hour mode, AM
0x3
0
0
0
0
0
4
0x044th day of the week
0x4
0
0
0
2
0x022 (date)
0x5
0
0
0
0
4
0x044 (month)
0x6
1
4
0x142014 (year)
0x7
0
0
0
0
0
0
0
0
0x00Square-wave disabled
0x8~0x3f









56 bytes RAM

또한 위의 두 명령을 아래와 같이 한줄로 써 줄수도 있다.

I2C>[0xd0 0x0 [0xd1 r r r r r r r]
I2C START BIT
WRITE: 0xD0 ACK
WRITE: 0x00 ACK
I2C START BIT
WRITE: 0xD1 ACK
READ: 0x54
READ: ACK 0x30
READ: ACK 0x51
READ: ACK 0x04
READ: ACK 0x02
READ: ACK 0x04
READ: ACK 0x14
NACK
I2C STOP BIT
I2C>