본문 바로가기

전자공학을 즐겁게/누구나 취미전자공학

파이썬으로 라즈베리 파이 GPIO 제어하기 - RPi.GPIO vs gpiozero

728x90
반응형

RPi.GPIO 모듈로 라즈베리 파이의 GPIO를 제어하는 방법에 대해서는 포스팅을 한 적이 있습니다.

파이썬으로 GPIO를 제어할 때, RPi.GPIO를 사용할 수도 있지만, gpiozero라는 모듈을 사용할 수 있습니다. 

다시 한 번 GPIO 제어에 대한 내용을 상기하면서 RPi.GPIO와 gpiozero가 어떻게 차이가 있는지 함께 살짝 들여다보겠습니다.

 

라즈베리 파이의 GPIO

라즈베리 파이에는 40핀의 헤더가 있습니다. 쉽게 눈에 보입니다. raspberrypi.com에 가면 Raspberry Pi OS 문서에 이 40핀 헤더의 핀 배치가 나와 있습니다.

 

 

라즈베리 파이의 터미널에서 'pinout' 커맨드를 사용해도 역시 핀 배치를 볼 수 있습니다.

 

 

이 중에 'GPIOx'라고 이름이 붙어 있는 핀들이 모두 GPIO입니다. 이 GPIO들은 1 또는 0, 두 가지 상태 중 하나를 출력하거나 입력을 받을 수 있는 입출력 장치라고 생각하면 됩니다.  1은 HIGH, 0은 LOW라고도 하는데, 전기적으로는 HIGH는 전압이 높은 것, 즉 라즈베리 파이의 경우에는 3.3V, LOW는 전압이 낮은 것, 즉 0V를 말합니다. 3.3V 또는 0V, 2가지의 상태 중 하나를 출력하거나, 아니면 입력받는 것이 GPIO의 역할입니다.

 

라즈베리 파이에서 Python으로 GPIO를 제어하기 위해서는 이를 위해서 모듈을 import 해야 합니다. 비교하기 위하여 한 모듈씩 번갈아 보여 드리지만, 두 가지가 모두 한꺼번에 필요한 것은 아니라는 것을 염두에 두세요.

 

RPi.GPIO 모듈의 import

RPi.GPIO는 다음과 같은 방법으로 import 합니다. 어떤 방법을 사용해도 동일한 기능을 합니다.

from RPi import GPIO 
# 다음과 같이 import하는 것도 가능
# import RPi.GPIO as GPIO 

GPIO.setmode(GPIO.BCM) # GPIO.BCM 또는 GPIO.BOARD

 

모듈을 import 한 이후에는 setmode라는 매써드를 호출해 주어야 합니다. 이것은 'GPIOx'에서 GPIO의 번호인 x를 사용해서 GPIO를 지정할 것인지, 40핀 헤더의 핀 번호를 사용해서 지정할 것인지를 설정하는 것입니다. GPIO.BCM을 보편적으로 사용합니다. GPIO 번호로 지정을 하겠다는 의미입니다. gpiozero 모듈에서 사용하는 것과 혼돈이 없게 하려면 GPIO 번호를 사용하는 것이 좋습니다.

 

gpiozero 모듈의 import

# gpiozero 모듈을 import합니다.
import gpiozero

 

gpiozero의 import는 직관적입니다.

 

GPIO 출력

앞서 말한 것과 같이 GPIO는 두 가지 상태 중 하나, HIGH 또는 LOW를 출력합니다. 라즈베리 파이의 경우 전기적으로는 HIGH는 3.3V, LOW는 0V가 됩니다. 보통 GPIO의 출력 실험은 LED를 이용해서 많이 합니다. LED에 대해서도 'LED의 이해'라는 포스팅을 한 적이 있으니 참고하세요.

실험에 사용되는 회로는 다음과 같습니다. R101은 LED에 흐르는 전류를 제한하기 위한 저항입니다. 이 저항이 어떻게 전류를 제한하는지는 'LED를 켜라'라는 포스팅에서 다룬 적이 있습니다. 

 

