Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ラズパイで作るペットの排泄検知システム

はじめに

Raspberry Pi Advent Calendar 2020の20日目です.

趣味で作ったペットの排泄検知システムについて書いていきます.
私は,フトアゴヒゲトカゲというオーストラリア原産のトカゲを飼っています.(飼育日記
image.png
うんちをすることはそれほど多くなく,月に2〜3回程度です.
ただ,外出中などにうんちをされると,片付けるまでに時間がかかってしまうので,うんちをしたらわかるようなシステムを作ってみようと思いました.

実装した機能

目標は,うんちをしたらセンサで検知して,スマホに通知が来ることです.また,センサの出力値はあとで眺めたいので,何処かに保存しておきたいなと思いました,
そのために,ラズパイ上に以下の機能を実装しました.

  • においセンサ
  • LINEBotによるスマホ通知機能
  • GoogleAppsScriptを作成し,センサー出力値をGoogleスプレッドシートに送信

においセンサ

回路基盤

まずは,ラズパイににおいセンサ用の回路基盤を実装しました.実装する回路基盤は,こちらの記事を参考にしました.
使用したものもほとんど同じで,増えたのはラズパイ用ユニバーサル基盤とLEDくらいです.
全部,秋月電子通称で買い揃えました.

回路基盤のイメージをfritzingで書きました.参考にした記事では,ブレッドボード上に実装していますので,そちらも合わせてご確認ください.
スクリーンショット 2020-12-20 12.16.14.png
(左上の四端子の部品がにおいセンサ,右上の三端子の部品2個がトランジスタ,下の二端子部品2個がLEDです.
ピンソケットを使って,直接ラズパイにはんだ付けで固定せず,においセンサ基盤だけモジュール化しました.
LEDは家にあったものを適当につけたので,適宜良さげなものをつけてください.そのための抵抗も大きめの抵抗から抵抗値を少しずつ下げて試して行って,いい感じに光るものをつけました.)

コンパクトに実装できて満足しています.
S__165576734.jpg

プログラム

プログラムは,pythonで実装しました.ソースコードをこちらに置いておきます.

import spidev
# src/unkoDetector/util/spiModule.py
def setup():
    spi = spidev.SpiDev()
    spi.open(0,0)
    spi.max_speed_hz=1000000
    spi.bits_per_word=8
    return spi

# src/unkoDetector/unkoDetectorByLineNotify.py
from measure import measure
from util import spiModule, LINENotifyBot
import RPi.GPIO as GPIO
import time
import os
from tqdm import tqdm
import requests

def main():
    # Execute the following command in advance on the shell.
    # export "LINE_NOTIFY_KEY"=<YOUR_ACCESS_TOKEN>
    access_token = os.environ["LINE_NOTIFY_KEY"]
    bot = LINENotifyBot(access_token=access_token)
    bot.send(message = "においの検出を開始しました")

    # Setting up a Google spreadsheet to enter sensor data
    # export "GAS_URL"=<YOUR_GAS_URL>
    gas_url = os.environ["GAS_URL"]

    # Setting of GPIO pins
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17,GPIO.OUT)
    GPIO.setup(22,GPIO.OUT)

    ch0 = 0x00
    spi = spiModule.setup()
    judge = False
    trial = 100
    outlier = 20
    threshold_list = [0]*trial
    scaling = 0.25

    # Warming up to remove outliers.
    print("ウォームアップを開始します")
    for i in tqdm(range(outlier)):
        GPIO.output(22,True)
        time.sleep(0.005)
        GPIO.output(22,False)
        GPIO.output(17,True)
        time.sleep(0.008)
        GPIO.output(17,False)
        time.sleep(0.237)
    print("ウォームアップが終了しました")

    # Trials for Threshold Determination.
    print("基準値の測定を開始します")
    for i in tqdm(range(trial)):
        GPIO.output(22,True)
        time.sleep(0.005)
        ch0_val = measure(spi, ch0)
        GPIO.output(22,False)
        GPIO.output(17,True)
        time.sleep(0.008)
        GPIO.output(17,False)
        time.sleep(0.237)
        val = 1023 - ch0_val
        threshold_list[i] = val
    threshold = sum(threshold_list) / len(threshold_list)
    #bot.send(message = "基準値を" + str(threshold) + "に決定しました.")
    print("基準値を" + str(threshold) + "に決定しました")

    try:
        while 1:
            GPIO.output(22,True)
            time.sleep(0.005)
            ch0_val = measure(spi, ch0)
            val = 1023 - ch0_val
            GPIO.output(22,False)
            GPIO.output(17,True)
            time.sleep(0.008)
            GPIO.output(17,False)
            time.sleep(0.237)
            print(val)
            requests.get(gas_url + "?data=" + str(val))
            if val > threshold*(1.0+scaling) and judge == False:
                judge = True
                bot.send(
                    message = "出たよ!!",
                    image = "/home/pi/Laboratory/unkoDetector/src/unkoDetector/photo/mafuyu.jpeg"
                )
            elif val < threshold*(1.0+scaling) and judge == True:
                judge = False
                bot.send(
                    message = "片付けてくれてありがとう!!",
                    image = "/home/pi/Laboratory/unkoDetector/src/unkoDetector/photo/latte.jpeg"
                )

    except KeyboardInterrupt:
        GPIO.output(22,False)
        GPIO.output(17,False)

    spi.close()

if __name__ == "__main__":
    main()

基本的な流れは,
1. においセンサを使うためにGPIOピンのセットアップ
2. においセンサの起動
3. 基準値となる現在のにおいレベルを測定
4. においの測定を繰り返し,全てのセンサ出力値を記録
5. 基準値を大幅に超えたら通知

LINEBot

LINEBotの通知機能は,こちらの記事で紹介されている,LINENotifyBotのclassをそのまま拝借しました.

GoogleAppsScript

GoogleAppsScriptによるGoogleスプレッドシートへの記録は,こちらの記事を参考に実装しました.

実際に動かしてみる

今回は,執筆中にフトアゴがうんちをしてくれなかったので,家にあった臭そうなものでテストしました.
実運用ではラズパイZeroを使いますが,テストにはラズパイ4を使いました.

おわりに

今回は,ラズパイを使ってフトアゴ用のにおいセンサを作ってみました.
うちの子もクリスマスプレゼントをもらってうれしそうにしています!!
S__165576728.jpg

j-ij
量子アニーリングを代表とするアニーリングマシン向けアプリケーション開発・研究を行うスタートアップ
j-ij.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away