植物の水やりをIoTする その2:モーター制御とトランジスタ


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

どうやって水をあげるべきか

植物へ自動で水やりをするとなると、一体どのような機構が考えられるだろうか。
例えば点滴のように重力を利用して、弁を開け閉めすることで給水を制御する方法がある。
この方法は、要は常に何かしらの形で水圧がかかっている状態を弁で制御するという方法なので、水道を利用しても同じ方法が取れるだろう。
これとは別に、水圧自体をオンオフする方法で制御するというものも考えられる。
この場合、予め水圧がかかっているような状態を確保する必要はなく、水たまりの中にモーターを放り込んでおくだけで良い。
今回は、このモーターをオンオフする手段によって、給水システムを構築する。

電子機械でモーターを制御する場合、考えなければならないことが2点ある。

  1. どうやって値を ON / OFF するか
  2. どうやって電圧を確保するか

どうやって値を ON / OFF するか

植物には定期的に水やりをしなければならない。そうしなければ枯れてしまうからだ。
とはいえ、圧倒的に水やりをしない時間の方が長く、常に給水のモーターを回し続けているわけにはいかない。
どうにかしてモーターが回るか回らないかの制御をする必要があるのだが、今回はもうその手段を我々は持っている。
そう、みんな大好き Arduino君である。
今回は、前回アナログ入力を受け付けるので大活躍した Arduino を使って、デジタル信号のオンオフを制御することにする。

この中の上段の列に2から12までの数字が並んているのがみて取れると思うが、これらのピン一本一本をそれぞれ制御することができる。
なぜか1はどこを探してもなく、12から視線を下に落としてもらえると13を見つけることができ、すなわち計12本のデジタル制御ピンを Arduino は持つことになる。
とはいえ今回はこれら全部を使用するということはなく、2番ピンのみを使用する。
ArduinoIDEを開き、以下のように入力する。

void setup() {
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);
  Serial.println("ON");
  delay(2000);
  digitalWrite(2, LOW);
  Serial.println("OFF");
  delay(2000);
}

まずは setup で2番ピンはアウトプットしますよという設定をしておち、これで2番はデジタル出力をするという前準備が完了する。

loop の中では、2番ピンの電圧を2秒おきに HIGH ⇔ LOW にしているだけである。
つまり、これを起動させれば2番ピンから2秒間電気が流れては2秒間待機するという制御を自動で行うことになる。
なので、これをそのままモーターへつなげればいいのかというと、話はそう簡単ではなかった。

どうやって電圧を確保するか

問題は、Arduino のデジタル出力はアンペア数が非常に低く、モーターを動かすには程遠いということだ。
単純に2番ピンとGNDにモーターをつなげても、残念ながらモーターはピクリともしない。
およそ20mA程度しかないと言われているこの電力量でできることといえば、せいぜいがダイオードを光らせることくらい。
つまり他所から、より高い電圧を確保する必要があるということである。
それを見越していたかどうかはわからないが、Arduino には5V出力が用意されている。
試しにこの5VとGNDにモーターをつなげてみたら、動いた。動きっぱなしなので、常に5Vが流れ続けていることになる。
つまりこの5VとGNDを使って電圧を確保し、2番ピンを使ってオンオフの制御をする事になる。
ここで登場するのがトランジスタだ。

トランジスタとは

説明は省く。
Wikipedia - トランジスタ

CPUの中にも極小のトランジスタが入っていたりするなど、普段我々は意識することはないが、これの恩恵にとてつもなくあやかっている。
今回使用するものはそこまで小さいものではなく、5Vの電圧に耐えうる程度のものである。

秋葉原で買ってきたのだ

黒く塗ってあるのが「ベース」で、これを2番ピンとつなげる。
本来であれば Arduino とモーターをつなげる場合はこれらに付け加えて抵抗なども使用するべきらしいが、ちょっとよくわからないので今回は省略する。
簡単な接続の仕方を回路図的に書いてみたものが以下である。

トランジスタの、コレクタとエミッタに5Vが流れるようにする。
そして、これらの電気をベースのオンオフで制御する。
今回は、その制御は2番ピンにて執り行うのでそのようにベースを繋ぐ。

モーターをプログラムで制御する

さて、これをプログラムにて操作するわけだが、今回は少々難儀した。
というのも、将来を見越して、何秒間モーターを動かすかをシリアルポートから受け取った信号にて行おうとしたためである。
どれくらいの量水やりをするかは、Arduino の外で決定する。
つまり、PCからArduino へ情報を渡してあげなければならないわけであるが、これをUSB経由で実施した。

実際に出来上がったコードが以下である。

Arduino
int moter = 2;      // select the pin for the LED

void setup() {
  Serial.begin(115200);
  pinMode(moter, OUTPUT);  
}

void loop() {
  if(Serial.available() > 0){
    int Vib = Serial.available();
    String VibON;

    for(int i = 0; i < Vib; i++){
      String tmp = String(Serial.read() - 48);
      VibON = VibON + tmp;
    }

    int v = VibON.toInt();

    if(0 < v){
      digitalWrite(moter, HIGH);
      delay(v);
      digitalWrite(moter, LOW);
    }
    Serial.println(VibON);
  }
}

値を送信するPython側のコードが以下である。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import serial
ser = serial.Serial('/dev/cu.usbmodem141101', 115200)

print('Start')
ser.write(b"1000")
print('Send')
ser.close()

まず前提として、PCからArduinoへのUSB経由でのシリアル通信では、バイナリでしかデータを送ることができない。
なので、"1000"の前にbがついている。
これは、文字列をバイナリとしますよ、という意味である。
送られた側はこれを解釈するが、まずはasciiの数値として認識される。
つまり、数値の048だしa97となる。
次の問題は、Arduinoにはasciiを文字へ変換するような機能を持たないということである。
すなわち、PCからArduinoへ文字列を送ろうと思ったら「asciiコードを文字へと変換する一覧を自作しなければならない」ということを意味する。
今回は「何秒動かす」という数値だけ送れればいいので「受け取った値から単純に48を減ずる」ことで「実際の数値」を得ることとする。
他の値が来ることは想定しない。私しか使わないので。バリデーションくらいはしてもいいかもだけど。

さて、ArduinoとPCを前回と同じような要領で繋ぎ、Python側のコードを実行すると……。

ウィーーーン……

動いたあああ!!!

きっかり1秒間動いてくれましたよ!

Appendix

さて、今回で「モーターを使用して水分を物理的に操作する」というところまで実現することができた。
次は、土壌水分センサーとこれを組み合わせて水分が足りなくなったときに必要な分水やりをする仕組みを構築する。