[Raspberry Pi] ペットを判別するトイレアラートを作ってみた

#作った背景
愛犬がトイレをした際に、自分が別の部屋にいると気づかず、すぐお世話できない、
という課題を解決するために作りました。
間違っている箇所やもっと良い書き方がありましたら、優しく教えてください。

#1.必要なもの 
- Raspberry Pi3 Model B
- Raspberry Pi カメラモジュール(webカメラでも可)
- 人感センサー
- ブレッドボード・ジャンパーワイヤ
- microSDカード
- microUSB給電ケーブル
- USB充電アダプター(推奨は5V/2.5A)
- USBマウス※
- USBキーボード※
- HDMIケーブル※
- HDMI対応ディスプレイ※

※ssh接続のみの場合は不要。
#2. セットアップ
基本的なセットアップをまとめます。
 
- microSDカードにOSの書き込み　
Raspbianをダウンロードし、microSDカードに書き込みます。
本サイトからダウンロードすると遅いので、日本語ミラーからダウンロードがおすすめ。
自分は以下から最新版をダウンロードしました。
http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian/images/
zipファイルを解凍後、Etcher(https://etcher.io) を使ってimgを書き込みました。

- 起動
ラズパイ本体に、USBケーブル、アダプター、ディスプレイ、マウス、キーボードを接続し起動する。
うまく起動しない場合、OSの書き込みに失敗しているか、USBアダプターの電流不足の可能性があります。

- piユーザーの名前変更
こちらの記事を参考にしました。→ https://jyn.jp/raspberrypi-username-change/

- パスワード変更 
`$ sudo raspi-config`でパスワード変更

- Wi-Fi接続、IPアドレス固定
	GUIからWi-Fiに接続しておき、ラズパイのIPアドレスを固定する。
こちらの記事を参考にしました。→　https://raspida.com/wifi4raspbian

- ssh接続
毎回ディスプレイ等を接続するのは面倒なので、他のPCから接続可能にします。
`$ sudo raspi-config`でSSHをYESにしておく。
`$ ssh user_name＠IPアドレス -p ポート番号`で接続できます。
- カメラモジュールを有効にする
カメラモジュールを接続し、`$ sudo raspi-config`でEnable CameraをYESにする。

- 人感センサーを取り付ける。

今回は、収納ボックスに入れてみました。高さ的にもトイレをきちんと監視できます。

![DdybE7iV0AExvEm.jpg](https://qiita-image-store.s3.amazonaws.com/0/206282/2220ba28-a4f8-b171-a5ea-71c59be78a02.jpeg)

![IMG_1956.JPG](https://qiita-image-store.s3.amazonaws.com/0/206282/3034e671-01a7-1530-7fad-e5c1aebe96cf.jpeg)


#3.機能実装
ここからが本番です。

大まかな流れとしては、
1) 人感センサーで人や犬を感知した際にカメラで撮影
2) Google Cloud Vision APIを使い、画像が犬かどうか判定
3) 犬だった場合、LINE notify APIを使って通知する
という流れです。LINEの通知と犬の判定はそれぞれ関数にまとめています。

細かい点をまとめます。

