「旅行や出張で数日家を空けると、観葉植物がしおれてしまう…」「水やりを忘れて枯らしてしまった」──そんな経験、ありますよね。

この記事では、Arduinoと静電容量式の土壌水分センサー、小型の水中ポンプを組み合わせて、土が乾いたら自動で水をあげる装置を作ります。難易度はArduino初〜中級者向け。LチカやanalogRead()を一度でも触ったことがあれば大丈夫です😊

ただ「乾いたらポンプON」だけだと、実はうまく動きません。この記事では、つまずきやすいキャリブレーションと水のやりすぎ防止(ヒステリシスと安全装置)まで一緒に見ていきましょう!

用意するもの

plant watering sensor
plant watering sensor / Photo by Tim Witzdam via Pexels
部品 役割・メモ
Arduino UNO(互換機でもOK) 全体の制御
静電容量式土壌水分センサー(Capacitive Soil Moisture Sensor v1.2 など) 土の湿り具合をアナログ値で出力
1チャンネル リレーモジュール ポンプの電源をON/OFFする
小型水中ポンプ(DC 3〜5V程度)+チューブ タンクから鉢へ水を送る
ポンプ用の電源(電池ボックスなど) ポンプはArduinoとは別の電源から給電する
水タンク(ペットボトルなど)・ジャンパーワイヤ

⚠️ 抵抗式(2本の金属電極がむき出しのタイプ)のセンサーは、長期間の設置には不向きです。電極に電流が流れ続けるため、土の中で腐食が進みやすいからです。常に挿しっぱなしにする自動水やりでは、電極が表に出ていない静電容量式を選びましょう。

配線

  • センサー:VCC → 5V、GND → GND、AOUT → A0
  • リレーモジュール:VCC → 5V、GND → GND、IN → D7
  • ポンプ:ポンプ用電源の+ → リレーの COM、リレーの NO → ポンプの+、ポンプの− → ポンプ用電源の−

ここが重要です👇

  • ポンプをArduinoの5Vピンから直接動かさない。モーターの起動電流でArduinoがリセットされる原因になります
  • センサーは基板の白線(上限ライン)より上を土に埋めない。電子部品が濡れると壊れます
  • 水と電気を扱うので、Arduino本体やリレーは鉢から離し、水がかからない場所に置きましょう

ステップ1:センサーをキャリブレーションする

静電容量式センサーは、乾いているほど値が大きく、湿っているほど値が小さくなります。イメージとしては「数字が大きい=カラカラ」です。

ところが、この値はセンサーの個体差や電源電圧で大きく変わります。ある個体では空気中で500台なのに、別の個体では600台、ということも珍しくありません。なので、まずは自分のセンサーで「カラカラの値」と「びしょびしょの値」を測ります。

// 土壌水分センサーのキャリブレーション用スケッチ
const int SENSOR_PIN = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  // 10回読んで平均し、ノイズを減らす
  long sum = 0;
  for (int i = 0; i < 10; i++) {
    sum += analogRead(SENSOR_PIN);
    delay(10);
  }
  int raw = sum / 10;

  Serial.print("raw=");
  Serial.println(raw);
  delay(500);
}

ポイントをまとめるとこんな感じです。

  • 10回読んで平均を取り、値のブレを抑えている
  • シリアルモニタ(9600bps)を開き、①センサーを空気中に置いたときの値と②白線の手前までコップの水に挿したときの値をメモする
  • ①が「DRY_RAW」、②が「WET_RAW」になります

表示例(値は個体によって異なります):

raw=521
raw=519
raw=520
(水に挿すと)
raw=262
raw=259

この記事では、以降 DRY_RAW = 520、WET_RAW = 260 として話を進めます。実際には自分で測った値に置き換えてください。

ステップ2:「しきい値1つ」がダメな理由をPythonで確かめる

いきなりポンプをつなぐ前に、制御の考え方をPythonで試しておきましょう。水とポンプを使う実験は失敗すると後片付けが大変なので、ロジックだけ先にPCで確認しておくと安心です。

