部品 · 読了まで19分

Arduinoでウォーターポンプ:小型の水中ポンプの配線と制御

Arduinoのウォーターポンプガイド:3〜6 Vの小型水中ポンプをMOSFETやリレーで駆動する方法を解説します。フライバックダイオード、別電源、流量、自動水やり、ESP32のコードも紹介します。

Arduinoのウォーターポンプのプロジェクトでは、ほとんどの場合同じ部品が使われます。3〜6 Vで動き、完全に水に沈めて使う、指くらいの大きさの小型の水中ポンプです。植木鉢に水をやる回路、水槽に水を補充する回路、コーヒーマシンのように決まった量の液体を出す回路、小さな噴水を動かす回路などの中心になる部品です。安くて静かで、線は2本だけです。ただし内部にブラシ付きDCモーターが入っているため、Arduinoのピンに直接つなぐことはできません。

このガイドでは、ポンプの内部構造、ピンに直接つなげない理由、そしてMOSFET、トランジスタ、リレーで安全に駆動する方法をステップごとに学びます。フライバックダイオードの役割、ポンプに専用の電源が必要な理由、流量と揚程の関係、空運転がポンプを壊す理由についても説明します。そのあと、PWMによる速度調整、ミリリットル単位の精度で液体を出すディスペンサー、土壌水分に応じた自動水やり、ESP32を使ったスマホからの操作、Raspberry Pi Picoによるタイマー式の水やりのコードを書きます。

6 Vの小型水中ポンプ
小型の水中ポンプ:3〜6 V DC、線は2本、ホースの出口は約7.5 mm。動作中は完全に水に沈めておく必要があります。

小型の水中ポンプとは?しくみは?

小型の水中ポンプは遠心ポンプです。プラスチックのケースの中に、小さなブラシ付きDCモーターと、その軸に取り付けられた羽根車(インペラー)が入っています。モーターが回ると、羽根車は底の吸い込み口から入った水を外側へはじき飛ばし、横または上にあるホースの出口から押し出します。モーターの部分は防水構造で密閉されていますが、羽根車の部屋は水で満たされています。この構造から、重要な点が2つあります。ポンプは自吸式ではない(空気を押し出せないので、水面より下に置く必要がある)こと、そして羽根車を冷やし、軸受けを潤滑しているのは、ポンプが送り出す水そのものだということです。

項目一般的な値(3〜6 Vの小型水中ポンプ)
動作電圧2.5〜6 V DC(最も効率がよいのは3〜5 V)
動作電流130〜220 mA(6 Vでは最大300 mA)
起動電流数ミリ秒の間、動作電流の2〜3倍
電力0.4〜1.5 W
流量(出口を開放した状態)80〜120 L/h(約1.3〜2 L/min)
最大揚程40〜110 cm(この高さで流量はゼロになる)
ホース内径5 mm、外径7〜8 mmのシリコンホース
連続運転の寿命約500時間(ブラシ付きモーター)

表の値はモデルによって異なります。必ず手元のポンプのラベルや販売者の情報を確認してください。特に重要なのは電流と起動電流の2行です。200 mAのポンプでも、回り始めた瞬間はモーターがまだ加速していないため、短時間400〜600 mAを流すことがあります。この突入電流を考えずに回路を設計すると、ポンプが動くたびにArduinoがリセットされてしまいます。

なぜポンプをArduinoのピンに直接つなげないの?

初心者に最も多い間違いは、ポンプの赤い線をデジタルピンに、黒い線をGNDに挿して、digitalWrite(HIGH)で動かそうとすることです。これには3つの問題があります。1つ目は電流です。Arduino Unoのピンが耐えられるのは最大40 mAで、安全な上限は20 mAですが、ポンプはその10倍を必要とします。2つ目は電圧スパイクです。モーターの巻線はコイルなので、電流が切れた瞬間に逆向きに数百ボルトの短いパルスを発生させることがあります。3つ目は電気的なノイズです。ブラシ付きモーターのブラシは1回転ごとに火花を出し、電源ラインにノイズをまき散らします。その結果、ポンプがまったく回らないか、ピンが永久に壊れてしまいます。

ボード1ピンあたりの安全な電流ピンの絶対最大定格ポンプの電流との比較
Arduino Uno / Nano(5 V)20 mA40 mAポンプは5〜10倍の電流が必要
ESP32(3.3 V)≈ 20 mA40 mA電流が足りず、電圧も低い
Raspberry Pi Pico(3.3 V)4 mA(初期設定)12 mA(最大の設定)ポンプは20倍以上の電流が必要

解決策は、ピンでポンプではなくスイッチを制御することです。ピンは数ミリアンペアの信号を出すだけで、ポンプを動かす実際の電流は別の電源からそのスイッチを通って流れます。スイッチには4つの選択肢があります。ロジックレベルMOSFET、NPNトランジスタ、市販のMOSFETモジュール、リレーモジュールです。それぞれがどんなときに向いているかを、下の表にまとめました。

駆動方法PWMによる速度調整3.3 Vのボードでメモ
ロジックレベルMOSFET(IRLZ44N、AO3400A)できるAO3400Aはとてもよい、IRLZ44Nでも十分最もおすすめ。ほとんど発熱しない
NPNトランジスタ(2N2222A、BC337)できる使える。ベース抵抗を小さくする300 mAまで。≈ 0.2〜0.3 Vの電圧降下
IRF520 MOSFETモジュールできる不可。半分しかオンにならない5 Vなら約1 Aまで使える
リレーモジュールできない(オン/オフのみ)3.3 Vで動作するモジュールが必要カチカチ鳴り、接点が摩耗する。12 Vや商用電源のポンプ向け
L298N / L9110Sモータードライバできる使える逆回転は不要。L298Nでは最大2 Vの電圧降下
MOSFETの選び方、ゲート抵抗、ロジックレベルの意味について詳しく知りたい場合は「ArduinoでMOSFETを使う方法」を、BJTとベース抵抗の計算については「トランジスタとは?」を読んでください。手元のトランジスタのピン配置と増幅率は「トランジスタのピン配置」ツールで調べられます。

