라즈베리파이로 악기 연주하기

1.초음파 센서 + RPi.GPIO

  • 초음파 센서로 거리 측정하여 LED 켜고 끄기
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

trig=13
echo=26
LED=21
GPIO.setup(trig, GPIO.OUT)
GPIO.setup(echo, GPIO.IN)
GPIO.setup(LED, GPIO.OUT, initial=GPIO.LOW)
    
print("start")

try:
    while True:
        GPIO.output(trig, GPIO.LOW)
        time.sleep(1)
        GPIO.output(trig, GPIO.HIGH)
        time.sleep(0.001)
        GPIO.output(trig, GPIO.LOW)

        start=0
        end=0
        
        while GPIO.input(echo)==GPIO.LOW:
            start=time.time()
        while GPIO.input(echo)==GPIO.HIGH:
            end=time.time()

        duration=end-start
        distance=(duration*340*100)/2
        print("distance: %dcm" %distance)
    
        if distance <= 10:
            GPIO.output(LED, GPIO.HIGH)
        else:
            GPIO.output(LED, GPIO.LOW)
        
except KeyboardInterrupt:
    GPIO.cleanup()

print("finish")

▷ 초음파 센서가 감지한 거리가 10cm 이하이면 LED를 켜고, 10cm보다 멀어지면 LED를 끈다.

https://m.blog.naver.com/PostView.nhn?blogId=chandong83&logNo=221155355360&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F
위 블로그를 참고하여 회로도를 구성하였다.

2.python의 pygame.midi 라이브러리

  • 중간 도부터 높은 도까지의 음 연주하기(피아노, 바이올린)
import pygame, pygame.midi
import time
instrument = 0  # 0 = GRAND_PIANO

pygame.init()
pygame.midi.init()

def sound(sound, loud):
    midi_out.note_on(sound, loud)
    time.sleep(0.5)
    midi_out.note_off(sound, loud)
    time.sleep(0.1)

port = pygame.midi.get_default_output_id()
print("using output_id : %s" %port)
midi_out = pygame.midi.Output(port, 0)

midi_out.set_instrument(instrument)
sound(72, 127)  # 72 = middle C  # loud : 0 ~ 127
sound(74, 127)  
sound(76, 127)
sound(77, 127)  # 미-파 : 반음 차이

instrument = 42  # 42 = Violin
midi_out.set_instrument(instrument)
sound(79, 127)  
sound(81, 127)
sound(83, 127)
sound(84, 127)  # 시-도 : 반음 차이

del midi_out
pygame.midi.quit()

▷ 중간 도부터 파까지는 피아노로, 솔부터 높은 도까지는 바이올린으로 연주한다.

위 코드는 노트북에서는 실행되었으나, 라즈베리파이에서는 실행되지 않았다.
라즈베리파이에서 다른 음악이나 영상의 소리는 출력되었기 때문에,
소리 출력의 문제가 아닌 python의 pygame.midi 라이브러리의 문제인 것으로 예상했다.

3.python의 pygame.mixer 라이브러리

  • 초음파 센서로 거리 측정하여 음악 재생하고 정지하기
import RPi.GPIO as GPIO
import pygame
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
pygame.init()
pygame.mixer.init()

trig = 4
echo = 18
GPIO.setup(trig, GPIO.OUT)
GPIO.setup(echo, GPIO.IN)

music = "Ed Sheeran - Thinking Out Loud.mp3"
pygame.mixer.music.load(music)

DISTANCE = 5
before = [0]
now = [0]

def measure_distance(num):
    GPIO.output(trig, GPIO.LOW)
    time.sleep(1)
    GPIO.output(trig, GPIO.HIGH)
    time.sleep(0.001)
    GPIO.output(trig, GPIO.LOW)

    start = 0
    end = 0

    while GPIO.input(echo) == GPIO.LOW:
        start = time.time()

    while GPIO.input(echo) == GPIO.HIGH:
        end = time.time()

    duration = end - start
    distance = (duration*340*100) / 2     # 단위 : cm
    print("distance: %dcm" %distance)

    return distance

def state(num, distance):
    if distance <= DISTANCE:
        now[num] = 1
    else:
        now[num] = 0

def change(num):
    distance = measure_distance(num)
    before[num] = now[num]
    state(num, distance)
    
    if before[num] != now[num]:
        return 1
    else:
        return 0
    
def sense(num):
    if change(num) == 0:
        print("stay")
        return 0    #stay
    elif now[num] == 1:     # now[num] == state(distance)
        print("on")
        return 1    #on
    else:
        print("off")
        return -1   #off

def sound_on(num):
    pygame.mixer.music.play()

def sound_off(num):
    pygame.mixer.music.stop()
    
#---
    
