본문 바로가기

프로젝트형 IoT 서비스 개발 4회차/3. 게이트웨이 디바이스 제어

[Day53] 2022-04-13(수) 라즈베리파이2 - GPIO2(PWM) - 김서연 강사님

728x90

[1] GPIO

  1. PWM

    - 라즈베리파이에서 PWM 신호는 10bit로 컨트롤하며, 따라서 0~1023 의 값을 줄 수 있다.

    - 하지만 RPi.GPIO 모듈은 소프트웨어적으로 PWM 신호를 Duty Cycle 값으로 제어할 수 있도록 구현되어 있다.

    1) PWM 객체 생성

      - 객체 = RPi.GPIO.PWM(핀번호, 주파수)

        ① 핀번호 : PWM 출력할 핀

        ② 주파수 : Hz 단위의 주파수로 0보다 큰 값을 입력

 

 

    2) 소프트웨어 PWM 시작

      - 객체.start(듀티비)

        - 듀티비 : Duty Cycle % 단위로서의 0~100 사이 숫자 입력

    3) Duty Cycle 변경

      - 객체.ChangeDutyCycle(듀티비)

    4) Frequency 변경

      - 객체.ChangeFreqeuncy(주파수)

    5) PWM+LED 예제1

pwm_led_test1.py

from RPi import GPIO
led_pin = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(led_pin, GPIO.OUT)

# 소프트웨어 PWM을 사용하기 위해 객체를 생성
# GPIO.PWM(핀번호, 주파수)
# 핀번호 : PWM을 출력할 핀,
# 주파수 : 0보다 큰 값
pwm = GPIO.PWM(led_pin, 1000)
pwm.start(50)     # 소프트웨어 PWM 시작 - 파형을 출력 (매개변수에는 duty cycle 숫자로 0~100까지의 숫자 입력)

time.sleep(3)
pwm.ChangeDutyCycle(100)
try:
    while True:     # led로 나가는 출력파형이 유지될 수 있도록
        pass
except KeyboardInterrupt:
    pass
finally:
    pwm.stop()		# PWM 출력 중지
    GPIO.cleanup()

    6) PWM+LED 예제2

      - LED 가 서서히 밝아졌다가 서서히 어두워지는 것을 반복

pwm_led_exam1.py

from RPi import GPIO
import time

led_pin = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(led_pin, GPIO.OUT)

pwm = GPIO.PWM(led_pin, 1000)
pwm.start(0)
try:
    while True:
        for i in range(101):
            pwm.ChangeDutyCycle(i)
            time.sleep(0.01)
        for i in range(100, -1, -1):
            pwm.ChangeDutyCycle(i)
            time.sleep(0.01)
except KeyboardInterrupt:
    pass
finally:
    pwm.stop()
    GPIO.cleanup()

    7) PWM+Buzzer 예제1

      - 아두이노에서는 내장 라이브러리의 tone 함수를 이용해 주파수를 조절했음

https://powerstone829.tistory.com/59?category=1014640 

 

[Day42] 2022-03-29(화) 아두이노7 - 부저, 조도센서, PIR센서, 온습도센서, LCD1 - 김서연 강사님

[1] 부저(Piezo Buzzer)   - <아두이노 마스터1 우노보드 기초 - 신동욱> p234~243 - 삐 소리를 출력 - 주파수 신호를 주면 음계를 표현할 수 있다. - 능동부저(전원만 연결해도 출력)와 수동부저(전원만

powerstone829.tistory.com

      - 라즈베리파이에서는 PWM 객체의 주파수를 조절하여 음계를 표현

      - 라즈베리파이 기본 전원이 3.3V이므로, 부저 소리가 작고 떨리는 듯한 소리가 나올 수 있음

      - 아래 사이트에서 보면 트랜지스터를 이용해 5V와 연결하여 사용할 수도 있다고 나온다.

https://rasino.tistory.com/332

 

【라즈베리Pi#20】 피에조 부저 사용하기! with (파이썬 코드)

【라즈베리Pi#20】 피에조 부저 사용하기! with (파이썬 코드) RaspberryPi Buzzer control with Python !  안녕하세요 라즈이노 IoT 입니다. 이번 시간에는 라즈베리 Pi에서 부저를 사용해 보는 실습을 진행합.

rasino.tistory.com

pwm_buzzer_test1.py

from RPi import GPIO
import time
buzzer_pin = 27
GPIO.setmode(GPIO.BCM)
GPIO.setup(buzzer_pin, GPIO.OUT)

pwm = GPIO.PWM(buzzer_pin, 262)     # 4옥타브 도에 해당하는 주파수
pwm.start(50)

time.sleep(2)
pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    8) PWM+Buzzer 예제2

      - 도,레 출력을 3번 반복