Arduinoのウォーターポンプの配線:MOSFET、ダイオード、共通GND

最も頑丈で応用が利くのは、ポンプをローサイドでスイッチングするNチャネルのロジックレベルMOSFETの回路です。ポンプのプラス線は外部電源のプラスに直接つなぎ、マイナス線はMOSFETのドレインにつなぎます。MOSFETのソースはGNDへ、ゲートは抵抗を通してArduinoのピンへつなぎます。ピンがHIGHになるとMOSFETが導通し、ポンプのマイナスをGNDにつないでポンプが回ります。IRLZ44Nでは、文字が印刷された面を手前に向けたとき、ピンは左からゲート、ドレイン、ソースの順です。

接続Arduino UnoESP32Raspberry Pi Pico
制御ピン → ゲート抵抗 → ゲートD9(PWM)、220 ΩGPIO 25、100 ΩGP15、100 Ω
ゲートとGNDの間のプルダウン抵抗10 kΩ10 kΩ10 kΩ
MOSFETのソースGNDGNDGND
MOSFETのドレインポンプのマイナス(黒)の線ポンプのマイナス(黒)の線ポンプのマイナス(黒)の線
ポンプのプラス(赤)の線外部5 V電源のプラス外部5 V電源のプラス外部5 V電源のプラス
外部電源のマイナスArduinoのGND(共通グラウンド)ESP32のGND(共通グラウンド)PicoのGND(共通グラウンド)
1N5819ダイオード、ポンプに逆並列カソード(線のある側)をポンプのプラスへカソードをポンプのプラスへカソードをポンプのプラスへ

ゲート抵抗は、MOSFETのゲート容量を充電するときにピンから流れる突入電流を制限します。10 kΩのプルダウン抵抗は、Arduinoの起動中やコードの書き込み中など、ピンの状態がまだ決まっていない間、ゲートをGNDに保ちます。この抵抗がないと、リセットのたびにポンプが数秒間勝手に動くことがあります。植木鉢のそばなら、机にコップ1杯分の水がこぼれることになります。ダイオードと共通GNDは、それぞれ独立した見出しで説明するほど重要です。

フライバックダイオード:ポンプを止めるときの電圧スパイク

モーターの巻線はコイルのようにふるまい、コイルは流れている電流が急に止まることを許しません。MOSFETがオフになった瞬間、巻線にたまったエネルギーは逃げ道を探し、ドレインに電源電圧をはるかに超える短い電圧スパイクを発生させます。このパルスはやがてMOSFETやトランジスタを破壊し、同じラインにつながったArduinoをリセットさせます。対策は、ポンプの2つの端子に逆向きにダイオードをつなぐことです。カソード(線のある側)をプラスへ、アノードをマイナスへつなぎます。通常の動作中、ダイオードには電流がまったく流れません。MOSFETがオフになると、コイルの電流がダイオードを通ってポンプに戻り、エネルギーは害なく消えます。

PWMでポンプを高速にオン・オフする場合、ダイオードは周期ごとに導通するので、高速なショットキーダイオードの1N5819が最適です。オン・オフするだけなら、手元にある1N4007でも十分です。ブラシから出るノイズを減らすには、ポンプの端子に100 nFのセラミックコンデンサもはんだ付けするとよいでしょう。ダイオードの種類と向きの見分け方は「ダイオードとは?」で説明しています。

別電源と共通GND:なぜArduinoがリセットされるの?

Arduino Unoの5Vピンからポンプに電源を供給すると、最初は動いているように見えますが、信頼性はありません。USBから給電されたUnoは、全体が500 mAのヒューズ(ポリスイッチ)の後ろにあり、パソコンのUSBポートも通常は500 mAまでしか供給しません。ポンプが起動すると、400〜600 mAの突入電流で電圧が一瞬4 Vを下回り、マイコンがリセットされたり、シリアルモニタの接続が切れたり、コードがおかしな動きをしたりします。代わりにACアダプターをUnoのDCジャックにつなぐと、今度はボード上の5 Vレギュレーターが熱くなります。入力が9 Vで250 mAのポンプなら、レギュレーターは(9 − 5) × 0.25 = 1 Wを熱に変えます。

  • 5 V ACアダプター(1〜2 A):最も実用的な方法です。ポンプと、必要ならArduinoも同じアダプターから、ただし別々の線で給電します。
  • 単3電池4本(4 × AA、6 V):6 Vのポンプに最適です。新しい電池では6.4 Vになりますが、ポンプには安全な値です。
  • 18650 Li-ion(3.7〜4.2 V):3〜5 Vのポンプに向いています。充電にはTP4056モジュールを使います。
  • ブレッドボード電源モジュール:MB102などのモジュールはブレッドボードに5 Vと3.3 Vを供給します。小型のポンプなら十分です。詳しくは「ブレッドボード電源モジュール」のガイドを参照してください。
  • 12 Vのシステムがある場合:LM2596降圧コンバーターで5 Vに下げてください。12 Vを6 Vのポンプに直接かけてはいけません。
外部電源のマイナスをArduinoのGNDにつなぐのを忘れないでください。共通GNDがないとゲート信号の基準がなくなり、MOSFETがオンにならず、ポンプはまったく動きません。さらに悪いことに、不規則に半分だけオンになって発熱することもあります。その理由は「GNDと共通グラウンド」で説明しています。また、電池の持ちを見積もるときは、ポンプではなくArduinoのことを考えてください。1日30秒動く200 mAのポンプが使うのは1日約1.7 mAhですが、常に動いているUnoは約1200 mAhを使います。「電池寿命計算ツール」を使うと、すぐにわかります。