- LINE notify API(https://notify-bot.line.me/ja/) とGoogle Cloud Vision API(https://cloud.google.com/vision/?hl=ja) の登録を済ませます。
- インストールするライブラリがいくつかあります。
    - GPIOのセットアップにはRPi.GPIO、APIリクエストにはrequests、画像の撮影にはpicameraを使用しています。
    
    - それぞれ、
    　`$ sudo apt-get install python-rpi.gpio`
    　`$ sudo apt-get install python-requests`
    　`$ sudo apt-get install python-picamera`
     でインストールします。
- 今回、設置の都合でカメラの向きが逆になってしまったので、写真を反転させています。
- Vision APIで、ラベル検出を指定し、結果を5つ返しています。
- 愛犬の写真をいくつか判定してみたのですが、ちゃんと'dog'と返してくれることが少なく、'cat', 'kitten', 'fur'などと返ってきたので、いくつかキーワードを指定しています。鼻やひげも含めています。

- コードを動かす前に、カメラで撮影して保存しておくと、スムーズに検証できると思います。

``` python:sensor_camera.py
#!/usr/bin/env python
# coding: UTF-8


import RPi.GPIO as GPIO
import time
import picamera
import requests
import json
import base64

camera = picamera.PiCamera()
# 画像を水平に反転
camera.hflip = True
# 垂直に反転
camera.vflip = True

# LINEに画像を送る
# your_api_keyには、ご自分のAPIキーを入れてください。
def line_notify():

  url = 'https://notify-api.line.me/api/notify'
  img_file_path = '/home/pi/Desktop/dog.jpg'

  headers = {
      'Authorization': 'Bearer your_api_key'
  }

  files = {
      'message':(None, '!'),
      'imageFile': (img_file_path, open(img_file_path, 'rb'))
  }

  response = requests.post(url, headers=headers, files=files)

# Cloud Vision APIを使って犬を判別
def dog_detect():

  key = 'your_api_key'
  url = 'https://vision.googleapis.com/v1/images:annotate?key='
  api_url = url + key

  img_file_path = '/home/pi/Desktop/dog.jpg'
  img = open(img_file_path, 'rb')
  img_byte = img.read()
  # 画像をbase64でエンコード
  img_content = base64.b64encode(img_byte)

  req_body = json.dumps({
      "requests": [{
          "image": {
              "content": img_content
          },
          "features": [{
              "type": "LABEL_DETECTION",
              "maxResults": 5
          }]
      }]
  })

  response = requests.post(api_url, data=req_body)
  response_json = response.json()
  labels = response_json['responses'][0]['labelAnnotations']
  dog_description = ['dog', 'cat', 'kitten', 'dog like mammal', 'cat like mammal', 'fur', 'whiskers', 'snout', 'puppy']

  for value in labels:
       # 'description'に、特定のラベルが合った場合、LINEに通知する。
        if (value['description'] in dog_description) == True:
          line_notify()
        else:
          print('Not found')

# GPIO ピンを有効にする。任意のピン番号を指定。
sensor_pin = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(sensor_pin, GPIO.IN)

while True:
  if GPIO.input(sensor_pin) == GPIO.HIGH:
       camera.capture('/home/pi/Desktop/dog.jpg')
       dog_detect()
  time.sleep(5)

GPIO.cleanup()
```

最後に、このプログラムを自動起動する設定をします。
autostartでやりました。
`$ nano ~/.config/lxsession/LXDE-pi/autostart `で、
`@python /home/pi/Desktop/sensor_camera.py`を追記します。

#4.結果
犬だった場合は画像と一緒にLINE通知、そうでない場合は何も起きません。
愛犬がトイレに来る度に、可愛い画像が送られてきます。
<img width="320" alt="fullsizeoutput_13f.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/206282/d9266800-4fc0-de1c-f19f-a19e848b065a.jpeg">

すぐにお世話ができて、衛生的になりました。


以下のリンクにデモ動画があります。
https://twitter.com/kaiyu_hara/status/998842257615732737

#まとめ
Raspberry Piで作れば、既製品よりもカスタマイズが効いて便利です。
犬の認識部分を無くせば監視カメラとしても機能しますし、判別する対象を変えれば赤ちゃんや高齢者の見守りもできます。
Cloud Vison APIは、ラベル検出だけでなく顔認識やテキスト検出も可能なので、様々な使い方ができます。
また、データセットを用意して機械学習をすると、さらに精度を上げられそうです。

#参考資料


- Raspbian のWi-Fi設定（Raspberry Pi 初期設定）
(https://raspida.com/wifi4raspbian)
- [Raspbian]ユーザ名変更の個人的に「正しい」と思うやり方
(https://jyn.jp/raspberrypi-username-change/)
- Raspberry Pi へのリモート接続
(https://qiita.com/b-wind/items/d33f759ace01658bb09e)
- RaspberryPiで人感センサーを作る
(https://qiita.com/inaBowBow/items/dca01622d086f113db00)
- 人感センサ A500BP (DSUN-PIR, SB00412A-1も) が安いだけでなく Raspberry Pi との相性もバッチリだったので、人感カメラが10分で出来てしまった話。
(https://qiita.com/UedaTakeyuki/items/dd4365cefdb7293f79f6)
- [*Raspberry Pi*] 夏だ！人感センサーを使って蝉を鳴かせよう
(https://qiita.com/cigalecigales/items/4cf9c16f24d1de92ec7d)
- 画像認識API使ってみた（１）Google Cloud Vision
(https://www.apibank.jp/use_google-cloud-vision/)
- curlコマンドをPythonやnode.jsのコードに変換する方法
(https://qiita.com/tottu22/items/9112d30588f0339faf9b)
- Raspberry Piでプログラムを自動起動する5種類の方法を比較・解説
(http://hendigi.karaage.xyz/2016/11/auto-boot/)