아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

라즈베리파이(Raspberry Pi)의 장점은 라즈베리파이 자체가 리눅스 기반의 소형 컴퓨터라는 점입니다. 즉, 우리가 데스크탑에서 할 수 있는 작업들을 라즈베리파이에서도 시도해 볼 수 있습니다. 또한 무선랜과 블루투스가 사용 가능하고 웹캠과 같은 다양한 USB 기기를 사용할 수 있습니다. 또한 GPIO를 통해 여러 장치들을 제어할 수 도 있습니다. 

반면, 아두이노(Arduino)는 하드웨어적으로 구현된 PWM을 통해서 정밀하게 모터와 같은 기기들을 제어할 수 있습니다. 하지만 아두이노는 하드웨어 제어에 특화되어있기 때문에 라즈베리파이가 가지는 소형 컴퓨터로써의 장점은 가질 수 없습니다. 

그래서 저는 라즈베리파이와 아두이노를 연결해서 사용해 볼려고 합니다. 즉, 라즈베리파이는 소프트웨어를 담당하고 아두이노는 하드웨어 제어를 담당해서 서로의 역할을 나누는 것이죠. 

라즈베리파이와 아두이노를 연동하는 방법은 여러가지가 있습니다. 제가 제시하는 방법은 Firmata를 사용하는 방법입니다. (Firmata는 마이크로컨트롤러(Microcontroller)와 일반 컴퓨터 소프트웨어 사이의 통신을 위한 프로토콜입니다.) 이제 그 방법을 알아보겠습니다. 

아두이노 Firmata 업로드

Firmata를 사용해서 라즈베리파이와 아두이노가 통신하기 위해선, 먼저 아두이노에 Firmata를 업로드 해줘야 합니다. 아두이노에 Firmata를 업로드 하면 더이상 아두이노에 프로그래밍 할 필요가 없습니다. 왜냐하면 라즈베리파이에서 Firmata 프로토콜로 아두이노를 제어할것이기 때문입니다. 아래처럼 StandardFirmata를 열어주세요. 

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

그리고 아래와 같이 코드창이 나타나면 아두이노에 업로드 해주세요. 

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

이제 아두이노는 준비가 완료되었습니다. 

라즈베리파이 pyfirmata 설치

라즈베리파이에서 Firmata를 사용하기 위해서, 저는 pyfirmata를 사용하도록 하겠습니다. 설치는 pip를 통해서 할 수 있습니다.

pip install pyfirmata

이제 라즈베리파이와 아두이노를 USB 케이블로 연결해 주세요. 

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

라즈베리파이 + 아두이노 연동 테스트

라즈베리파이에서 파이썬(Python) 코드를 통해서 아두이노의 led를 제어해 보겠습니다. 아두이노 우노(Uno)의 디버그용 led는 13번 핀넘버로 제어할 수 있습니다. 아래 코드를 파일로 저장 후 실행을 하면, 아두이노의 led가 깜박 거리는것을 확인 할 수 있습니다. 

import time
import pyfirmata

# 아두이노에 연결합니다. 
board = pyfirmata.Arduino('/dev/ttyACM0')

# 디지털(digital) 핀(pin) 13번을 출력(output) 모드로 가져옵니다. 
led_builtin = board.get_pin('d:13:o')

while True:
    # 핀에 출력값으로 1을 주면 led 불이 켜집니다. 
    led_builtin.write(1)
    time.sleep(1)
    # 핀에 출력값으로 0을 주면 led 불이 꺼집니다.     
    led_builtin.write(0)
    time.sleep(1)

위의 코드에서 get_pin() 함수에 'd:13:o' 라거 인자를 넣어주었습니다. d는 핀 타입(Pin Type)이 디지털(Digital) 이라는것을 의미하고, 숫자는 핀넘버, 그리고 o 는 핀 모드(Pin Mode)를 나타냅니다. 핀 타입은 d(digital), a(analog) 가 사용 가능합니다. 핀 모드는 i(input), o(output), p(pwm), s(servo) 가 사용 가능합니다. 핀 넘버는 아래 그림에서 확인 가능합니다. 

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
이미지 출처: https://www.arduino.cc/en/Reference/Board

실제 동작 화면은 아래와 같습니다. 깜박거리는 led가 아두이노 보드에 기본적으로 달려있는 디버그용 led 입니다. 

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

오늘이라도

https://github.com/upcake/Class_Examples

