LoginSignup
9
7

More than 5 years have passed since last update.

スマートじゃないDIYスマートホーム

Last updated at Posted at 2017-12-07

FUJITSU Advent Calendar 2017 8日目の記事です。
昨年はSI現場でいろいろ作った話を書きました。今回は仕事とは無関係。

こんなものが出来上がります

(動画は音が鳴ります)

人間はぼけーっと起きただけで何もしていません。

とある未来の家のお話…

朝、起床時間。

照明が徐々に明るくなり、カーテンがゆっくりと開く。
すべて機械が自動的にやってくれる。そろそろテレビの電源が入るだろう。タイミングはバッチリ。

柔らかな日射しに、自然と目が覚める。爽やかな朝だ。

…という夢を見たんだ。

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のピンそばに表示があるので、確認しつつ接続します。

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秒に設定して確かめてみます。よい感じです。

※動画では権利的に微妙なのでゆっくりに喋ってもらいましたが、実際はトールとカンナちゃん(小林さんちのメイドラゴン #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

qiita_2_ブレッドボード_.png

サーボモータの動かし方

サーボモータを動かすには"PWM"を使います。
一定周期で信号のON/OFFを繰り返すのですが、そのON/OFFの比率(デューティ比)によって、サーボモータの位置を指示できます。

サーボモータの設置場所とスクリプトを試行錯誤する

「スイッチを押す」という動きを実現するには、試行錯誤するしかありません。
Raspberry Piでサーボモータ(SG90)を制御する|Buffer Overruns を参考にしつつ、サーボモータの設置場所と指示角度・指示タイミングを決めます。

20171202_PC020950.jpg

※サーボモータには、付属する白い部品(ホーン[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ヶ月くらい毎週秋月に通っていました。
ここに載せていない電子部品も色々買っていて、合算すると結構な額に…

もっと未来へ

まだまだ何かできそうです。
最近スマートスピーカが流行りだしてきたので、ラズパイさんに音声認識で電気を消してもらいました。

完璧…! と思ったのですが、実際に運用すると3回に1回しか反応しませんでした。悲しくなったので使っていません。

うーん、次は何をしようかな。

参考


これは個人の見解であり、所属する組織の公式な見解ではありません。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7