流量と揚程:ポンプは水をどこまで持ち上げられる?

販売者が示す100〜120 L/hの流量は、ホースをつけず、出口を水面に置いた状態での値です。実際には、水がホースを上るにつれてポンプは重力に逆らって働くため、流量が下がります。ポンプがもう水をまったく持ち上げられなくなる高さを最大揚程といいます。この高さでは、羽根車は回っていてもホースから水は出てきません。長いホース、細いホース、折れ曲がったホースも、摩擦が増えるため同じ影響があります。下の表は、5 Vで出口を開放したときに約100 L/hを出す一般的なポンプが、高さによってどう変わるかを示しています。

水面からホースの先端までの高さおおよその流量1秒あたり
0 cm100 L/h≈ 28 ml
25 cm75 L/h≈ 21 ml
50 cm50 L/h≈ 14 ml
75 cm25 L/h≈ 7 ml
100 cmほぼゼロぽたぽたと垂れる程度

そのため、水やりの時間をカタログの値から計算するのではなく、実際の装置で測定してください。実際に使う高さでホースを計量カップに向け、ポンプをちょうど10秒間動かして、カップの水の量を読み取ります。たとえば185 mlなら流量は18.5 ml/sで、250 mlを出すにはポンプを250 / 18.5 ≈ 13.5秒動かす必要があります。測定を3回繰り返して平均をとると、電池の電圧やホースの違いによる誤差が小さくなります。ポンプの電圧が変わると(電池が弱ってくると)流量も変わります。正確な量を出したい場合は、安定した5 V電源を使ってください。

空運転とサイフォン効果:ポンプの2つの隠れた敵

ポンプの軸受けを潤滑し、モーターを冷やしているのは水です。タンクが空になると、ポンプは空気の中で回り、羽根車の軸受けが摩擦で熱くなり、プラスチック部品がやわらかくなり、モーターは通常より速く回ります。数秒の空運転ならたいていのポンプは壊れませんが、何分も空運転したポンプは固着するか、音が変わって流量が落ちてしまいます。自動化したシステムでこれを防ぐ方法は2つあります。タンクに水位センサーやフロートスイッチを入れることと、ポンプが1回に動ける最長時間をコードで制限することです。下の自動水やりのコードでは、その両方を行います。

サイフォン効果に注意:ホースの先端がタンクの水面より低いと、ポンプが止まったあとも水が重力で流れ続け、タンクの水が植木鉢に流れ出てしまいます。ホースの一番高い位置を常にタンクの水面より上に保つか、ホースの一番上に針で小さな空気穴を開けてください。ポンプが止まると空気が入り、水の流れが切れます。

ステップごとに:初めてのポンプテスト

  1. 水を入れた容器にポンプを完全に沈め、出口に30〜50 cmのシリコンホースを取り付けます。ホースの先端は2つ目の容器に向けます。
  2. IRLZ44Nをブレッドボードに挿します。ゲートを220 Ωを通してD9に、さらに10 kΩを通してGNDにつなぎます。ソースはGNDにつなぎます。
  3. ポンプの黒い線をドレインに、赤い線を外部5 V電源のプラスにつなぎます。1N5819ダイオードを、線のある側がプラス側になるようにポンプの2つの端子に取り付けます。
  4. 外部電源のマイナスをArduinoのGNDにつなぎます。配線をもう一度確認してから、電源を入れます。
  5. 下のコードを書き込み、シリアルモニタを9600ボーで開きます。ポンプが3秒動いて10秒止まれば成功です。
C++ (Arduino IDE)
1const byte PUMP_PIN = 9;            // MOSFET gate (220 Ω üzerinden) / MOSFET gate (through 220 Ω)
2
3void setup() {
4  pinMode(PUMP_PIN, OUTPUT);
5  digitalWrite(PUMP_PIN, LOW);      // açılışta pompa kapalı / pump off at start-up
6  Serial.begin(9600);
7}
8
9void loop() {
10  Serial.println(F("Pompa calisiyor / pump on"));
11  digitalWrite(PUMP_PIN, HIGH);     // MOSFET iletimde, pompa döner / MOSFET on, pump runs
12  delay(3000);                      // 3 saniye su bas / pump for 3 seconds
13  Serial.println(F("Pompa durdu / pump off"));
14  digitalWrite(PUMP_PIN, LOW);
15  delay(10000);                     // 10 saniye bekle / wait 10 seconds
16}

ポンプが動かない場合は、まず共通GND、次にMOSFETのピンの順番を確認してください。止まらない場合は、ドレインとソースが逆になっている可能性があります。流量を測るには、同じコードのdelay(3000)をdelay(10000)に変えて、ホースを計量カップに向けるだけです。このコードはdelay()を使っているので、ポンプが動いている間、Arduinoはほかの処理ができません。次の例からはmillis()で時間を計ります。違いが気になる場合は「millis()とdelay()の違い」を見てください。

PWMでポンプの速度を調整する

MOSFETを使う最大の利点は、PWMでポンプの速度を調整できることです。ゆっくりした流れは噴水ではより自然に見え、水槽のフィルターでは汚れを巻き上げにくく、量を出すときにも細かい調整ができます。実用上の問題が2つあります。1つ目は、小型のポンプは低いデューティ比(たいてい30〜40%未満)では回り始められず、ブーンとうなるだけになることです。そこでコードでは、まず短時間フルパワーでポンプを起動し、そのあと指定の速度に下げます。2つ目は、UnoのD9ピンの490 HzのPWMでは、ポンプから耳に聞こえる高い音が出ることです。コードではこの周波数を3.9 kHzに上げています。