교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다. 

gif 파일은 클릭해서 보는 것이 정확합니다.


 - 아두이노 연동하기 -

○ 아두이노 IDE 설치

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
▲아두이노 IDE 설치

 - sudo apt-get install arduino

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

 - 설치가 완료된 후 개발 탭에 Arduino IDE가 추가된 것을 알 수 있다.

▲아두이노 LED 점멸 작동 영상
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
int led = 7;
int val = 0;

void setup() {
  pinMode(led, OUTPUT);
} //setup()

void loop() {
  digitalWrite(led,HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);0
} //loop()

▲_14_arduino_led_blink.ino

○ 시리얼 모니터로 조작 (PWM)

▲LED 시리얼 모니터로 조작 작동 영상
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
▲시리얼 모니터
int led = 10; //~ mark port
int val = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("input 0 ~ 255");
  pinMode(led, OUTPUT);
} //setup()

void loop() {
  if(Serial.available()) {
    val = Serial.parseInt();
    Serial.println(val);
    analogWrite(led, val);
  }
  delay(50);
} //loop()

▲_15_Arduino_LED_PWM.ino

○ Firmata 프로토콜 이용해서 파이썬으로 조작

아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong

 - Firmata 프로토콜 : 아두이노에 시리얼을 통해 명령을 전달하는 프로토콜

 - 예제 - Firmata - StandardFirmata 를 아두이노에 업로드해준다.

 - 터미널로 라이브러리 설치

 - sudo apt-get install python-serial

 - sudo apt-get install git

 - git clone https://github.com/tino/pyFirmata

 - cd pyFirmata

 - sudo python3 setup.py install

▲파이썬으로 아두이노 조작 작동 영상
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
import RPi.GPIO as GPIO
import time
import sys

# 라이브러리 경로 추가
sys.path.append('/home/pi/pyFirmata')
import pyfirmata

# 아두이노에 잡힌 포트 번호
board = pyfirmata.Arduino('/dev/ttyACM0')

# 아두이노에 꽂은 포트를 알려줌
# d : digital / a : analog
# 9 : 9번 포트
# o : OUTPUT / i : INPUT / p : PWM (value가 0 ~ 1)
pin9 = board.get_pin('d:9:o')

try:
    while True:
        pin9.write(1)
        time.sleep(1) #여긴 단위가 초(second)이다.
        pin9.write(0)
        time.sleep(1) #따라서 1초임
        
except KeyboardInterrupt:
    GPIO.cleanup()

▲16.Arudino.pyfirmata.py

▲PWM 입력으로 아두이노 LED 조작 작동 영상
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
▲입력 화면
import RPi.GPIO as GPIO
import time
import sys
sys.path.append('/home/pi/pyFirmata')
import pyfirmata

board = pyfirmata.Arduino('/dev/ttyACM0')
#디지털 9번 포트 PWM 제어
pin9 = board.get_pin('d:9:p')

try:
    while True:
        value = int(input("Enter Number (0 to 100) : "))
        pin9.write(value/100.0)
        
except KeyboardInterrupt:
    GPIO.cleanup()

▲17.Arduino pyfirmata PWM.py

▲조도센서 작동 영상
아두이노 라즈베리파이 연동 - adu-ino lajeubelipai yeondong
import RPi.GPIO as GPIO
import time
import sys
sys.path.append('/home/pi/pyFirmata')
import pyfirmata

led_pin = 11;

GPIO.setmode(GPIO.BOARD)
GPIO.setup(led_pin, GPIO.OUT, initial=GPIO.LOW)

board = pyfirmata.Arduino('/dev/ttyACM0')
pinA0 = board.get_pin('a:0:i')

#아날로그 값 받는 방식
it = pyfirmata.util.Iterator(board)
it.start()
pinA0.enable_reporting()

try:
    while True:
        # 핀 값을 읽는다
        coValue = pinA0.read()
        print(coValue)
        # 값이 아예 넘어오지 않을 수 있기 때문에
        if (coValue != None) and (coValue > 0.5):
            GPIO.output(led_pin, True)
        else:
            GPIO.output(led_pin, False)
            
        time.sleep(1)
        
except KeyboardInterrupt:
    GPIO.cleanup()
    

▲18.Arduino pyfirmata analog sensor.py

 - 일산화탄소 센서, 소리 센서, 조도 센서 등의 아날로그 센서 전반에 적용할 수 있습니다.