植物の水やりをIoTする その1:土壌水分量センサーとArduino


いつ水をあげるべきか

植物の水やりって、面倒ですよね。
毎日ちゃんと水をあげなければ枯れるし、ものによっては水をやり過ぎてもよろしくなかったりとまあ実に面倒なことこの上ない。
なので、ものぐさな私は植物の水やりの面倒臭さをIoTで解消することはできないかと思い立つのである。

いつ、どれだけの量の水をあげるべきか、植物を育てる全てはここにあるといっても過言ではない(過言)。

百歩譲って毎日決まった時間に水やりをするのはいいのだが、あまりにも水を注ぎ過ぎてトレーから水が溢れ出てしまうなどということもしばしば。
土が乾いたら水をあげればいいというただそれだけのことが、「土がどれだけ乾燥しているのか」ということすら我々人間には知覚することができないために、できないのである。

だから、まずは「どれだけ土が乾燥しているか」を感知するセンサーを使ってみるのだ。

土壌水分センサー

こちらが今回使用する土壌水分センサー、正式名称を「静電容量式土壌水分センサー」などというらしい。

Capacitive Soil Mosture Sensor V1.2

回路とかむき出しな感じがなんかIoTっぽくて素敵だ。
ちなみにこれは中国産の廉価版で一個あたり158円である(やっすい!)。
ちゃんとしたやつはオリジナルのものがちゃんとあるらしいが、今は生産していないのか情報があまり出てこない(originated by DFRobot)。
なお、回路設計図などは公開されているため、上記のものもこれをもとにして作ったのだろうと推測される。
まあ、これでもちゃんと動くは動くのでこれを使う。

仕組みは至って簡単で、ここの部分に水分が付着すると電気が流れて、それを感知するわけである。

触れている箇所が広ければ広いほど流れる電気の量も多くなるので、「どれだけの水分量があるか」を測ることができるわけである、なんて便利なんだ!

このセンサーから電気信号を受け取ってパソコンへ移さなければならないず、ここで一つの問題が発生する。
電気信号がアナログなのだ。

アナログ信号をデジタル信号へ

言わずもがな、我々の使用しているコンピュータというものはデジタルで動いている。
なので、電気信号といえどもアナログ信号をそのまま受け取ることはできない。
なので、これをデジタル信号へ変換してあげる必要があるのだが、ここでとても便利なデバイスが登場する。

ここまでいえば、もう皆さんお分かりですね。

そう、みんな大好き Arduino である(私はアルディーノと呼んでいる、多分男の子)。

Arduino とは、イタリアの5人の天才たちが生み出した、マイコンをよりシンプルかつ安価に様々な人が使えるように構築されたハードとソフトを包括した呼称である。
https://ja.wikipedia.org/wiki/Arduino

今回は、そこまで多くのことをするわけではないので、おそらく Arduino の中でも最小構成に近いであろう ArduinoMicro を使用する。
これに先ほどの土壌水分センサーを取り付けていくわけであるが、何をどこにつけるのかは注意が必要だ。

これを

この中のどこかにつける。

電気関係にアレルギーのある方はこの時点でもうリタイヤ寸前かもしれないが、少し踏ん張ってみよう。

どこに繋げるか、それが問題だ

今回のセンサーにとって、必要な情報は実はたったの三つでしかない。

  • 電極受け側端子(GND、Ground)
  • 電極送り側端子(VCC)
  • シグナル端子(AOUT、アナログ出力)

つまりとりあえず端子のプラスとマイナスを付けて、情報を送ってくれるシグナル端子をまたどこかへつなげればいいということになる。
ちなみに、これら組み込み関連のデバイスでは基本的には5Vや3.3Vといった電圧が規格となっているらしく、上記の Arduino の画像の中にも「5V」や「3V」といった表記が見受けられると思う。
基本的に VCC にはこれらのどれかをつなげることになる。今回は 3V へ繋げる。
GND は大人しく同じ表記のある GND へ繋げる。
最後、 AOUT をどこに繋げるかだが Arduino はアナログ信号を受け取るために複数の端子を用意している。
画像の「A0」から「A5」までの端子がそれに当たる。
このうちのどこかに AOUT をつなげれば良い、今回は A0 を使用する。
そして繋げるとこのようになる。

センサーに同封されているケーブルの先端の黒い部分に関しては、以下のようにして爪楊枝で取り外すことができる。
邪魔なだけなので取り外してしまおう。

そして出来上がったものを

こうじゃ。
Arduino は基本USBを備えているのでそれを使うのが便利である。
Raspberry Pi などと繋げる際には上記のように一本一本線を繋ぐような方法もあるのだが、やはりUSBで繋げるのが簡単でよろしいだろう。
初期状態では、ArduinoにはLEDランプを1秒おきに明滅させるだけのプログラムしか組み込まれておらず、電源を入れるとLEDがチッカッチッカとするはずである(少なくとも MICRO は)。

次に、これをソフト側で制御する。

ArduinoIDE