C++ (Arduino IDE)
1const byte PUMP_PIN = 9;            // MOSFET gate, Timer1 PWM pini / Timer1 PWM pin
2const byte POT_PIN = A0;            // hız potansiyometresi / speed potentiometer
3const byte MIN_DUTY = 90;           // bunun altında pompa dönmez (≈ %35) / pump stalls below this (≈ 35 %)
4
5byte duty = 0;
6
7void setup() {
8  // D9-D10 PWM frekansı 490 Hz yerine 3,9 kHz (daha az vızıltı) / D9-D10 PWM at 3.9 kHz instead of 490 Hz (less whine)
9  TCCR1B = (TCCR1B & 0b11111000) | 0x02;
10  pinMode(PUMP_PIN, OUTPUT);
11  Serial.begin(9600);
12}
13
14void loop() {
15  int raw = analogRead(POT_PIN);                    // 0-1023
16  byte target = map(raw, 0, 1023, 0, 255);
17  if (target < MIN_DUTY) target = 0;                // çok yavaşsa tamamen durdur / stop completely if too slow
18
19  if (duty == 0 && target > 0) {                    // pompa duruyordu, şimdi kalkacak / pump was stopped, now starting
20    analogWrite(PUMP_PIN, 255);                     // kısa tam güç darbesi / short full-power kick
21    delay(150);
22  }
23  duty = target;
24  analogWrite(PUMP_PIN, duty);
25
26  Serial.print(F("PWM: "));
27  Serial.print(duty);
28  Serial.print(F("  (%"));
29  Serial.print(duty * 100 / 255);
30  Serial.println(F(")"));
31  delay(100);
32}

ポテンショメーターの中央のピンをA0に、両端のピンを5VとGNDにつなぎます。TCCR1Bの行が影響するのはTimer1、つまりD9とD10のピンだけです。millis()とdelay()はTimer0を使うので、そのまま動きます。ただしServoライブラリもTimer1を使うので、プロジェクトにサーボがある場合はこの行を削除してください。MIN_DUTYは手元のポンプで探します。ポテンショメーターをゆっくり回し、ポンプが自力で回り始められる最低の値をシリアルモニタで読み取り、少し余裕を足してください。ポンプの電圧を下げると揚程も下がります。遠心ポンプの圧力は回転数の2乗に比例するため、半分の速度では、全速のときの約4分の1の高さまでしか水を持ち上げられません。

液体ディスペンサー:ボタンを押すとちょうど50 ml

流量を測ったら、ポンプを定量ディスペンサーにするのは簡単です。必要な量を流量で割れば、ポンプを動かす時間がわかります。下のコードでは、D2とGNDの間につないだボタンを押すたびに50 mlの液体を出します。ポンプの動作中にもう一度ボタンを押すと、その回は中止されます。時間をmillis()で計っているので、ループは待たされることがなく、常にボタンを読み取れます。ソープディスペンサー、植物の肥料の定量供給装置、カクテルマシンなどのプロジェクトの基本になる考え方です。

C++ (Arduino IDE)
1const byte PUMP_PIN = 9;                 // MOSFET gate / MOSFET gate
2const byte BUTTON_PIN = 2;               // buton: D2 ile GND arası / button between D2 and GND
3const float ML_PER_SECOND = 18.5;        // kendi ölçtüğün debi / the flow rate you measured
4const float DOSE_ML = 50.0;              // bir basışta verilecek miktar / amount per press
5
6unsigned long doseTime = 0;              // ms cinsinden doz süresi / dose time in ms
7unsigned long startTime = 0;
8unsigned long lastPress = 0;
9bool pumping = false;
10bool lastButton = HIGH;
11
12void setPump(bool on) {
13  pumping = on;
14  digitalWrite(PUMP_PIN, on ? HIGH : LOW);
15  if (on) startTime = millis();
16}
17
18void setup() {
19  pinMode(PUMP_PIN, OUTPUT);
20  digitalWrite(PUMP_PIN, LOW);
21  pinMode(BUTTON_PIN, INPUT_PULLUP);     // basılıyken LOW / LOW while pressed
22  Serial.begin(9600);
23  doseTime = (unsigned long)(DOSE_ML / ML_PER_SECOND * 1000.0);
24  Serial.print(F("Doz suresi / dose time (ms): "));
25  Serial.println(doseTime);              // 50 / 18,5 = 2703 ms
26}
27
28void loop() {
29  bool button = digitalRead(BUTTON_PIN);
30  if (button == LOW && lastButton == HIGH && millis() - lastPress > 200) {   // yeni basış, 200 ms debounce / new press, 200 ms debounce
31    lastPress = millis();
32    setPump(!pumping);                   // ilk basış başlatır, ikincisi iptal eder / first press starts, second cancels
33    Serial.println(pumping ? F("Doz basladi / dose started") : F("Iptal / cancelled"));
34  }
35  lastButton = button;
36
37  if (pumping && millis() - startTime >= doseTime) {   // süre doldu / time is up
38    setPump(false);
39    Serial.println(F("Doz tamam / dose done"));
40  }
41}

1回目だけ量が少ない場合、原因はおそらくホースが空だったことです。ポンプはまずホースを満たし、それから液体を外に出します。ホースの先端をタンクの水面より少し上に保てば、ホースは満たされたままになり、毎回同じ量が出ます。油、シロップ、液体せっけんのような粘りのある液体では、流量が水よりずっと少なくなるので、キャリブレーションは必ずその液体で行ってください。食品に触れるプロジェクトでは食品グレードのシリコンホースを使い、使うたびにポンプをきれいな水ですすいでください。

土壌水分に応じた自動水やり

最も人気のあるArduinoのウォーターポンプのプロジェクトは、土が乾くと自分で水をやる植木鉢です。初心者が陥りやすいのは、土壌水分が目標値に届くまでポンプを動かし続けてしまうことです。水がセンサーまで届くには何分もかかり、その間に鉢から水があふれてしまいます。正しい方法は短く区切って水をやることです。ポンプを4秒動かし、水が土に広がるまで1分待ってから、もう一度水分を測ります。このコードでは、タンクが空ならポンプを一切動かしません。また、6回水をやっても水分が上がらない場合(センサーが土から抜けた、ホースが外れたなどの可能性)は、システムをロックしてLEDを点灯させます。センサーのキャリブレーションは「土壌水分センサー」のガイドで詳しく説明しています。