GPIO에 연결된 LED의 회로입니다.

 

HIGH는 3.3V이기 때문에 큰 전류가 필요한 것이 아니라면, 다시 말해서 많은 에너지가 필요한 것이 아니라면 GPIO의 출력이 전원 역할을 할 수가 있습니다. 전력과 부하에 대하여 약간 더 들어가 보고자 하는 분은 다음 포스트들을 참고하세요.

 

RPi.GPIO 모듈을 사용한 출력 제어

RPi.GPIO에서는 다음과 같이 합니다.

# GPIO2를 출력으로 지정합니다.
GPIO.setup(2, GPIO.OUT)

# GPIO2에 HIGH를 출력합니다.
GPIO.output(2, GPIO.HIGH)

# GPIO2에 LOW를 출력합니다.
GPIO.output(2, GPIO.LOW)

setup 매써드를 사용하여 특정 GPIO를 출력으로 지정하고, output 매써드로 HIGH 또는 LOW를 출력합니다. 우리가 사용한 회로에서라면 HIGH가 출력되는 경우에 LED가 켜집니다.

 

gpiozero 모듈을 사용한 출력 제어

gpiozero는 RPi.GPIO보다 한 단계 더 추상화되어 있기 때문에, 표면상으로는 GPIO라는 것이 덜 드러난다고 보면 됩니다. 

# GPIO 2에 연결된 LED instance를 생성합니다.
led = gpiozero.LED(2)

# led on
led.on()

# led off
led.off()

 

led라는 인스턴스를 만들 때, GPIO2라는 것을 지정하는 것을 제외하고는 그냥 led라는 것을 끄고 켜는 매써드가 호출됩니다.

 

우리가 실험하는 회로는 Active High의 회로입니다. 즉, GPIO에 HIGH가 출력될 때 LED가 켜지는 회로입니다.  GPIO에 LOW가 출력될 때 켜지는 LED가 켜지는 회로를 Active Low 회로라고 하는데, 이렇게 되는 경우라면 LED의 캐소드(cathode)가 GPIO에 연결되고 반대편이 전원으로 연결이 됩니다. gpiozero의 문서에서 LED 부분을 살펴보면 Active High/Active Low를 설정할 수 있습니다. 여기서 자세히는 다루지 않습니다만, 필요한 경우에 참고하세요.

 

 

GPIO 입력

GPIO의 입력은 말 그대로 현재 GPIO의 상태가 HIGH인지 LOW인지를 바탕으로 응답이 오는 것을 말합니다.

 

실험에는 푸시 버튼을 사용합니다. 다음에 나와 있는 것과 같은 회로를 사용하게 됩니다.

 

 

푸시 버튼은 눌렀을 때, 양쪽 단자 사이에 전기가 통하는 부품입니다. 위의 회로에서는 버튼이 눌리면 GPIO는 GND와 연결이 됩니다. 즉, 0V입니다. 버튼에서 손을 떼면 스위치는 양쪽 단자 사이는 떨어지고 GPIO는 저항을 통하여 3.3V에 연결이 됩니다. 그렇다면 이때의 GPIO의 전압은? 3.3V입니다. 이 경우에는 저항이 있더라도 전압이 떨어지지 않습니다. 전류가 거의 흐르지 않기 때문입니다. 옴의 법칙에 따라 전류가 흐르지 않으면 저항의 전압 강하는 0V입니다. 그래서 GPIO의 전압은 $3.3V-0V=3.3V$가 되는 것입니다. 그러나 이 저항이 없으면 GPIO의 전압은 알 수 없는 상태가 됩니다. 이와 같은 상태를 피하기 위하여 사용되는 이와 같은 저항을 풀업 저항(Pull-up resistance)라고 합니다.

 

RPi.GPIO 모듈을 사용한 입력

