2016년 7월 21일 목요일

Firmata를 사용해 라즈베리 파이에서 아두이노 제어하기 (Controlling Arduino from Raspberry Py using Firmata)


아두이노와 라즈베리 파이를 시리얼 포트롤 통해 연결하면 firmata를 사용해 라즈베리 파이에서 아두이노의 핀들을 제어할 수 있다. 아두이노와 라즈베리 파이를 시리얼 포트로 연결하는 방법은 이전 포스트(라즈베리 파이와 아두이노를 시리얼 포트로 연결하는 방법들 )를 참고하면 된다.

먼저 아두이노를 설정 해 준다.

Firmata를 사용해 라즈베리 파이에서 아두이노를 제어하려면 아두이노에도 firmata 소프트웨어가 설치되어 있어야 한다.

메뉴의 File -> Examples -> Firmata 에서 StandardFirmata를 오픈해 자신이 사용하는 아두이노에 업로드 해 주면 된다.

다음은 라즈베리 파이에 pyfirmata를 설치해야 한다.

터미널 창에서 아래의 명령을 입력해 주면 된다. 기존에 이미 pip와 pyserial이 설치되어 있다면 첫번째 줄은 건너 뛰어도 된다.

$ sudo apt-get install python-pip python-serial
$ sudo pip install pyfirmata

이제 아두이노를 USB케이블을 사용해 라즈베리 파이에 연결해 주면 /dev 디렉토리에 ttyUSB0 디바이스가 만들어진다. 이 디바이스 이름을 알고 있어야 한다.

만일 라즈베리 파이에 허브를 연결한 다음 여러대의 아두이노를 연결해 주면 각각 /dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2, .... 식으로 이름이 부여된다.

이제 실제로 라즈베리 파이와 아두이노를 firmata를 사용해 연결해 준다.

$ python
Python 2.7.3 (default, Mar 18 2014, 05:13:23)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyfirmata import Arduino, util

>>> board = Arduino('/dev/ttyUSB0')
>>>

위와 같이 에러가 없이 진행되었다면 연결이 성공한 것이다.

이제 아두이노의 디지털 포트는 board.digital[] 리스트를 사용해 제어할 수 있다.

즉 13번핀의 LED를 on/off하고 싶으면 다음과 같이 하면 된다.

>>> board.digital[13].write(1)
>>> board.digital[13].write(0)
>>>

핀의 상태를 읽을 때는 다음과 같다.

>>> print board.digital[3].read()
 0
>>>

그런데 핀을 반복적으로 사용해야 하는 경우 매번 board.digital[...] 이렇게 쓰는건 귀찮다. 그 대신 board.get_pin() 함수를 사용해 핀의 reference를 얻어 올 수 있다. 함수의 파라미터 부분에 "[a|d]:[pin#]:[i:o:p:s]" 형태의 스트링을 넘겨줘야 하는데 파라미터는 3개의섹션으로 되어 있고 각 섹션은 콜론(':')으로 구분한다.

첫번째 섹션은 핀이 아날로그(a)인지 디지털(d)인지를 지정한다. 두번째 섹션은 사용할 핀 번호가 된다. 즉 아두이노 우노의 경우 아날로그면 0~5, 디지털이면 0~13 사이의 값이 올 수 있다. 세번째 섹션은 핀 모드를 설정한다. 'i'면 입력, 'o'면 출력, 'p'면 PWM, 's'면 서보가 된다.

이 함수의 리턴값을 변수에 넣어 추후 read, write에 사용하면 된다.

>>> pin13 = board.get_pin('d:13:o')
>>> pin13.write(1)
>>>
>>> pin2 = board.get_pin('d:2:i')
>>> pin2.read()
0
>>>

아날로그 핀에서 값을 읽을 때는 먼저 analog value reporting을 활성화 시켜줘야만 한다. 하지만 그렇게 하면 아두이노가 라즈베리 파이에게 지속적으로 값을 보내게 된다. 라즈베리 파이에서 값을 계속 읽어내지 않으면 시리얼 통신을 막아버려 스크립트가 정상적으로 동작하지 못하게 만들어 버린다. 그러므로 정상적으로 값을 읽기 위해서는 iterator 스레드를 사용하는 것이 유용하다.

>>> it = util.Iterator(board)
>>> it.start()
>>> board.analog[0].enable_reporting()
>>> board.analog[0].read()
>>> it.start()
>>>

아날로그 값 리포팅을 멈추게 하려면 disable_reporting() 메소드를 호출하면 된다.






댓글 4개:

  1. 작성자가 댓글을 삭제했습니다.

    답글삭제
  2. 디바이스 이름이 뭔지 확인이 안됩니다. ttyUSB0가 없더라구요.
    혹시 제 디바이스 이름을 알 수 있는 방법이 있을까요?

    답글삭제
    답글
    1. 소위 말하는 정품이면 라즈베리 파이에 꼽으면 바로 인식되는데 저가 아두이노 클론의 경우 usb-to-serial 칩이 FTDI제품이 아니고 CH340을 사용했기 때문에 이 칩은 raspbian에 디폴트로 드라이버가 들어있지 않아 디바이스 인식이 안됩니다.
      이 경우 https://github.com/aperepel/raspberrypi-ch340-driver 등을 참고해 CH340 드라이버를 먼저 설치한 다음 다시 해 보시면 디바이스 이름을 확인할 수 있을겁니다.

      삭제
    2. 기본값은 보통 /dev/ttyACM0 더라구요

      삭제