C++ (Arduino IDE)
1const byte PUMP_PIN = 9;                 // MOSFET gate / MOSFET gate
2const byte SOIL_PIN = A0;                // kapasitif toprak nem sensörü AOUT / capacitive soil sensor AOUT
3const byte FLOAT_PIN = 3;                // şamandıra: D3 ile GND arası / float switch between D3 and GND
4const byte LED_PIN = 13;                 // uyarı LED'i / warning LED
5
6const int DRY_VALUE = 600;               // sensör kuru havadayken / sensor in dry air
7const int WET_VALUE = 280;               // sensör bardak sudayken / sensor in a glass of water
8const int START_PERCENT = 35;            // bunun altında sulamaya başla / start watering below this
9const int STOP_PERCENT = 55;             // buna ulaşınca dur / stop once this is reached
10const unsigned long PULSE_MS = 4000;     // bir darbede pompa süresi / pump time per pulse
11const unsigned long SOAK_MS = 60000;     // suyun toprağa yayılma süresi / time for the water to soak in
12const byte MAX_PULSES = 6;               // bir sulamada en fazla darbe / max pulses per watering
13
14byte pulses = 0;
15bool locked = false;
16unsigned long lastCheck = 0;
17
18bool waterAvailable() {
19  return digitalRead(FLOAT_PIN) == LOW;  // şamandıra yukarıda: kontak kapalı / float up: contact closed
20}
21
22int readMoisture() {
23  long sum = 0;
24  for (byte i = 0; i < 10; i++) {        // 10 ölçümün ortalaması / average of 10 readings
25    sum += analogRead(SOIL_PIN);
26    delay(5);
27  }
28  int percent = map(sum / 10, DRY_VALUE, WET_VALUE, 0, 100);
29  return constrain(percent, 0, 100);
30}
31
32void runPump(unsigned long ms) {
33  unsigned long t0 = millis();
34  digitalWrite(PUMP_PIN, HIGH);
35  while (millis() - t0 < ms) {
36    if (!waterAvailable()) break;        // su biterse hemen dur / stop at once if the water runs out
37  }
38  digitalWrite(PUMP_PIN, LOW);
39}
40
41void setup() {
42  pinMode(PUMP_PIN, OUTPUT);
43  digitalWrite(PUMP_PIN, LOW);
44  pinMode(FLOAT_PIN, INPUT_PULLUP);
45  pinMode(LED_PIN, OUTPUT);
46  Serial.begin(9600);
47  lastCheck = millis() - SOAK_MS;        // ilk ölçüm hemen yapılsın / take the first reading right away
48}
49
50void loop() {
51  if (!waterAvailable()) {               // depo boş: yavaş yanıp sön / tank empty: slow blink
52    digitalWrite(LED_PIN, (millis() / 500) % 2);
53    return;
54  }
55  if (locked) {                          // arıza: LED sürekli yanar / fault: LED stays on
56    digitalWrite(LED_PIN, HIGH);
57    return;
58  }
59  digitalWrite(LED_PIN, LOW);
60  if (millis() - lastCheck < SOAK_MS) return;
61  lastCheck = millis();
62
63  int moisture = readMoisture();
64  Serial.print(F("Nem / moisture: %"));
65  Serial.println(moisture);
66
67  if (pulses == 0 && moisture >= START_PERCENT) return;   // sulama gerekmiyor / no watering needed
68  if (moisture >= STOP_PERCENT) {                        // hedefe ulaşıldı / target reached
69    pulses = 0;
70    return;
71  }
72  if (pulses >= MAX_PULSES) {                            // nem yükselmiyor: sensör ya da hortum sorunu / moisture not rising: sensor or hose problem
73    locked = true;
74    Serial.println(F("Kilitlendi, kontrol et / locked, check the setup"));
75    return;
76  }
77  runPump(PULSE_MS);
78  pulses++;
79}

コードで2つのしきい値を使っているのは意図的です。水分が35%を下回ると水やりを始め、55%に達するまで続けます。このヒステリシスのおかげで、しきい値付近で読み取り値が揺れても、ポンプがオンとオフを繰り返すことはありません。DRY_VALUEとWET_VALUEは手元のセンサーで測ってください。静電容量式のセンサーでは、この値は電源電圧やケーブルの長さによって変わります。フロートスイッチの線が切れるとピンはHIGHを読み取り、コードはタンクが空だと判断します。つまり、何かが故障してもシステムは安全側にとどまり、ポンプを止めます。決まった時間帯にだけ水をやりたい場合は、RTC時計モジュールを追加して、条件に時刻のチェックを加えてください。

ポンプの制御にリレーが向いているのはどんなとき?

手元にリレーモジュールしかない場合でも、小型ポンプを動かせます。ポンプのプラス側は、外部電源からリレーのCOM端子へ、NO端子からポンプへつなぎます。マイナス側は電源のマイナスにつなぎます。リレーはポンプをボードの回路から完全に絶縁でき、同じモジュールで12 Vの大きなポンプや商用電源で動く水槽用ポンプもオン・オフできます。その代わり、リレーではPWMによる速度調整ができず、切り替えのたびにカチッと鳴り、接点は時間とともに摩耗し、コイルだけで約70 mAを消費します。1日に数回ポンプをオン・オフするだけならリレーで十分ですが、定量供給や速度調整が必要なら、MOSFETのほうが常に優れています。リレーを使う場合でも、ポンプの端子にダイオードを入れると接点のアークを減らせます。

ESP32でスマホからウォーターポンプを操作する

