マイコンとセンサーで「入店音」を鳴らそう
はじめに
先日、部活の展示の際にお客さんが中々こない時間に作業をしていたら、いざお客さんが来た時にすぐ気づけなくて申し訳ないことをしてしまいその反省から来客を検知できるものをドアに貼り付けておきたいなと思ったのが始まりです。
今回は、安価で手に入るArduinoと人感センサー(焦電型赤外線センサー)を使って、人が通るとあの「某コンビニの入店音」が流れる装置を作ります。
この記事書き終わった後に部屋の中からRasberry Pi pico2がでてきたのでそちらの方がコンパクト(材料費も安いので)ついでにその配線とプログラムも掲載しておきます。
正直な話picoで実装するほうがおすすめです。
焦電型赤外線センサは表面のレンズが赤外線を集め、内部の焦電素子が温度の変化を電気信号に変えることで動きを検知する仕組みです。発信機と受信機の2つを用意しなくても使えるのでコンパクトでありがたい存在です。(発信機と受信機の場合出入り口の左右に取り付けるので配線が面倒なので...)
準備したもの
今回使用する部品は以下の通りです。
- Arduino UNO R3
※たまたま手元にあっただけなのでもっと安いものでいいです - 焦電型赤外線検出ユニット (PSUP7C-02-NCL-16-1)
※購入時640円(税込み) - 圧電スピーカー (PT08-Z185R)
※購入時100円(税込み) - ブレッドボード(基盤)
- ジャンパー線
回路の接続
各部品を、下の図の通りにブレッドボード上で接続します。あとは好きにはんだ付けなどしてお気に入りのケースにはめ込んで取り付けしやすいようにしましょう。
1. 人感センサーの接続
| センサー側ピン | 接続先(Arduino側) |
|---|---|
| Vcc (電源) | 5V |
| Gnd (接地) | GND |
| Dout (信号出力) | デジタル2番ピン |
2. 圧電スピーカーの接続
| スピーカー側 | 接続先(Arduino側) |
|---|---|
| プラス(+) | デジタル8番ピン |
| マイナス(-) | GND |
コード全体
回路が完成したら、Arduino IDEを開いて以下のコードをすべてコピー&ペーストし、Arduinoに書き込みましょう。
メロディーの定義に必要なpitches.hファイルも今回のプログラムと同一ディレクトリ内に保存をしてbuildをしてください。
#include "pitches.h"
// ----- ピン設定 -----
const int SENSOR_PIN = 2;
const int SPEAKER_PIN = 8;
// ----- 某コンビニ入店音のメロディー定義 -----
int melody[] = {
NOTE_FS5, NOTE_D5, NOTE_A4, NOTE_D5,
NOTE_E5, NOTE_A5, 0, NOTE_E4,
NOTE_E5, NOTE_FS5, NOTE_E5, NOTE_A4,
NOTE_D5, 0
};
// 音の長さ
int noteDurations[] = {
8, 8, 8, 8,
8, 8, 8, 8,
8, 8, 8, 8,
4, 4
};
// ----- グローバル変数 -----
bool isDetecting = false;
// ----- セットアップ関数 -----
void setup() {
Serial.begin(9600);
pinMode(SENSOR_PIN, INPUT);
// センサーの安定待ち時間
Serial.println("センサーの安定化待機中(約60秒)...");
delay(61000);
Serial.println("センサーの準備ができました。");
// 準備完了を知らせる音を3秒間鳴らす
tone(SPEAKER_PIN, 880); // 音を鳴らし始める
delay(3000); // 3秒間待つ
noTone(SPEAKER_PIN); // 音を止める
}
// ----- メインループ -----
void loop() {
int sensorState = digitalRead(SENSOR_PIN);
if (sensorState == LOW) {
if (!isDetecting) {
Serial.println("検知しました!メロディーを再生します。");
playFamimaChime();
isDetecting = true;
// メロディー再生後、10秒間は再検知しない
delay(10000);
}
} else {
if (isDetecting) {
Serial.println("非検知状態に戻りました。");
isDetecting = false;
}
}
delay(100);
}
// ----- 某コンビニのチャイムを再生する関数 -----
void playFamimaChime() {
int songLength = sizeof(melody) / sizeof(melody[0]);
for (int thisNote = 0; thisNote < songLength; thisNote++) {
int noteDuration = 1000 / noteDurations[thisNote];
tone(SPEAKER_PIN, melody[thisNote], noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
noTone(SPEAKER_PIN);
}
}
ヘッダーファイル (pitches.h)
上記のメインコードを動作させるには、このpitches.hファイルが同じフォルダに必要です。Arduino IDEで新しいタブを作成し、ファイル名をpitches.hとして以下の内容を貼り付けてください
/*************************************************
* Public Constants
*************************************************/
#ifndef PITCHES_H
#define PITCHES_H
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
#endif
Raspberry Pi Pico版
同じことは、Raspberry Pi Pico(またはPico W)でも実現できます。Picoを使う場合は、プログラム言語がMicroPythonに変わります。
準備するもの
- Raspberry Pi Pico (W)
- その他はArduinonの際と同じです。
回路の接続 (Pico版)
| 部品 | 接続元 | → | 接続先 |
|---|---|---|---|
| 人感センサー Vcc | センサー Vccピン | → | Pico 3V3(OUT)ピン(ピン36)【3.3V電源】 |
| 人感センサー Gnd | センサー Gndピン | → | Pico GNDピン(ピン38など) |
| 人感センサー Dout | センサー Doutピン | → | Pico GP15ピン(ピン20) |
| スピーカー プラス(+) | スピーカー (+) | → | Pico GP16ピン(ピン21) |
| スピーカー マイナス(-) | スピーカー (-) | → | Pico GNDピン(ピン38など) |
MicroPythonコード
開発環境のThonny IDEを開き、以下のコードをPicoにmain.pyという名前で保存してください。
import machine
import time
# ----- ピン設定 -----
# センサーのDoutピンをPicoのGP15に接続
sensor_pin = machine.Pin(15, machine.Pin.IN)
# スピーカーをPicoのGP16に接続
buzzer_pin = machine.Pin(16)
# PWM(パルス幅変調)で音を制御する準備
buzzer = machine.PWM(buzzer_pin)
# ----- 某コンビニ入店音のメロディー定義 -----
# Note(周波数)の定義
NOTE_A4 = 440
NOTE_D5 = 587
NOTE_E5 = 659
NOTE_FS5 = 740
NOTE_A5 = 880
NOTE_E4 = 330
# メロディーと音の長さのリスト
melody = [
NOTE_FS5, NOTE_D5, NOTE_A4, NOTE_D5,
NOTE_E5, NOTE_A5, 0, NOTE_E4, # 0は休符
NOTE_E5, NOTE_FS5, NOTE_E5, NOTE_A4,
NOTE_D5, 0
]
note_durations = [
8, 8, 8, 8,
8, 8, 8, 8,
8, 8, 8, 8,
4, 4
]
# ----- 関数定義 -----
def play_chime():
"""メロディーを再生する関数"""
try:
for i in range(len(melody)):
note = melody[i]
# 4分音符を250msとして長さを計算
duration_sec = (1.0 / note_durations[i]) * 1.0
if note == 0:
time.sleep(duration_sec) # 休符
else:
buzzer.freq(note) # 周波数を設定
buzzer.duty_u16(32768) # 50%のデューティ比で音を鳴らす
time.sleep(duration_sec * 0.9) # 音符の長さだけ待つ
buzzer.duty_u16(0) # 音を止める
time.sleep(duration_sec * 0.1) # 音の間に短い休止を入れる
finally:
buzzer.duty_u16(0) # 念のため最後に音を止める
# ----- ここからプログラムが開始 -----
# 1. センサーの安定待ち時間
print("センサーの安定化待機中(約60秒)...")
time.sleep(61) # 仕様書に基づき61秒待機
print("センサーの準備ができました。")
# 2. 準備完了を知らせる音を3秒間鳴らす
print("準備完了を音で通知します。")
buzzer.freq(880) # 880Hzの音に設定
buzzer.duty_u16(32768) # 音を鳴らし始める
time.sleep(3) # 3秒間待つ
buzzer.duty_u16(0) # 音を止める
# 3. メインループ
is_detecting = False # 検知状態フラグ
print("来客検知を開始します。")
while True:
# センサーが人を検知するとピンの値が0(LOW)になる
if sensor_pin.value() == 0:
if not is_detecting:
is_detecting = True
play_chime()
# 10秒間のクールダウン
print("10秒間のクールダウン...")
time.sleep(10)
else:
if is_detecting:
print("非検知状態に戻りました。")
is_detecting = False
time.sleep(0.1) # ループの負荷を少し下げる