素直に考えると「湿度40%未満ならポンプON、40%以上ならOFF」ですよね。でもセンサー値には少しノイズが乗るので、40%付近をウロウロすると…? これ、実行せずに答えられますか?

# 自動水やりの「しきい値」と「ヒステリシス」をPythonで先に確かめる
DRY_RAW = 520   # 空気中(カラカラ)のときの値
WET_RAW = 260   # 水に挿したときの値

def to_percent(raw):
    """センサーの生の値を 0〜100% の湿度に変換する"""
    # Arduino の map() と同じく小数点以下は切り捨て
    percent = int((DRY_RAW - raw) * 100 / (DRY_RAW - WET_RAW))
    return max(0, min(100, percent))

# 土が乾いていく〜水やりまでを想定したセンサー値(少しノイズが乗っている)
readings = [408, 412, 415, 419, 414, 418, 413, 420, 424, 428, 431, 395, 360, 330]

def simulate(on_below, off_above):
    pump = False
    log = []
    for raw in readings:
        p = to_percent(raw)
        if not pump and p < on_below:
            pump = True
        elif pump and p >= off_above:
            pump = False
        log.append((raw, p, "ON" if pump else "--"))
    return log

for name, on_below, off_above in [("しきい値1つ(40%)", 40, 40),
                                  ("ヒステリシスあり(35%でON / 60%でOFF)", 35, 60)]:
    log = simulate(on_below, off_above)
    switches = sum(1 for a, b in zip(log, log[1:]) if a[2] != b[2])
    print(f"■ {name}")
    print("  " + " ".join(f"{p:>3}%" for _, p, _ in log))
    print("  " + " ".join(f"{s:>4}" for _, _, s in log))
    print(f"  ポンプの切り替え回数: {switches}回\n")
実行結果:しきい値1つとヒステリシスありのポンプ切り替えの比較
実行結果:しきい値1つとヒステリシスありのポンプ切り替えの比較

実行すると、上の実行結果のようになります。

しきい値が1つだと、40%付近のわずかなブレでポンプがON/OFFを6回も繰り返しています。これでは水がチョロチョロ出たり止まったりして、リレーやポンプにも負担がかかります。

そこで使うのがヒステリシスです。つまり「ONにする値」と「OFFにする値」をわざとずらす方法です。35%を下回ったら水やり開始、60%以上になるまで止めない、とすると、切り替えは開始と終了の2回だけになりました🚀 エアコンのサーモスタットも同じ考え方で動いています。

ちなみに、変換式は Arduino の map() と同じく小数点以下を切り捨てにしているので、Arduinoで表示される%とそろいます。

ステップ3:自動水やりスケッチ

いよいよ本番のスケッチです。ヒステリシスに加えて、水のやりすぎを防ぐ工夫を2つ入れています。

// 静電容量式土壌水分センサー+ポンプで自動水やり
const int SENSOR_PIN = A0;
const int PUMP_PIN = 7;          // リレーモジュールの IN につなぐ

const int DRY_RAW = 520;         // キャリブレーションで測った「空気中」の値に書き換える
const int WET_RAW = 260;         // キャリブレーションで測った「水中」の値に書き換える

const int ON_BELOW = 35;         // これを下回ったら水やり開始(%)
const int OFF_ABOVE = 60;        // これ以上になったら水やり終了(%)

const unsigned long PUMP_MS = 3000;   // 1回の給水時間(3秒)
const unsigned long SOAK_MS = 60000;  // 水が土にしみ込むのを待つ時間(60秒)
const int MAX_PULSES = 5;             // 1回の水やりで給水する回数の上限

// LOW で ON になるリレーモジュールなら RELAY_ON を LOW に変える
const int RELAY_ON = HIGH;
const int RELAY_OFF = (RELAY_ON == HIGH) ? LOW : HIGH;

bool watering = false;  // 水やり中かどうか
int pulses = 0;         // 今回の水やりで給水した回数
bool locked = false;    // 安全装置が作動したか

int readPercent() {
  long sum = 0;
  for (int i = 0; i < 10; i++) {
    sum += analogRead(SENSOR_PIN);
    delay(10);
  }
  int raw = sum / 10;
  // 乾いているほど値が大きいので、DRY→0%、WET→100% に変換
  int percent = map(raw, DRY_RAW, WET_RAW, 0, 100);
  return constrain(percent, 0, 100);
}

