2016년 2월 10일 수요일

PiFaceCAD

올해 초부터 우분투 한국 사용자모임에서 시작한 Raspberry Pi 스터디에 매주 나가고 있다. Pi에서 node.js를 구동하여 웹을 통해 이런저런 장치를 제어하는 것을 목표로 하는데, 작업의 편의를 위해 PiFaceCAD(PiFace Control and Display)라는 제품을 구입해서 사용하기로 했다. 들고다니다가 망가뜨리지 않을까 걱정이 되어, Raspberry Pi에 PiFaceCAD를 꽂은 채로 넣을 수 있는 케이스도 함께 샀다.

PiFaceCAD에 친숙해지기 위해 Python으로 스코어보드를 만들어보는 숙제가 있었다. LCD에 두 팀의 점수를 보여주는 기능을 하며, 각 팀의 점수를 올리기 위한 스위치 한 개 씩과, 점수를 리셋하는 용도의 스위치 한 개를 사용한다.


위의 영상과 같이 동작하며, 내가 짠 코드는 다음과 같다. (먼저 셋업이 필요하다)

#!/usr/bin/python3

import pifacecad

cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()

def show():
    cad.lcd.clear()
    cad.lcd.write('A team:' + str(score[0]) + '\n'
                  + 'B team:' + str(score[1]))

score = [0, 0]
show()

while True:
    if cad.switches[0].value == 1:
        score[0] = score[0] + 1
        while cad.switches[0].value == 1: pass
        show()
    elif cad.switches[1].value == 1:
        score[1] = score[1] + 1
        while cad.switches[1].value == 1: pass
        show()
    elif cad.switches[4].value == 1:
        score = [0, 0]
        while cad.switches[4].value == 1: pass
        show()

스위치를 한 번 누르는 동안 여러 점이 올라가는 것을 막기 위해, 손을 뗄 때까지 pass시키는 작은 while 문을 넣었다. 다른 사람들은 time.sleep()을 사용해서 처리했다. 이때, 일반적으로 0.25 초 정도의 sleep이 적당하다고 한다.

작성해놓고 보니 while 블록에서 중복으로 나타나는 것들을 정리하고 싶어져서 아래와 같이 바꾸었다.

#!/usr/bin/python3

import pifacecad

cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()

def show():
    cad.lcd.clear()
    cad.lcd.write('A team:' + str(score[0]) + '\n'
                  + 'B team:' + str(score[1]))

def listen(i, func):
    global score
    if cad.switches[i].value == 1:
        if func == 'add': score[i] = score[i] + 1
        elif func == 'reset': score = [0, 0]
        while cad.switches[i].value == 1: pass
        show()

score = [0, 0]
show()

while True:
    listen(0, 'add')
    listen(1, 'add')
    listen(4, 'reset')

다음의 코드는, 위쪽에 붙은 로커 스위치를 테스트해보기 위해 수정한 버전이다.

#!/usr/bin/python3

import pifacecad

cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()

def show():
    cad.lcd.clear()
    cad.lcd.write('A team:' + str(score[0]) + '\n'
                  + 'B team:' + str(score[1]))

def listen(i, func, team=None):
    global score
    if cad.switches[i].value == 1:
        if func == 'add': score[team] = score[team] + 1
        elif func == 'reset': score = [0, 0]
        while cad.switches[i].value == 1: pass
        show()

score = [0, 0]
show()

while True:
    listen(5, 'reset')
    listen(6, 'add', 0)
    listen(7, 'add', 1)

2016년 2월 3일 수요일

PyAudio

앞의 글에서는 Raspberry Pi에 USB 마이크를 연결하고 arecord와 aplay 명령을 사용하여 소리의 녹음과 재생을 해보았는데, 이번에는 같은 일을 Python에서 시도해 보았다. 사용한 라이브러리는 PyAudio라는 것으로, PortAudio의 Python 바인딩이다.


PyAudio 설치


다음의 명령으로 라이브러리를 설치한다.

$ sudo apt-get install python-pyaudio


Wav 파일 재생


PyAudio 홈페이지에 소개된, wav 파일을 재생하는 예제를 실행해보았다.
http://people.csail.mit.edu/hubert/pyaudio/#play-wave-example

경고 메시지가 많이 뜨긴 하지만 일단 무시했다. 소리가 많이 끊어져 들렸는데, CHUNK 값을 2048로 조정하니 조금 좋아졌지만 여전히 끊기는 듯한 느낌이 든다.


Wav 파일 녹음


이번에는 소리를 wav 파일로 녹음하는 예제를 실행해보았다.
http://people.csail.mit.edu/hubert/pyaudio/#record-example

IOError 메시지가 떴는데, 역시 CHUNK 값을 조정하여 해결했다. 이번에는 4096으로 설정. 그리고, 모노 마이크를 사용하기 때문에 CHANNELS = 1로 설정했다.

2016년 2월 1일 월요일

Raspberry Pi에서 소리 입력 및 녹음하기

Raspberry Pi는 소리를 출력할 수 있지만, 아날로그 마이크를 연결해서 소리를 녹음할 수 없다. 그래서 ① 마이크가 내장된 USB 카메라를 사용하거나,  ② USB 사운드카드에 마이크를 연결한다. 내가 선택한 것은 ③ USB 동글 형태의, 사운드카드와 마이크 일체형(?)으로, "USB Microphone" 비슷한 이름이 붙은 물건이다. eBay에서 1.65 달러에 구입했다.

http://www.ebay.com/itm/231668535198?_trksid=p2057872.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT

USB 마이크


구성 및 테스트

  1. USB 마이크를 Pi에 꽂은 후, Pi에 전원을 넣는다.

  2. USB 오디오 녹음장치를 찾아본다.

    $ arecord -l
    **** List of CAPTURE Hardware Devices ****
    card 1: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
      Subdevices: 1/1
      Subdevice #0: subdevice #0

    위에서는 card 번호가 1, device 번호가 0이다.

  3. 녹음해본다. 앞에서 알아낸 번호를 -D hw: 인자에 써준다.

    $ arecord -D hw:1,0 -f S16_LE -d 5 -r 44100 test.wav
    Recording WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono

    만약 장치(-D 옵션)를 올바로 지정하지 않으면 다음과 같은 오류가 발생한다.

    arecord: main:682: audio open error: No such file or directory

    비트율(-r 옵션)을 생략하거나 부적당한 값을 지정하면 경고가 발생할 수 있다. 'got = '에 표시된 값으로 바꿔서 다시 녹음해본다.

    Warning: rate is not accurate (requested = 8000Hz, got = 44100Hz)
                    please, try the plug plugin

  4. 녹음된 파일을 재생해본다.

    $ aplay test.wav
    Playing WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono

  5. 음량을 조절하려면 alsamixer를 실행한다. 처음 보이는 화면은 재생 음량이고, 탭을 한 번 누르면 녹음 음량이 보인다. 이때, <F6> 키를 누르고 사운드카드를 선택한 다음, 위아래 화살표 키로 음량을 조절한다. 스페이스 바를 눌러 "CAPTURE"라는 빨간 글씨가 보이도록 해야한다. <esc> 키로 종료한다.
    설정 값을 저장해두하려면 sudo alsactl store를 실행한다.

alsamixer

Raspberry Pi에서 MP3 오디오 재생하는 방법은 공식 문서(번역)를 참조.

참고