サンプルプログラム

サンプルプログラム(自動給水システム)

開発背景

知り合いのイチゴ農業ハウスの従事者から、

「養液供給は自動化されているものの、土壌に養液がきちんと浸透しているかの測定までは自動化できていない。」

というお話しを伺いました。
一方、会社でも家庭でも観葉植物はよくあるものの、その手入れ、特に定期的な水やりは何かの都合でできない場合があり、そのために枯らしてしまったという話しもお聞きします。

自動的に給水するツールはよくあるものの、一方的に決まった量を給水するために、過剰な給水で根腐れしたり、逆に水が不足する場合など、なかなか難しい現実があります。

そのような背景のなか、今回はプロトタイプ(試作モデル)として、土の湿度を計測しながら、その湿度に合わせて供給する水を制御するものを開発しました。

完成画面

SensingAppで土壌湿度の状況を確認できるようにしました。
(画面はSensingApp旧バージョンになります)

土壌湿度センサーと室内温度のセンサー登録例
土壌湿度をグラフ化したもの(サンプルデータ)

必要なパーツ

今回の開発で使用した主なパーツは次のとおりです。詳細な仕様はリンク先をご覧下さい。

  • Raspberry Pi
  • 土壌湿度センサー
    Arduino用 土壌湿度センサー Soil Moisture Sensor
  • 給水ポンプ
    水中ポンプ DC 12V 小型ポンプ 吐出量240L/H
  • リレーモジュール
    リレーモジュール 1チャンネル DC 5V 高低レベル トリガー フォトカプラ付き
  • SORACOMドングル
    3G対応データ通信端末 AK-020
  • その他(給水のためのチューブ、水タンク、試用のための観葉植物、ポンプ駆動電源など)
       

IoTシステムの構成図

当システムの構成は次のとおりです。

ラズパイの開発

  • ラズパイのOSをSDカードに書き込み、SORACOMの3G USBドングルでインターネット接続できるようにセットアップします。
    参考:Raspberry Pi と USB モデム
  • 土壌湿度センサー、リレーモジュール、電源、給水ポンプを接続します。(下図の通りです)
配線図
  • ラズパイに湿度センサーのデータ取得のプログラムを作成します。
  • ラズパイに給水ポンプを起動するためのリレーモジュールを動作させるプログラムを作成し、指定する土壌湿度の閾値を下回った場合に給水が行われるようにします。
  • サーバーと通信するプログラムを用意し、湿度センサーのデータを定期的にサーバーにアップします。

これらの3の機能を持つプログラムは次のとおりです。

# -*- coding: utf-8 -*-
import time
import os
import RPi.GPIO as GPIO
from datetime import datetime
import base64
import json
import urllib.request

# データ送信先
URL = "https://beta.sensingapp.io/api/data/"
USER_ID = "XXXXXXXXXXXXX" 
ITEM = 'MOISTURE'

SPICLK = 11
SPIMOSI = 10
SPIMISO = 9
SPICS = 8
SENSOR_NUM = 1  # 使用するセンサーの個数(CH0から順番に使用する)

# 給水ポンプ制御
MOISTURE_LIMIT = 300    # 乾燥閾値(土壌湿度センサーがこの数値を下回ったらポンプで給水する)
SUPPLY_TIME = 3         # 給水時間(秒)
RELAY_PIN = 26


def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if adcnum > 7 or adcnum < 0:
        return -1
    GPIO.output(cspin, GPIO.HIGH)
    GPIO.output(clockpin, GPIO.LOW)
    GPIO.output(cspin, GPIO.LOW)
    commandout = adcnum
    commandout |= 0x18
    commandout <<= 3
    for i in range(5):
        if commandout & 0x80:
            GPIO.output(mosipin, GPIO.HIGH)
        else:
            GPIO.output(mosipin, GPIO.LOW)
        commandout <<= 1
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
    adcout = 0
    for i in range(13):
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
        adcout <<= 1
        if i>0 and GPIO.input(misopin)==GPIO.HIGH:
            adcout |= 0x1
    GPIO.output(cspin, GPIO.HIGH)
    return adcout