void setup() {
  digitalWrite(PUMP_PIN, RELAY_OFF);  // 起動直後にポンプが回らないよう先にOFFを書く
  pinMode(PUMP_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (locked) {
    Serial.println("LOCKED: check water tank and sensor");
    delay(10000);
    return;
  }

  int percent = readPercent();
  Serial.print("moisture=");
  Serial.print(percent);
  Serial.println("%");

  // ヒステリシス:35%未満で開始、60%以上で終了
  if (!watering && percent < ON_BELOW) {
    watering = true;
    pulses = 0;
  } else if (watering && percent >= OFF_ABOVE) {
    watering = false;
    Serial.println("watering done");
  }

  if (watering) {
    if (pulses >= MAX_PULSES) {
      // 何度給水しても湿らない=タンクが空かセンサーが抜けている
      locked = true;
      return;
    }
    digitalWrite(PUMP_PIN, RELAY_ON);
    delay(PUMP_MS);
    digitalWrite(PUMP_PIN, RELAY_OFF);
    pulses++;
    Serial.print("pump pulse ");
    Serial.println(pulses);
    delay(SOAK_MS);  // しみ込むまで待ってから測り直す
  } else {
    delay(5000);
  }
}

ここが重要です👇

  • 少しずつ給水して、しみ込むのを待つ:水をあげてもすぐにはセンサーの値が上がりません。60%になるまでポンプを回し続けると、値が上がる前に鉢から水があふれます。そこで「3秒給水 → 60秒待って測り直す」を繰り返しています
  • 給水回数の上限(安全装置):タンクが空になったり、センサーが鉢から抜けたりすると、いくら給水しても値が上がりません。5回給水しても60%に届かなければロックして止まるので、部屋が水浸しになるのを防げます
  • リレーの向きに注意:リレーモジュールには、INがHIGHでONになるタイプとLOWでONになるタイプがあります。電源を入れた瞬間にポンプが回るなら、RELAY_ON を LOW に変えてください
  • setup() で pinMode() より先にOFFを書いておくと、起動直後にポンプが一瞬動くのを防ぎやすくなります

シリアルモニタの表示例:

moisture=41%
moisture=38%
moisture=34%
pump pulse 1
moisture=47%
pump pulse 2
moisture=62%
watering done
moisture=61%

うまく動かないときのチェックポイント

  • %がいつも0%や100%に張り付く:DRY_RAW / WET_RAW が自分のセンサーの値と合っていません。ステップ1をやり直しましょう
  • 値が安定しない:センサーの周りに隙間があると値が暴れます。挿したあと周りの土を軽く押さえて密着させてください
  • ポンプが回るとArduinoがリセットされる:ポンプの電源をArduinoと分けているか確認しましょう
  • しきい値の決め方:植物によって好む湿り具合は違います。まずは数日シリアルモニタで値を観察し、「そろそろ水をあげたい」と感じたときの%をON_BELOWの目安にするのがおすすめです

まとめ

  • 自動水やりには、腐食に強い静電容量式の土壌水分センサーを使う
  • センサー値は個体差が大きいので、空気中と水中の値でキャリブレーションしてから%に変換する
  • しきい値1つだとON/OFFを繰り返すので、ヒステリシス(35%でON/60%でOFF)を使う
  • 「少しずつ給水→しみ込むのを待つ」と「給水回数の上限」で、水のやりすぎと水浸しを防ぐ

「むずかしそう」に見える自動水やりも、分解してみるとセンサーを読む → %に変換 → ポンプをON/OFFの3ステップです。ざっくりとした流れがつかめたら、ぜひ手元の鉢植えで試してみてください😊

📡 Arduinoをもっと深く学ぼう!

Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。

Arduinoロボット入門のおすすめコース・部品を見る →

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
Arduinoをはじめよう 第4版 (Make: PROJECTS)

もしも

Arduinoをはじめよう 第4版 (Make: PROJECTS)

Arduino公式推薦の定番入門書

Amazonで見る
徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。