以下のサイトからIDEをダウンロードしてインストールする。
https://www.arduino.cc/en/software


まずは、以下のように、使用するボードが正しいものが選択されているかを確認する。

デフォルトでは ArduinoUno が選択されているはずなので、今回は ArduinoMicro へ変更する。

次に、以下のようにつながっているデバイスを選択する。

基本的にはUSBへ繋いだ時点でデバイスはPCに認識されているはずなので、ここに表示されない場合は接続方法を確認するといいかもしれない。
なお、ここで表示されている「/dev/cu.usbmodem143101」というデバイス名称はのちに使用するのでどこかにメモっておく。

信号を受け取る

A0 端子へ流れてくるであろうアナログ信号を受け取り、画面へ表示させる。
この Arduino の凄いところは、これらどのようにプログラムすれば良いかのサンプルを数多く取り揃えてくれていることである。

これらを参考にして、信号を受け取るプログラムを組んでみた。

簡単だなオイ!!!
たったこれだけで、アナログの0番端子からの読み込みをしますよ、というプログラムになる。
この中のコードのうち、「115200」が通信速度(bps)となり、のちにpythonで外部PCとシリアル通信する際に必要になるのでどこかへメモっておくこと。

コードが書けたらデバイスへプログラムを送信する。
こちらも以下の画像のようにするだけの簡単仕様である。

送信が成功したら、すでに常時稼働状態になっているのでシグナルの入力と出力がされているかを確認しよう。
0.5秒刻みで入力を受け取って出力へ回しており、これは「シリアルモニタ」で確認が可能だ。


ちゃんと値を受け付けて、出力もしているようだ。
この出力は、USBを経由してPCで受け取ることもできる。

Pythonで値を受け取る

PCにはすでにUSBで接続済みなので、USB経由で受け取ったシグナルをちゃんと解析するプログラムを書いてあげれば問題ない。
以下のサイトを参考にして(ほぼ丸コピして)プログラムを組んでみた。
https://misoji-engineer.com/archives/raspberrypi-arduino.html#toc10

使用しているライプラリの中で特殊なものはpyserialくらいなので、以下のコマンドでインストールしておく。

sudo pip install pyserial
Arduino.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import itertools
import math
import numpy as np

import serial
ser = serial.Serial('/dev/tty.usbmodem143101', 115200)

from matplotlib import pyplot as plt
from matplotlib import animation

from subprocess import getoutput


def _update(frame, x, y):
    """グラフを更新するための関数"""
    # 現在のグラフを消去する
    plt.cla()
    # データを更新 (追加) する
    x.append(frame)

    # Arduino*の電圧を取得する
    a=""
    a=ser.readline()
    while ser.in_waiting:
        a= a + ser.readline()
    a3= a.split(b'\r')
    y.append(100 - (int(a3[0]) - 200) // 3)

    # 折れ線グラフを再描画する
    plt.plot(x, y)

    # グラフのタイトルに電圧を表示する
    plt.title("Mosture per "+ str(y[-1]) +" %")

    # グラフの縦軸_電圧の範囲を指定する
    plt.ylim(0,100)![Something went wrong]()


def main():
    # 描画領域
    fig = plt.figure(figsize=(10, 6))
    # 描画するデータ
    x = []
    y = []

    params = {
        'fig': fig,
        'func': _update,  # グラフを更新する関数
        'fargs': (x, y),  # 関数の引数 (フレーム番号を除く)
        'interval': 500,  # 更新間隔 (ミリ秒)
        'frames': itertools.count(0, 0.1),  # フレーム番号を無限に生成するイテレータ
    }
    anime = animation.FuncAnimation(**params)

    # グラフを表示する
    plt.show()

if __name__ == '__main__':
    main()

このコードの中で重要なのは以下の一行で

ser = serial.Serial('/dev/tty.usbmodem143101', 115200)

デバイス/dev/tty.usbmodem143101と通信速度115200bpsで送受信するシリアル信号を接続対象として設定しますよ、という意味になる。
メモっておいたデバイス名称とポート番号をここに指定すること。

受け取る値は下が200で上が500くらいなので、これをいい感じにパーセンテージ表示してくれるようにするため数値を標準化している。

実行すると、

グラフが表示され始める。
このセンサー部分を水につけると

反応した!

センサーが反応して水分量のパーセンテージが上がっていることがわかる。
あとはこれをもうちょっとどうにかこうにかすれば、土壌水分量の遠隔監視ができるようになるわけである。

Appendix

今回は、センサーの信号をアナログからデジタルへ変換し、それをPCへ渡すところまでを実施した。
これを本格的にIoTするためには、このデータをさらにネット上へ送るような仕組みも必要になってくる。
基本的には Raspberry Pi などを使用することになるだろうが実はこの Arduino、何か頑張ればこれ単体でWifi接続すらもできるようになるらしい。
データを送ることさえできてしまえばあとはどうとでもなるのが現代のWEBなので、これ以降の議論は別の記事へと譲ることとしよう。