FUJITSU Advent Calendar 2017 8日目の記事です。
昨年はSI現場でいろいろ作った話を書きました。今回は仕事とは無関係。
こんなものが出来上がります
(動画は音が鳴ります)
DIYスマートホーム デモ動画 pic.twitter.com/tZt7Csqpz6
— Yamaguchi Takuya (@yamaguchi_39_jp) 2017年12月3日
人間はぼけーっと起きただけで何もしていません。
とある未来の家のお話…
朝、起床時間。
照明が徐々に明るくなり、カーテンがゆっくりと開く。
すべて機械が自動的にやってくれる。そろそろテレビの電源が入るだろう。タイミングはバッチリ。柔らかな日射しに、自然と目が覚める。爽やかな朝だ。
…という夢を見たんだ。
10年以上前、IT系の雑誌でこんな話を読んだ記憶があります。
しかし残念なことに、一人暮らしの私の部屋にその未来は訪れていません。
でも、ちょっとでもそういう未来に近づいてみたい。
というわけで、Raspberry Piを使って手作り感あふれる「DIY未来」を作ってみました。
材料
品名 | 価格 | 備考 (私が買ったもの) |
---|---|---|
Raspberry Pi 3 Model B | \5,000 | ネットワーク接続できれば別モデルでもOK |
ブレッドボード | \200 | BB-801 (秋月 P-05294) |
ジャンパーワイヤ (オス-オス) | \180 | 秋月 C-05371 |
ジャンパーワイヤ (オス-メス) | \220 | 秋月 C-08934 |
人感センサ(焦電型赤外線センサ) | \500 | SB412A (秋月 M-09002) |
ACアダプタ 5V (0.5A~) | \650 | GF12-US0520 (秋月 M-01801) |
DCジャック DIP化モジュール | \313 | マルツエレック DC-POWER-JACK基板(MDK024) |
電解コンデンサ 100μF | \10 | ルビコンPX 100μF/16V/105℃ (秋月 P-10271) |
サーボモータ | \400 | SG-90 (秋月 M-08761) |
USB オーディオ変換アダプタ(DAC) | \1,220 | BUFFALO BSHSAU01BK |
スピーカ | - | (PC用スピーカを流用) |
オーディオケーブル | - | (余ってたものを流用) |
各材料について
- ブレッドボード、ジャンパーワイヤ
- Raspberry Piと各電子部品との接続に用います。
- 人感センサ
- 人(熱源)が動くと反応します。
- サーボモータ
- 普通のモータと違い、"指示した位置(角度)まで動いてくれる"モータです。照明をつけるのに使います。
- ACアダプタ、DCジャック、電解コンデンサ
- サーボモータへの電源供給用です(コンデンサは動作安定化のため)。照明をつけるのに使います。なぜDCジャックだけマルツが登場するのかというと、ハンダ付け済みだからです(手抜き)。
※RasPiの+5Vで事足りるかもしれませんが未検証です。 - USB オーディオ変換アダプタ(DAC)、スピーカ、オーディオケーブル
- 音楽や音声を流すのに使います。
USB DACを用意するのは、サーボモータでPWM機能を使うとRasPiのアナログ音声出力が使えなくなるためです。
1. 起きたらクラシックを流し、帰ったら「おかえり」と喋ってもらう
最初に簡単なところから。人感センサに反応して音声再生をさせます。
人感センサとスピーカを繋ぐ
まずは人感センサを繋ぎます。SB412Aのピンそばに表示があるので、確認しつつ接続します。
SB412Aのピン表示 | Raspberry Piのピン | 補足 |
---|---|---|
"+" | +5V | +5Vは2箇所あるがどちらでもOK。+3.3Vでも動作 |
"VO" (Vout) | GPIO4 | 任意のGPIOでもOK |
"-" | GND | GNDは複数箇所あるがどこでもOK |
そして、Raspberry PiにUSB オーディオ変換アダプタ(DAC)を接続し、さらにスピーカの入力端子とをオーディオケーブルで繋ぎます。ちなみにDACへ出力するためにはちょっと工夫がいります(参考:Rapberry Pi に USB DAC をつないでオーディオサーバーにする (接続編) - Qiita)。
スクリプトを書く
人感センサの出力(Vout)は通常LOWで、熱源が動くとしばらくHIGHになります。
これを利用して、長時間センサがLOWのままだと就寝・外出とみなし、そこからHIGHになったタイミングで起床・帰宅と判断します。
スクリプトはPythonで。
GPIOの入力はRPi.GPIOモジュールを、音声再生にはomxplayerをsubprocessモジュールで実行しています。omxplayerではなくmpg321等でもかまいません。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -- 設定
pin = 4 # センサのGPIOピン
welcome_sound_seconds = 180 * 60 # 外出・就寝したとみなす無反応時間(秒)
watch_interval_seconds = 5 # 監視間隔(秒)
# -- スクリプト
import RPi.GPIO as GPIO
from time import sleep
import subprocess
import datetime
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.IN)
off_seconds = 0
away_from_room = False
try:
while True:
# 経過時間を測定
value = GPIO.input(pin)
if value == 0:
off_seconds += watch_interval_seconds
else:
off_seconds = 0
if away_from_room == False and off_seconds >= welcome_sound_seconds:
# 外出モードオン
away_from_room = True
print(datetime.datetime.now())
print("value:", value, ", off_seconds:", off_seconds)
print("away:", away_from_room)
if away_from_room == True and off_seconds == 0:
# 外出モードオフ
away_from_room = False
hour = datetime.datetime.now().hour
if hour > 4 and hour < 12:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/peergynt_morning.mp3'])
else:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/welcome.mp3'])
print(datetime.datetime.now())
print("value:", value, ", off_seconds:", off_seconds)
print("away:", away_from_room)
sleep(watch_interval_seconds)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
音声ファイルはscp(WinSCP)などでRaspberry Piに転送しておきます。
また、omxplayerが入っていなければインストールしておきます。
$ sudo apt-get install omxplayer
人感センサの設置場所を決める
下記を満たすような、絶妙な場所を探して配置します。
- 就寝時には反応しない
- 起床時、帰宅時には反応する
- 在宅中にも「外出・就寝とみなす無反応時間(3時間)」以内にちょくちょく反応する
データシートでは、検出角度は100度、最大検出距離は3~5mとなっています。この辺も加味します。
デモンストレーション
無反応時間を10秒に設定して確かめてみます。よい感じです。
DIYスマートホーム 音声再生サンプル pic.twitter.com/xncQEKlPNH
— Yamaguchi Takuya (@yamaguchi_39_jp) 2017年12月3日
※動画では権利的に微妙なのでゆっくりに喋ってもらいましたが、実際はトールとカンナちゃん(小林さんちのメイドラゴン #11)が「おかえり(なさい)」と言ってくれます。最高です。
2. テレビじゃなくてPCの電源を入れてもらう
PCがないと落ち着かない人間なので、人感センサに反応したらPCの電源を入れてもらいます。
ここではWake on LAN機能を使います。
ネットワーク越しに特殊なパケットを送りつけることで電源が入ります。
PCのWake on LAN(WoL)を有効にし、MACアドレスを確認する
BIOS・OS・NIC(ドライバ)によって設定方法が異なるので、手順は端折ります。
MACアドレスは ipconfig /all (Windows) とかで。
※Windows 10+Realtek(RTL8111F) NICの組み合わせだと、設定を有効にしても機能せず、公式サイトから最新版ドライバをインストールしたらやっと機能した、ということがありました。
スクリプトを書く
まずは wakeonlan をインストールしておきます。
$ sudo apt-get install wakeonlan
さっきのスクリプトの「外出モードオフ」のところに、wakeonlanコマンドを実行するようにコードを追加します。
if away_from_room == True and off_seconds == 0:
# 外出モードオフ
away_from_room = False
hour = datetime.datetime.now().hour
if hour > 4 and hour < 12:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/peergynt_morning.mp3'])
else:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/welcome.mp3'])
print(datetime.datetime.now())
print("value:", value, ", off_seconds:", off_seconds)
print("away:", away_from_room)
# PCの電源を入れる
subprocess.Popen(['wakeonlan', '00:00:5E:00:53:01'])
3. 照明をつけてもらう
最後に、照明をつけてもらうようにします。
といっても、電気工事とかは怖くてできません。
そこで、サーボモータに照明のスイッチを押してもらいます。
サーボモータを繋ぐ
サーボモータ、ACアダプタ、DCジャック、コンデンサを繋ぎます。
※電解コンデンサは極性があるので+-逆に繋がないよう注意します。
SG-90のワイヤ色 | 接続先 | 補足 |
---|---|---|
橙 (PWM) | RasPi GPIO18 | GPIO18限定。PWM機能を使用 |
赤 (+) | DCジャック + | |
茶 (-) | DCジャック - と RasPi GND | RasPi GNDは複数箇所あるがどこでもOK |
サーボモータの動かし方
サーボモータを動かすには"PWM"を使います。
一定周期で信号のON/OFFを繰り返すのですが、そのON/OFFの比率(デューティ比)によって、サーボモータの位置を指示できます。
サーボモータの設置場所とスクリプトを試行錯誤する
「スイッチを押す」という動きを実現するには、試行錯誤するしかありません。
Raspberry Piでサーボモータ(SG90)を制御する|Buffer Overruns を参考にしつつ、サーボモータの設置場所と指示角度・指示タイミングを決めます。
※サーボモータには、付属する白い部品(ホーン[Horn]:角)をつけておきます。
余っているダンボールとセロハンテープで固定。急に手作り感が出てきました。
そしてPythonスクリプトを書いては調整を繰り返し、安定してスイッチが押せるようになりました。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
gp_out = 18
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0.0)
time.sleep(0.2)
servo.ChangeDutyCycle(9)
time.sleep(0.2)
servo.ChangeDutyCycle(11.5)
time.sleep(0.2)
servo.ChangeDutyCycle(9)
time.sleep(0.2)
servo.stop()
サーボモータのようす
がんばってスイッチを押してくれています。
スクリプトを書く
GPIO18をPWM出力として初期化し、サーボモータを動かす処理を組み込みました。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -- 設定
pin = 4 # センサのGPIOピン
pwm_pin = 18 # サーボモータのPWM制御ピン
welcome_sound_seconds = 180 * 60 # 外出・就寝したとみなす無反応時間(秒)
watch_interval_seconds = 5 # 監視間隔(秒)
# -- スクリプト
import RPi.GPIO as GPIO
from time import sleep
import subprocess
import datetime
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.IN)
GPIO.setup(pwn_pin, GPIO.OUT)
servo = GPIO.PWM(pwn_pin, 50)
off_seconds = 0
away_from_room = False
try:
while True:
# 経過時間を測定
value = GPIO.input(pin)
if value == 0:
off_seconds += watch_interval_seconds
else:
off_seconds = 0
if away_from_room == False and off_seconds >= welcome_sound_seconds:
# 外出モードオン
away_from_room = True
print(datetime.datetime.now())
print("value:", value, ", off_seconds:", off_seconds)
print("away:", away_from_room)
if away_from_room == True and off_seconds == 0:
# 外出モードオフ
away_from_room = False
hour = datetime.datetime.now().hour
if hour > 4 and hour < 12:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/peergynt_morning.mp3'])
else:
subprocess.Popen(['omxplayer', '-o', 'alsa', '/home/pi/Music/welcome.mp3'])
print(datetime.datetime.now())
print("value:", value, ", off_seconds:", off_seconds)
print("away:", away_from_room)
# PCの電源を入れる
subprocess.Popen(['wakeonlan', '00:00:5E:00:53:01'])
# サーボモータを動かす
servo.start(0.0)
sleep(0.2)
servo.ChangeDutyCycle(9)
sleep(0.2)
servo.ChangeDutyCycle(11.5)
sleep(0.2)
servo.ChangeDutyCycle(9)
sleep(0.2)
servo.stop()
sleep(watch_interval_seconds)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
完成: 未来がやってきた!
出来上がりました。動画は冒頭に載せたので省略。
既に1ヶ月ほど運用していますが、安定して動いています。照明スイッチの押し損ねもありません。
見た目は不格好でスマートさのかけらもありませんが、DIYで未来がやってきました!
おわりに
意外と便利、何より楽しい
「勢いで買ったけどどうしよ…」と思っていましたが、割と便利なものが出来ました。
既製品では出来ないヘンテコな動きも自由にできるのが良いです。
また、ソフトウェアだけでは出来ない「物理的なフィードバック」は非常に楽しいです。
代償: お金と時間
あんまり楽しいので、2ヶ月くらい毎週秋月に通っていました。
ここに載せていない電子部品も色々買っていて、合算すると結構な額に…
もっと未来へ
まだまだ何かできそうです。
最近スマートスピーカが流行りだしてきたので、ラズパイさんに音声認識で電気を消してもらいました。
『ラズパイさん、電気消して』 pic.twitter.com/yZyt0U2XCR
— Yamaguchi Takuya (@yamaguchi_39_jp) 2017年12月3日
完璧…! と思ったのですが、実際に運用すると3回に1回しか反応しませんでした。悲しくなったので使っていません。
うーん、次は何をしようかな。
参考
- 秋月電子通商のWebサイトから参照できるデータシート各種 (材料のリンクから参照ください)
- Raspberry Piに焦電型赤外線(人感)センサーを接続してみた - Qiita
- 家に帰ると小林さんちのメイドラゴンのカンナちゃんが「おかえりー」って言ってくれる装置を作った - Qiita
- Raspberry Piでサーボモータ(SG90)を制御する|Buffer Overruns
- Raspberry PiのPWMはアナログ音声出力と共用 - Qiita
- Rapberry Pi に USB DAC をつないでオーディオサーバーにする (接続編) - Qiita
- Julius 独自辞書作成方法 - Qiita
- 文書に記述する際の説明用/例示用のドメイン名、IPアドレス、MACアドレス RFC6890,RFC5737,RFC3849,RFC2606,RFC6761,RFC7042 IANAなどなど – Abacus Technologies Blog – kana.me 要
これは個人の見解であり、所属する組織の公式な見解ではありません。