# センシングデータをサーバに送信
def send_data(item_num, data):
    obj = {
        "user_id": USER_ID,
        "item": ITEM,
        "item_num": item_num,
        "regist_date": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        "sensing_data": str(data),
    }
    json_data = json.dumps(obj).encode("utf-8")
    print(json_data) # for debug
    # httpリクエストを準備してPOST
    request = urllib.request.Request(URL, data=json_data, method="POST", headers={"Content-Type": "application/json", })
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")
    if "Error" in response_body:
        print("response_body Error") # for debug
    else:
        interval_time = int(response_body)  # インターバルをクラウドから取得した数値を入れる

    print(interval_time) # for debug
    return(interval_time)


# 給水ポンプを起動
def supply_water():
    print("給水開始 "+str(SUPPLY_TIME)+"秒間")  # for debug
    GPIO.output(RELAY_PIN, True)
    time.sleep(SUPPLY_TIME)
    GPIO.output(RELAY_PIN, False)
    time.sleep(0.5)


# 決められた時間間隔でのセンシング
def main():
    GPIO.setwarnings(False)  # GPIOのWarning非表示
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(SPICLK, GPIO.OUT)
    GPIO.setup(SPIMOSI, GPIO.OUT)
    GPIO.setup(SPIMISO, GPIO.IN)
    GPIO.setup(SPICS, GPIO.OUT)
    GPIO.setup(RELAY_PIN, GPIO.OUT)
    pin_count = 0  # CH0から使用するセンサー分をカウントする
    try:
        while True:
            moisture_data = readadc(pin_count, SPICLK, SPIMOSI, SPIMISO, SPICS)
            if moisture_data < MOISTURE_LIMIT:
                supply_water()
            print(datetime.now().strftime('%Y/%m/%d,%H:%M:%S, ') + str(moisture_data))  # for debug
            interval_time = send_data(pin_count+1, moisture_data)
            time.sleep(interval_time)
            pin_count += 1
            print("pin_count="+str(pin_count))  # for debug
            if pin_count == SENSOR_NUM:
                pin_count = 0
    except KeyboardInterrupt:
        pass
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()

プログラム中のUSER_ID「XXXX」には、ユーザー独自のものを設定します。

参考サイト:
ハウス栽培5:土壌センサを使って土壌の湿気計測
ラズパイとリレーモジュール

次の画面は、サーバー側のグラフ表示です。土壌湿度はこのシステムでリアルに計測した数値になります。
(旧SensingAppの画面になります)

これらのプロトタイプは次のように接続して行いました。右側の土壌湿度センサーで取得したデータをもとに、左側にあるリレーのON/OFFを制御し、ONのときにタンクに入れているポンプから鉢に給水します。

今後の展開

今回の開発はプロトタイプになり、このまま販売商品にできるものではありませんが、今後は次の機能を追加していきたいと考えています。

  • 1台のラズパイで、複数の土壌湿度センサーによるセンシングと複数の給水ポンプを制御し、最大8箇所の自動給水システムを稼働させ、またラズパイ自体の個数を追加できる仕様とすることにより、広いハウス内での給水、または養液の注水を制御できるようにする。
  • 各給水ポンプが取水するための給水センタータンクへの給水も自動制御する。養液の場合には少なくなったら、アラームが上がるようにする。

以上です。ご参考になれば幸いです。

YouTube

 今回のシステム紹介を下部のYoutubeで行っています。 あとで確認すると途中で差し込んだ動画に入れたはずのキャプチャーが消えてしまっていたので、差し込んだ動画で説明したのを次に示しておきます。

  • 右側のブラウザ画面は DjangoのREST Frameworkを使用したデバッグ画面です。ラズパイからネット回線を通してサーバーに送り込まれているJSONデータを表示させています。
  • 左側の下のブラウザ画面はユーザーがログインしたあとに見られるデータグラフです。横軸に時間、縦軸に土壌湿度を表しています。
  • 予め設定した閾値(しきいち)は300です。それを下回ると給水ポンプは起動します。給水ポンプは3秒間動くように設定しています。またセンシング間隔はテストで10秒です。(SensingApp では最小60秒と決められていますが、デモのために設定しています)
  • 動画は、一度、土壌湿度を下げるために、手動でセンサーを土から少し出しています。そうすると土壌湿度が300以下になるのでポンプから水が送られます(実際は鉢ではなく、タンク内で水を出しています)。その後、センサーを土の中に入れて、一旦土壌湿度を上げていますが、再度、センサーを持ち上げて土壌湿度を下げて、給水ポンプが動作するようにしています。
※ 旧バージョンのSensingAppで動かしてしているのでご承知置きください。