ESP32のWi-Fiを使えば、スマホのブラウザからポンプを動かせます。下のコードはESP32で小さなWebサーバーを起動します。同じネットワークにつないだスマホで、シリアルモニタに表示されたIPアドレスを開くと、5秒と15秒の水やりボタンと停止ボタンが表示されます。WebServerはESP32のコアに含まれているので、追加のライブラリは不要です。安全のため、ポンプはどんな場合でも30秒を超えて動きません。接続が切れても、時間が来れば自動的に止まります。ESP32は3.3 Vで動作するので、3.3 Vで完全にオンになるMOSFETを選んでください。AO3400Aが最適ですが、小型ポンプの300 mA程度ならIRLZ44Nでも余裕で足ります。

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WebServer.h>
3
4const char* WIFI_SSID = "AgAdi";             // Wi-Fi adın (2,4 GHz) / your Wi-Fi name (2.4 GHz)
5const char* WIFI_PASS = "Sifre123";          // Wi-Fi şifren / your Wi-Fi password
6const int PUMP_PIN = 25;                     // MOSFET gate, 100 Ω üzerinden / through 100 Ω
7const unsigned long MAX_RUN_MS = 30000;      // güvenlik: en uzun çalışma / safety: longest run
8
9WebServer server(80);
10bool pumpOn = false;
11unsigned long pumpStart = 0;
12unsigned long pumpDuration = 0;
13
14void startPump(unsigned long ms) {
15  if (ms > MAX_RUN_MS) ms = MAX_RUN_MS;
16  pumpDuration = ms;
17  pumpStart = millis();
18  pumpOn = true;
19  digitalWrite(PUMP_PIN, HIGH);
20}
21
22void stopPump() {
23  pumpOn = false;
24  digitalWrite(PUMP_PIN, LOW);
25}
26
27void handleRoot() {
28  String html = F("<!DOCTYPE html><html><head><meta charset='utf-8'>"
29                  "<meta name='viewport' content='width=device-width,initial-scale=1'>"
30                  "<title>Pompa</title></head><body style='font-family:sans-serif;text-align:center'>"
31                  "<h2>BlueGrays Pompa</h2><p>");
32  html += pumpOn ? "Pompa çalışıyor / pump is on" : "Pompa kapalı / pump is off";
33  html += F("</p><p><a href='/run?s=5'><button>5 sn</button></a> "
34            "<a href='/run?s=15'><button>15 sn</button></a> "
35            "<a href='/stop'><button>Durdur / Stop</button></a></p></body></html>");
36  server.send(200, "text/html", html);
37}
38
39void goHome() {                              // ana sayfaya geri dön / go back to the main page
40  server.sendHeader("Location", "/");
41  server.send(303);
42}
43
44void handleRun() {
45  long seconds = server.arg("s").toInt();     // /run?s=5 → 5 saniye / 5 seconds
46  if (seconds > 0) startPump(seconds * 1000UL);
47  goHome();
48}
49
50void handleStop() {
51  stopPump();
52  goHome();
53}
54
55void setup() {
56  pinMode(PUMP_PIN, OUTPUT);
57  digitalWrite(PUMP_PIN, LOW);
58  Serial.begin(115200);
59  WiFi.mode(WIFI_STA);
60  WiFi.begin(WIFI_SSID, WIFI_PASS);
61  while (WiFi.status() != WL_CONNECTED) {
62    delay(500);
63    Serial.print(".");
64  }
65  Serial.println();
66  Serial.print(F("Tarayicida ac / open in the browser: http://"));
67  Serial.println(WiFi.localIP());
68
69  server.on("/", handleRoot);
70  server.on("/run", handleRun);
71  server.on("/stop", handleStop);
72  server.begin();
73}
74
75void loop() {
76  server.handleClient();
77  if (pumpOn && millis() - pumpStart >= pumpDuration) {   // süre doldu / time is up
78    stopPump();
79  }
80}

このページは自宅のWi-Fiネットワークからしか開けません。外出先からもポンプを操作したい場合や、タンクが空になったときに通知を受け取りたい場合は、「ESP32のTelegramボット」や「Blynk」のガイドの方法をこのコードに加えてください。WebSocketですぐに更新されるダッシュボードにするには、「ESP32の非同期Webサーバー」のガイドを参照してください。ESP32のピンの出力は3.3 VなのでIRF520モジュールはここでは動きません。モジュールを使う場合は、ロジックレベルMOSFETを搭載したものを選んでください。

Raspberry Pi Picoでタイマー式の水やり(MicroPython)

Picoでは、GP15につないだMOSFETでポンプを駆動し、PWMでソフトスタートさせられます。ソフトスタートはポンプの起動電流を数百ミリ秒に分散させ、電源電圧が急に下がるのを防ぎます。Picoとポンプが同じ電源を使っている場合は、これで不規則なリセットを防げます。下のコードは12時間ごとに8秒間水をやり、GP14につないだボタンを押すと、さらに3秒間水をやります。Picoのピンは3.3 Vしか出さないので、ここでもAO3400Aのように3.3 Vでの動作が保証されたMOSFETを選んでください。MicroPythonが初めての場合は、まず「Raspberry Pi Picoとは?」を見てください。