RPi.GPIO는 input 매써드를 사용하여 지정된 GPIO의 상태를 읽습니다. GPIO를 지정하여 입력으로 설정하고, input 매써드를 사용합니다.

# GPIO 3을 입력으로 설정합니다.
GPIO.setup(3, GPIO.IN)

# 입력으로 지정된 GPIO 3으로부터 값을 읽어 출력합니다.
print(GPIO.input(3))

 

gpiozero 모듈을 사용한 입력

출력과 마찬가지로 gpiozero에는 푸시버튼을 추상화한 Button이라는 클래스가 있습니다. GPIO를 지정하면서 Button 클래스의 인스턴스를 생성하고, 값을 읽습니다. gpiozero의 Button 클래스에는 이 이외에도 유용한 기능들을 제공하고 있습니다. 문서를 참조하세요.

# GPIO 3에 연결된 Button 클래스의 인스턴스 button을 생성합니다.
button = gpiozero.Button(3)

# button이 눌렸는지 눌리지 않았는지 출력합니다.
print(button.value)

 

LED와 마찬가지로 Button에도 Active High/Active Low가 있습니다. 여기에서 더 다루지는 않겠지만, 나중을 위하여 참고하세요.

 

 

 

GPIO 제어로 교통 신호등 흉내내기

불도 켜지고 버튼도 동작하면 각자의 시나리오에 따라 표시가 달라지는 여러 가지를 만들 수 있습니다. LED 5개와 푸시 버튼 하나로 만들어 불 수 있습니다. 영상을 확인하세요.

 

 

영상에서 구성한 회로의 다이어그램입니다.

 

GPIO 제어를 위하여 사용한 코드입니다.

import gpiozero
import time

class vehicle_signals:
    def __init__(self, red, amber, green):
        self.red = gpiozero.LED(red)
        self.amber = gpiozero.LED(amber)
        self.green = gpiozero.LED(green)
        
    def go(self):
        self.red.off()
        self.amber.off()
        self.green.on()
        
    def stop(self):
        self.red.on()
        self.amber.off()
        self.green.off()
        
    def caution(self):
        self.red.off()
        self.green.off()
        self.amber.on()

class pederstrian_signals:
    def __init__(self, red, green, button=None):
        self.red = gpiozero.LED(red)
        self.green = gpiozero.LED(green)
        if button != None:
            self.button = gpiozero.Button(button) 
    def go(self):
        self.red.off()
        self.green.on()
        
    def stop(self):
        self.red.on()
        self.green.off()
        
    def wait_next_signal(self):
        self.red.off()
        self.green.blink(0.5, 0.5)
        
    def pederstrian_in_queue(self):
        return True if self.button.value == 1 else False

vehicle = vehicle_signals(2, 3, 4)
pederstrian = pederstrian_signals(14, 15, 18)

current_state = 'vehicles'

while True:
    if current_state == 'vehicles':
        vehicle.go()
        pederstrian.stop()
        if pederstrian.pederstrian_in_queue():
            time.sleep(10)
            current_state = 'cautious'
    elif current_state == 'cautious':
        vehicle.caution()
        pederstrian.stop()
        time.sleep(5)
        current_state = 'pederstrians'
    elif current_state == 'pederstrians':
        vehicle.stop()
        pederstrian.go()
        time.sleep(5)
        current_state = 'wait'
    elif current_state == 'wait':
        vehicle.stop()
        pederstrian.wait_next_signal()
        time.sleep(5)
        current_state = 'vehicles'

 

 

생각나는 대로 막 만들어서 그냥 지저분한 로직일 수 있겠습니다.

이것저것 만드는 취미를 팅커링이라고 한다지요? 제가 보여 드리는 지저분한 코드라도 하드웨어 입출력과 코드의 관계를 이해하고 나아가서는 이것저것 재미있는 것을 만드는 취미 생활, 특히 전자공학을 취미 생활로 발전시킬 수 있는 계기가 되기를 바랍니다.

728x90
반응형