pwm_buzzer_tset2.py

from RPi import GPIO
import time

buzzer_pin = 27
GPIO.setmode(GPIO.BCM)
GPIO.setup(buzzer_pin, GPIO.OUT)
pwm = GPIO.PWM(buzzer_pin, 1)
pwm.start(50)

for i in range(0, 3):
    pwm.ChangeFrequency(262)
    time.sleep(0.5)
    pwm.ChangeFrequency(294)
    time.sleep(0.5)

pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    9) PWM+Buzzer 예제3

      - 도레미파솔라시도 출력

pwm_buzzer_exam.py

from RPi import GPIO
import time

buzzer_pin = 27
note = [262, 294, 330, 349, 391, 440, 494, 523]
GPIO.setmode(GPIO.BCM)
GPIO.setup(buzzer_pin, GPIO.OUT)
pwm = GPIO.PWM(buzzer_pin, 1)
pwm.start(50)

for i in note:
    pwm.ChangeFrequency(i)
    time.sleep(0.5)

pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    10) PWM+Servo Motor 예제1

https://powerstone829.tistory.com/58?category=1014640 

 

[Day41] 2022-03-28(월) 아두이노6 - RGB LED, 서보모터, 초음파센서 - 김서연 강사님

2022-03-28(월) 21:50 수정 - 초음파센서 사용법 수정 [1] RGB LED 제어   - <아두이노 마스터1 우노보드 기초 - 신동욱> p172~179 1. RGB LED 예제1 - R,G,B가 연결된 핀에 각각 PWM 신호로 0~255 값을 랜덤하..

powerstone829.tistory.com

      ① 주파수 : 50Hz

      ② 각도 별 듀티비

        - 0도 : 2.5%

        - 90도 : 7.5%

        - 180도 : 12.5%

pwm_servo_test1.py

from RPi import GPIO
import time

servo_pin = 19
GPIO.setmode(GPIO.BCM)
GPIO.setup(servo_pin, GPIO.OUT)
pwm = GPIO.PWM(servo_pin, 50)
pwm.start(2.5)      # 서보모터의 초기값을 0으로 설정
time.sleep(2)
pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    11) PWM+Servo Motor 예제2

      - 0~180도까지 서서히 움직이고, 마지막에 다시 0도로 이동

pwm_servo_test2.py

from RPi import GPIO
import time

servo_pin = 19
GPIO.setmode(GPIO.BCM)
GPIO.setup(servo_pin, GPIO.OUT)
pwm = GPIO.PWM(servo_pin, 50)
pwm.start(2.5)      # 서보모터의 초기값을 0으로 설정
for i in range(25, 126):      # 0: 2.5, 90: 7.5, 180: 12.5
    pwm.ChangeDutyCycle(i/10)
    time.sleep(0.02)

pwm.ChangeDutyCycle(3)
time.sleep(2)
pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    12) PWM+Servo Motor 예제3

      - 0~180~0도로 이동하는 것을 3번 반복

pwm_servo_exam1.py

from RPi import GPIO
import time

servo_pin = 19
GPIO.setmode(GPIO.BCM)
GPIO.setup(servo_pin, GPIO.OUT)
pwm = GPIO.PWM(servo_pin, 50)
pwm.start(2.5)

for j in range(3):
    for i in range(25, 126):
        pwm.ChangeDutyCycle(i/10)
        time.sleep(0.02)
    for i in range(125, 24, -1):
        pwm.ChangeDutyCycle(i/10)
        time.sleep(0.02)

pwm.ChangeDutyCycle(0)
pwm.stop()
GPIO.cleanup()

    13) Servo Motor 임의의 각도로 컨트롤 하기

      - 0, 90, 180도는 각각 듀티비가 2.5, 7.5, 12.5 로 정해져 있다.

      - 그 외 각도를 구하기 위해서는 해당 각도의 듀티비를 구해야 한다.

      - 선형보간법을 이용하여 식을 세운다.

https://ko.wikipedia.org/wiki/%EC%84%A0%ED%98%95_%EB%B3%B4%EA%B0%84%EB%B2%95

 