MicroPython
1from machine import Pin, PWM
2import time
3
4pump = PWM(Pin(15))                       # MOSFET gate, 100 Ω üzerinden / through 100 Ω
5pump.freq(1000)                           # 1 kHz PWM
6pump.duty_u16(0)                          # açılışta kapalı / off at start-up
7button = Pin(14, Pin.IN, Pin.PULL_UP)     # buton: GP14 ile GND arası / button between GP14 and GND
8
9INTERVAL_MS = 12 * 60 * 60 * 1000         # 12 saatte bir / every 12 hours
10WATER_MS = 8000                           # her seferde 8 saniye / 8 seconds each time
11SPEED = 0.8                               # %80 hız / 80 % speed
12
13def water(ms):
14    top = int(65535 * SPEED)
15    for d in range(0, top, 2000):         # yumuşak kalkış (≈ 0,3 s) / soft start (≈ 0.3 s)
16        pump.duty_u16(d)
17        time.sleep_ms(10)
18    pump.duty_u16(top)
19    time.sleep_ms(ms)
20    pump.duty_u16(0)                      # pompayı durdur / stop the pump
21    print("Sulandi / watered:", ms, "ms")
22
23last = time.ticks_ms()
24while True:
25    if time.ticks_diff(time.ticks_ms(), last) >= INTERVAL_MS:
26        last = time.ticks_ms()
27        water(WATER_MS)
28    if button.value() == 0:               # elle sulama / manual watering
29        water(3000)
30        while button.value() == 0:        # bırakılmasını bekle / wait for release
31            time.sleep_ms(10)
32    time.sleep_ms(50)

このコードはtime.ticks_diff()で時間を計ります。この関数は、カウンターが一周して0に戻ったときでも正しい差を返します。Picoの内部の時計は電源を切るとリセットされ、1日に数秒ずれることもあるので、「毎朝07:00に水やり」のように実際の時刻に合わせたスケジュールが必要なら、RTCモジュールを追加するか、Pico Wを使ってインターネットから時刻を取得(NTP)してください。停電のあとは、12時間のカウンターが0からやり直しになります。たいていの植物には問題ありませんが、長い旅行の間に動かすプロジェクトでは注意してください。

小型のウォーターポンプを使ったプロジェクトのアイデア

  • 旅行中の水やりシステム:バケツ1杯の水と、いくつかの鉢に分岐した細いホースで、2週間植物に水をやります。全体の作り方は「スマート温室プロジェクト」で紹介しています。
  • ペット用の自動給水器:器の水位が下がると、ポンプがタンクから水を補充します。水位の検知には非接触液面センサーが便利です。
  • 非接触のソープディスペンサー・消毒液ディスペンサー:HC-SR04や赤外線センサーが手を検知すると、ポンプが0.5秒間動きます。
  • カクテル・ドリンクマシン:ボトルごとに入れた3〜4台のポンプの流量をそれぞれ測り、レシピどおりに飲み物を混ぜます。
  • 卓上の滝・飾り池:夜はPWMで流れをゆるやかにし、LDRで部屋が暗くなったのを検知すると止まる噴水です。
  • 水槽の自動給水:フロートスイッチで水位の低下を検知すると、蒸発した分の水を別のタンクから補充するシステムです。
  • スマートホームとの連携:ESP32を使い、MQTTとHome Assistantでポンプをほかの機器と連携させます。

よくある間違いと対処法

症状考えられる原因対処法
ポンプがうなるだけで水を送らない内部に空気が残っている、またはポンプが水面より上にあるポンプを完全に沈め、軽く振って空気を抜く。ホースが折れないように置く
ポンプが動くとArduinoがリセットされるポンプをArduinoの5Vピンから給電している、またはダイオードがないポンプを別の5 V電源から給電し、逆並列の1N5819と100 nFを追加する
ポンプがまったく動かない共通GNDがない、またはMOSFETのピンの順番が違う外部電源のマイナスをArduinoのGNDにつなぎ、G-D-Sの順番を確認する
Arduinoの起動中にポンプが一瞬動くゲートが浮いている、プルダウン抵抗がないゲートとGNDの間に10 kΩを入れる
ポンプが止まったあとも水が流れ続けるサイフォン効果:ホースの先端がタンクの水面より低いホースを高くするか、ホースの一番上に小さな空気穴を開ける
流量がだんだん落ちる吸い込み口の網の詰まり、電池の消耗、または空運転による摩耗吸い込み口を掃除し、電源の電圧を測り、水位センサーを追加する
低いPWMでポンプが回らないデューティ比がモーターの起動しきい値より低い起動時に短くフルパワーをかけ、MIN_DUTYを上げる
回路を植物のそばに設置する前に、テスト用の容器を使って机の上であらゆる場面を試してください。タンクが空のときはどうなるか、センサーの線が外れたらどうなるか、停電して電源が戻ったときにポンプが勝手に動かないか。電子回路は必ず水の容器の真上ではなく、横か上のほうに置いてください。また、ケーブルはボードに届く前に一度下に垂れるようにたるませ(ドリップループ)、ケーブルを伝ってきた水がボードに届かないようにしてください。

正しく駆動すれば、小型の水中ポンプは何年もトラブルなく動く、安くて静かな部品です。ロジックレベルMOSFET、逆向きのダイオード、別の5 V電源、共通GNDがあれば、Arduinoは完全に安全です。あとはアイデア次第です。測った流量を使ってミリリットル単位で量を出したり、土壌水分に応じて水をやったり、ESP32でスマホからポンプを管理したりできます。BlueGraysアプリでは、「スマート水やりステーション」のプロジェクトを、ESP32のWebサーバーやRTC時計のプロジェクトと一緒に、ステップごとの回路図とコード付きで紹介しています。

よくある質問

ウォーターポンプをArduinoにつなぐには?

小型のウォーターポンプはArduinoのピンに直接つなげません。ピンが出せる電流は20〜40 mAですが、ポンプは150〜300 mAを必要とするからです。ポンプのプラスを外部5 V電源に、マイナスをIRLZ44NのようなロジックレベルMOSFETのドレインにつなぎます。ゲートは220 Ωを通してピンに、ソースはGNDにつなぎます。ポンプに1N5819ダイオードを逆並列に入れ、2つの電源のGNDを共通にしてください。

小型のウォーターポンプの消費電流は?

3〜6 Vの小型水中ポンプは、動作中ふつう130〜220 mA、6 Vでは最大300 mAを流します。起動時には数ミリ秒の間、その2〜3倍になることがあります。そのため、電源は1 A以上のものを選び、ポンプをArduinoの5Vピンから給電しないようにしてください。

