피에조 효과를 이용한 부저인데, 초음파 센서와 같은 효과로 동작한다. 진동 주파수를 이용해 원하는 음계를 낼 수 있다.
피에조 효과?
얇은 금속 판에 전기를 주면 진동이 발생하는데 그 발생된 진동으로 인해 파동이 생긴다. 이때 생긴 파동이 귀에 들리는 소리 영역이라면 음파라고 칭하며, 부저로 동작한다. 귀에 들리지 않는 소리 영역이라면 초음파라고 칭하며, 초음파 센서로 동작한다.
buzzer | raspberry pi gpio pin num |
---|---|
s | gpio14 |
- | gnd |
vcc | 5v |
btn | esp32 pin |
---|---|
buzzer btn1 | gnd |
buzzer btn2 | gpio17 |
Tone
나중에 부저로 멜로디를 쓸 일이 있을까 싶어서 음계별 주파수를 딕셔너리로 만들었다.
TONE_DIC = {
'c4': 261.62,
'c4#': 277.18,
'd4': 293.66,
'd4#': 311.12,
'e4': 329.62,
'f4': 349.22,
'f4#': 369.99,
'g4': 391.99,
'g4#': 415.3,
'a4': 440,
'a4#': 466.16,
'b4': 493.88,
'c5': 523.25,
'c5#': 554.36,
'd5': 587.32,
'd5#': 622.24,
'e5': 659.25,
'f5': 698.45,
'f5#': 739.98,
'g5': 783.99,
'g5#': 830.6,
'a5': 880,
'a5#': 932.32,
'b5': 987.76,
}
etc_thread.py
etc
topic을 구독하게 했다. buzzer_on
이 들어오면 (= ESP32에 연결된 버튼이 pressed 상태에 접어드는 순간) 부저를 play()
하는데, 적당히 C4정도로 줬다. (부저 성능이 안 좋은 건지 소리가 약간 찢어진다;)buzzer_off
가 들어오면 (= ESP32에 연결된 버튼이 released 상태에 접어드는 순간) play되고 있던 부저를 stop()
한다. etc_thread.py
import threading
from gpiozero import TonalBuzzer
import socket
import paho.mqtt.client as mqtt
import tone_dic
class EtcThread(threading.Thread):
BROKER_ADDRESS = socket.gethostbyname(socket.gethostname())
buzzer = TonalBuzzer(14)
def __init__(self):
super().__init__()
self.client = mqtt.Client("etc_sub")
self.client.connect(self.BROKER_ADDRESS)
self.client.subscribe("etc")
self.client.on_message = self.on_command
def on_command(self, client, userdata, message):
cmd = str(message.payload.decode("utf-8"))
if "buzzer_on" == cmd:
self.buzzer.play(tone_dic.TONE_DIC['c4'])
elif "buzzer_off" == cmd:
self.buzzer.stop()
def run(self):
self.client.loop_forever()
main app.py
스레드 객체로 만든 거니까 app.py 에서도 생성&실행을 해줘야 한다.
import cmd_thread
import etc_thread
if __name__ == '__main__':
# ... cmd thread 생성 & start
etc_th = etc_thread.EtcThread()
etc_th.start()
직진, 후진 버튼을 만들었던 것처럼 마찬가지로 thread로 press/release 상태를 측정한다.
buzzer_button_check()
: 커스텀 객체가 아닌, 기본 Thread
객체를 만들어서 interval 마다 주기적으로 실행할 함수를 정의했다. COMMAND_XXX
는 값이 바뀌지 않는 한 mqtt 송신을 한 번만 보내도록 하기 위해 만든 bool 변수로 volatile
키워드를 추가해 과하게 똑똑한 컴파일러의 방해(!)를 차단했다.#define BUZZER_BUTTON 17 // the number of the buzzer button pin
// 한 번만 보내기 위한 flg 변수
volatile bool COMMAND_BUZZER = false;
char *ETC_TOPIC = "etc";
// ... EspMQTTClient 코드
// ... go/back command 실행될 스레드 함수 관련 코드
// ... mpu6050 값을 읽을 스레드 클래스 관련 코드
// ... mqtt 송신용 tx() 함수
// ...
// 스레드가 설정된 interval에 맞춰 주기적으로 실행할 함수
void buzzer_button_check(void) {
if (digitalRead(BUZZER_BUTTON) == LOW && !COMMAND_BUZZER) {
// Serial.println("buzzer_on");
tx(ETC_TOPIC, "buzzer_on");
COMMAND_BUZZER = true;
} else if (digitalRead(BUZZER_BUTTON) == HIGH && COMMAND_BUZZER) {
// Serial.println("buzzer_off");
tx(ETC_TOPIC, "buzzer_off");
COMMAND_BUZZER = false;
}
}
// create thread
Thread buzzer_th = Thread();
// ... thread controller 관련 코드
void setup(void) {
// ... serial monitor begin
// ... mqtt client enable
// ... command (go/back) button
// buzzer button
pinMode(BUZZER_BUTTON, INPUT_PULLUP);
// callback thread func
// ... (go/back) button callback thread func set
// buzzer button callback thread func set
buzzer_th.onRun(buzzer_button_check);
buzzer_th.setInterval(50);
// ... mpu thread add to thread controller
// ... cmd thread add to thread controller
// buzzer thread add to thread controller
controller.add(&buzzer_th);
// ... mpu init code
}