try:
    while True:
        sns = sense(0) 
        if sns == 0:
            pass
        elif sns == 1:
            print("on")
            sound_on(0)
        else:
            print("off")
            sound_off(0)

except KeyboardInterrupt:
    GPIO.cleanup()

※ 소스 파일이 저장된 폴더에 “Ed Sheeran – Thinking Out Loud.mp3” 파일을 포함시킨 후 실행했다.

▷ 초음파 센서가 감지한 거리가 5cm 이하가 되면 음악 재생을 시작하고, 5cm보다 멀어지면 음악 재생을 정지한다.

위 코드가 파이에서 실행됨으로써, 앞서 소리가 출력되지 않은 것은 midi 라이브러리의 문제였던 것이 확인되었다.

  • 라즈베리파이로 악기 연주하기
                                                                                                                                                                                                                                                                                                                                                                                          # setting
import RPi.GPIO as GPIO
import pygame
import time
SENSOR = 4
DISTANCE = 10    #cm

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
pygame.init()
pygame.mixer.init()

trig = [4, 17, 27, 6]
echo = [18, 23, 24, 12]
for i in trig:
    GPIO.setup(i, GPIO.OUT)
for i in echo:
    GPIO.setup(i, GPIO.IN)

sound_channel = [0, 0, 0]
for i in range(3):
    sound_channel[i] = pygame.mixer.Channel(i + 1)

sound_list = [[], [], []]
sound_list[0] = ["piano-C4.wav", "piano-G4.wav", "piano-C5.wav"]
sound_list[1] = ["trumpet-C4.wav", "trumpet-G4.wav", "trumpet-C5.wav"]
sound_list[2] = ["violin-C4.wav", "violin-G4.wav", "violin-C5.wav"]

for i in range(3):
    for j in range(3):
        sound_list[i][j] = pygame.mixer.Sound(sound_list[i][j])

before = [0 for i in range(SENSOR)]
now = [0 for i in range(SENSOR)]

global count
count = 0

# ---

def measure_distance(num):
    trg = trig[num]
    ech = echo[num]
    
    GPIO.output(trg, GPIO.LOW)
    time.sleep(0.001)
    GPIO.output(trg, GPIO.HIGH)
    time.sleep(0.001)
    GPIO.output(trg, GPIO.LOW)

    start = 0
    end = 0

    while GPIO.input(ech) == GPIO.LOW:
        start = time.time()

    while GPIO.input(ech) == GPIO.HIGH:
        end = time.time()

    duration = end - start
    distance = (duration*340*100) / 2     #cm
    #print("sensor = %d   distance: %dcm" %(num + 1, distance))

    return distance

def state(num, distance):
    if distance <= DISTANCE:
        now[num] = 1
    else:
        now[num] = 0

def change(num):
    distance = measure_distance(num)
    before[num] = now[num]
    state(num, distance)
    
    if before[num] != now[num]:
        return 1
    else:
        return 0

def sense(num):
    if change(num) == 0:
        return 'stay'
    elif now[num] == 1:     # now[num] == state(distance)
        return 'on'
    else:
        return 'off'

def change_instrument():
    if sense(SENSOR - 1) == 'on':
        global count
        count = (count + 1) % 3
        for i in range(SENSOR - 1):
            sound_channel[i].stop()
        print("\n< Musical instrument is changed >\n")
        
def sound_on(num):
    global count
    sound_channel[num].play(sound_list[count][num])

def sound_off(num):
    global count
    sound_channel[num].stop()

# ---

try:
    while True:
        change_instrument()
        for i in range(SENSOR - 1):
            sns = sense(i)
            if sns == 'stay':
                pass
            elif sns == 'on':
                sound_on(i)
                print("sensor %d on" %(i + 1))
            else:
                sound_off(i)
                print("sensor %d off" %(i + 1))

except KeyboardInterrupt:
    GPIO.cleanup()

※ 소스 파일이 저장된 폴더에 “piano-C4.wav”, “piano-G4.wav”, “piano-C5.wav”, “trumpet-C4.wav”, “trumpet-G4.wav”, “trumpet-C5.wav”, “violin-C4.wav”, “violin-G4.wav”, “violin-C5.wav” 파일을 포함시킨 후 실행했다.

▷ 3개의 초음파 센서는 각각 중간 도, 솔, 높은 도의 음을 담당한다.
▷ 초음파 센서에서 감지한 거리가 5cm 이하가 되면 악기 음 note가 재생된다.
거리가 5cm보다 멀어지면 음악 재생이 중단된다.
▷ 동시에 여러 음악이 재생될 수 있다.
▷ 왼쪽 끝의 초음파 센서는 악기를 바꾸는 역할을 담당한다. 한 번 감지할 때마다 피아노→트럼펫 → 바이올린 → 피아노 → … 의 순서대로 악기를 바꾼다.

광고