ウォーターポンプの駆動はリレーとMOSFETのどちらがいい?

3〜6 Vの小型ポンプなら、ロジックレベルMOSFETのほうが優れています。静かで摩耗せず、PWMで速度も調整できます。リレーはオン・オフしかできず、カチッと鳴り、さらにコイルが約70 mAを消費します。リレーが向いているのは、12 Vの大きなポンプや商用電源で動くポンプの場合や、ポンプを1日に数回しか動かさない場合です。

小型のウォーターポンプを空運転するとどうなる?

このポンプは水で冷やされ、軸受けも水で潤滑されています。数秒の空運転ならふつうは問題ありませんが、何分も空運転すると軸受けが過熱し、プラスチック部品が摩耗して、ポンプが固着することがあります。自動化したシステムでは、タンクに水位センサーかフロートスイッチを入れ、コードで最長の動作時間を制限してください。

小型のウォーターポンプは水をどのくらいの高さまで上げられる?

3〜6 Vの小型水中ポンプの最大揚程は、たいてい40〜110 cmです。その高さに近づくにつれて流量は急に下がり、限界の高さではホースからほとんど水が出なくなります。もっと高い場所に水を送る必要がある場合は、より強力な12 Vのポンプかダイヤフラムポンプを使ってください。

Arduinoでウォーターポンプの速度を調整できる?

できます。ロジックレベルMOSFETでポンプを駆動していれば、PWMピンにanalogWrite()を使って速度を調整できます。小型のポンプはデューティ比が約30〜40%より低いと起動できないので、まず短くフルパワーをかけてから速度を下げてください。リレーでは速度を調整できません。

全プロジェクトを見る
スマート水やりステーション
#83上級
プレミアム

スマート水やりステーション

旅行中も植物が枯れないよう、自動で水やりをするシステムです。土壌水分センサーで土の湿り具合を測定し、乾燥するとArduinoが給水ポンプを数秒間動かして、青いライトを点灯させます。水分が適切なときは緑のライトが点灯します。土がひどく乾燥すると、赤いライトが点滅し、ブザーが鳴って知らせます。

5.0(42)
57
ESP32非同期Webサーバー(LCDにIPアドレスを表示)
#129上級

ESP32非同期Webサーバー(LCDにIPアドレスを表示)

このプロジェクトでは、ESP32を同じWi-Fiネットワーク上のスマートフォンやパソコンから操作できる非同期Webサーバーにします。ESPAsyncWebServerライブラリを使うと、従来のWebServer.hのように1つのリクエストで処理がブロックされず、複数のリクエストを同時に処理できます。ブラウザーでESP32のIPアドレスを開き、ON/OFFボタン(/onと/offのルート)を押すと、GPIO 5に接続したLEDを点灯・消灯できます。

4.8(16)
26
ESP32 Wi-Fi STA接続(LCDディスプレイ付き)
#127上級

ESP32 Wi-Fi STA接続(LCDディスプレイ付き)

このプロジェクトでは、ESP32をステーション(STA)モードで家庭のWi-Fiネットワークに接続し、安全で障害に強い接続を実現します。SSIDとパスワードを別のsecrets.hファイルに保存してGitへの流出を防ぎ、自動再接続の仕組みを実装します。RSSIによる信号強度とIPアドレスはI2C LCDディスプレイに表示します。内蔵LEDは状態表示に使います。実運用を想定した接続管理の仕組みです。

4.4(21)
34
ESP32とDS1307 RTCのデジタル時計(I2C + LCD)
#120中級
プレミアム

ESP32とDS1307 RTCのデジタル時計(I2C + LCD)

このプロジェクトでは、DS1307リアルタイムクロック(RTC)モジュールを使って16x2 I2C LCDに時刻と日付を表示します。DS1307は電池でバックアップされるRTCで、ESP32の電源を切っても時刻を保持します。両方のモジュールが同じI2Cバス(SDA/SCL)を共有するため、2本の信号線だけで複数の機器を制御する方法を学べます。I2C通信プロトコルやRTCモジュールの動作原理、LCDの表示データを随時更新する方法を実践的に学ぶプロジェクトです。

4.6(26)
40
DS1302 RTC時計モジュールのセットアップ
#45初級

DS1302 RTC時計モジュールのセットアップ

Arduinoの電源を切っても時刻を保持する、小さな時計モジュールを動かします。モジュールには専用の小さな電池があり、一度時刻を設定すると、パソコンの画面に日付と時刻が毎秒表示されます。アラームやタイマー、記録を残すプロジェクトは、いずれもこのステップから始まります。

4.5(23)
31
BluetoothでスマートフォンからLEDを操作
#34初級
プレミアム

BluetoothでスマートフォンからLEDを操作

スマートフォンで部屋の照明をつけたり消したりするための、小さな練習です。Bluetoothモジュールがスマートフォンから送られた文字をArduinoに伝えます。ある文字で赤いLEDが、別の文字で緑のLEDが点灯し、同じ文字を小文字で送ると消灯します。無線操作の仕組みを、ごくシンプルな形で学べます。

4.8(68)
89
ESP32スマート照明(PIR + LDR + リレー + OLED)
#141上級
プレミアム

ESP32スマート照明(PIR + LDR + リレー + OLED)

ESP32で廊下やトイレ、食品庫の照明をスマート化します!PIRモーションセンサー、LDR光センサー、リレーモジュールを使い、「暗い場所で動きを検知すると点灯する」定番の仕組みを作ります。周囲が明るければ動きを検知しても点灯しないため、日中の無駄な電力消費を抑えられます。照明は30秒間点灯し、動きが続くとタイマーがリセットされて点灯時間が延びます。SSD1306 OLEDには大きな文字で状態(ON / DAYTIME / WAITING)とカウントダウンを表示します。

4.3(6)
11