선형 보간법 - 위키백과, 우리 모두의 백과사전

선형 보간법(線型補間法, linear interpolation)은 끝점의 값이 주어졌을 때 그 사이에 위치한 값을 추정하기 위하여 직선 거리에 따라 선형적으로 계산하는 방법이다. 두 빨간색 점 사이에 있는 파랑

ko.wikipedia.org

      - A(0, 2.5), B(180, 12.5) 두 점을 지나는 직선의 1차함수( duty=f(degree) )를 구하는 것과 같다.

        => duty = degree / 180 * (12.5-2.5) + 2.5

        => duty = degree / 180 * 10 + 2.5

def getDuty(degree):
    duty = degree/180*10 + 2.5
    return duty   # duty값을 리턴


print(getDuty(0))   # 2.5~3
print(getDuty(90))  # 7.5
print(getDuty(180)) # 12.5
print(getDuty(45))  # ?
print(getDuty(120)) # ?
print(getDuty(100)) # ?

    14) PWM 종합 예제

# 스위치 2개, 서보모터, LED, 부저
# 스위치1 : +10도씩 서보모터를 이동
# 스위치2 : -10도씩 서보모터를 이동
# 180도 되면 스위치1을 눌러도 180도 유지
# 0도가 되면 스위치2를 눌러도 0도 유지
# 0도와 180도가 되면 부저에서 소리가 출력
# 90도가 되면 led 불 켜지도록 작업
# duty를 구하고 설정하는 것은 함수로 처리
# 나머지도 함수로 처리할 수 있는 것들은 처리해보기
from RPi import GPIO
import time

servo_pin = 19
angle = 0
push_btn1 = 20
push_btn2 = 21
led_pin = 22
buzzer_pin = 26

GPIO.setmode(GPIO.BCM)
GPIO.setup(servo_pin, GPIO.OUT)
GPIO.setup(push_btn1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(push_btn2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(led_pin, GPIO.OUT)
GPIO.setup(buzzer_pin, GPIO.OUT)

servo = GPIO.PWM(servo_pin, 50)
servo.start(2.5)
buzzer = GPIO.PWM(buzzer_pin, 262)
buzzer.start(0)


def getDuty(degree):
    duty = degree / 180 * 10 + 2.5
    return duty


def buzzer_on():
    buzzer.ChangeDutyCycle(50)
    time.sleep(0.1)
    buzzer.ChangeDutyCycle(0)


def check_90():
    if angle == 90:
        GPIO.output(led_pin, GPIO.HIGH)
    else:
        GPIO.output(led_pin, GPIO.LOW)


def btn_call1(channel):
    global angle
    if angle != 180:
        angle += 10
        servo.ChangeDutyCycle(getDuty(angle))
    if angle == 180:
        buzzer_on()
    check_90()


def btn_call2(channel):
    global angle
    if angle != 0:
        angle -= 10
        servo.ChangeDutyCycle(getDuty(angle))
    if angle == 0:
        buzzer_on()
    check_90()


GPIO.add_event_detect(push_btn1, GPIO.RISING, callback=btn_call1, bouncetime=200)
GPIO.add_event_detect(push_btn2, GPIO.RISING, callback=btn_call2, bouncetime=200)
try:
    while True:
        pass
except KeyboardInterrupt:
    pass
finally:
    servo.ChangeDutyCycle(2.5)
    time.sleep(0.5)
    servo.stop()
    buzzer.stop()
    GPIO.cleanup()

  ※ 작업 중 GPIO.add_event_detect 관련 이슈

    - callback 함수 내에 sleep 으로 딜레이가 있는 경우의 문제

      -> sleep이 bouncetime보다 긴 경우, 마치 디바운싱이 안되는 것처럼 callback 함수를 두 번 실행하는 현상 발생

      -> 방법1: sleep 시간을 bouncetime보다 짧게 주는 방법

      -> 방법2: callback 함수가 실행되는 동안은 event가 detect 되지 않도록 하는 방법

      -> 방법1은 내가 원하는 만큼 sleep 시간이나 bouncetime 시간을 줄 수 없는 문제

      -> 방법2는 callback 함수가 실행되는 동안에도 event를 detect 해야 하는 경우 문제 발생

      -> 어떤 해결 방법이 있을지 찾아보고 고민해 보아야 할 것 같다.

 

- 끝 -

728x90