
Arduinoと超音波センサを使って水面レベルセンサを作りました、リレーでポンプのON・OFFを制御させることで水槽間の水を循環させることができます。
今回は、ArduinoUnoに超音波モジュールであるURM37を使って水槽の水面高さを測定することでポンプのON・OFF条件を決定しています。
目次
水槽間で水を循環させたい

アクアリウムではろ過能力が非常に重要で、水槽の中の生体数とろ過能力は切っても切れない関係があります。水槽のろ過能力を超えてしまうと俗にいう崩壊が待っています。
ですが、生体数が増えると高いろ過能力と水量、ろ過能力の高いフィルターも手持ちにありません。そのため、それを補う方法として水槽間の水を循環させる方法を考え付きました。
サイフォンの原理とポンプで水を循環させる
水位が同じであればパイプ通して(サイフォンの原理)ポンプを循環させればで水を循環させることが可能ですが、水位差があるとパイプとモーターの水流量を釣り合わせるのが難しくなるため、ポンプ側での制御が必要になります。
ちなみに、水槽で使用するポンプは同期モーターを使用しているため、VVVFコントローラでもなければなければ水流量を調整することが出来ません。
現在使用しているポンプはモータ出力が高いものなので、ポンプによる水のくみ上げ量ほうが多く水槽の水が溢れてしまいます。そのため、水面高さを測定してコンセントをON・OFFしてポンプを制御させる必要があります。
Arduinoで水面高さの検知とポンプの制御の方法
超音波センサURM37による水面高さ検知
水面高さの検知には、以前使用したURM37 v3.2を使用します。URM37の解像度は1cmとなっているため水槽の水面高さを測定するなら十分な精度と言えるでしょう。
動作させるプログラムも、サンプルコードを流用して測定データをif条件で分岐できるようにします。
ポンプの制御条件

本来、フィルターの水中ポンプは24時間稼働を前提に作られているもので、頻繁にON/OFFさせるようには出来ていないはずです。そのため、頻繁にON/OFFしないよう制御を調整する必要があります。
ポンプの制御条件には、水面高さ測定の他にポンプの状態も加えてヒステリシスな動作にすることで過剰なON・OFFを行わないようにします。
フローチャートにすると非常に簡単な処理で実装できるので、スケッチは短く済むでしょう。
条件1:何cm以下かつポンプがONの時ポンプOFF
条件2:何cm以上かつポンプがOFFの時ポンプON
ブロック図・配線図

この機能を実装させるためのブロック図をメモしておきます。非常に簡単なブロック構成になりますが、100V系と5V系が混在する構成となるので、リレーを使って確実に回路を分離する必要があります。

スケッチ
// # Editor : Jiang from DFRobot
// # Data : 24.07.2012
// # Product name:ultrasonic scanner Kit
// # Product SKU:SEN0001
// # Version : 0.2
// # Description:
// # The Sketch for scanning 180 degree area 4-500cm detecting range
// # Connection:
// # Pin 1 VCC (URM V3.2) -> VCC (Arduino)
// # Pin 2 GND (URM V3.2) -> GND (Arduino)
// # Pin 4 PWM (URM V3.2) -> Pin 3 (Arduino)
// # Pin 6 COMP/TRIG (URM V3.2) -> Pin 5 (Arduino)
// # Pin mode: PWM
// # Working Mode: PWM passive control mode.
// # If it is your first time to use it,please make sure the two jumpers to the right hand
// # side of the device are set to TTL mode. You'll also find a secondary jumper on
// # the left hand side, you must break this connection or you may damage your device.
#include <Servo.h> // Include Servo library
#define ON 1
#define OFF 0
Servo myservo; // create servo object to control a servo
////////////////////////////////////////////グローバル変数/////////////////////////////////////////
int pos=0; // variable to store the servo position
int URPWM=3; // PWM Output 0-25000us,every 50us represent 1cm
int URTRIG=5; // PWM trigger pin
int RL = 12; //リレーの操作(pin10使用の宣言)
int RLfrag= OFF; //RLの状態取得
int under = 20; //水の下限値(この値を超えるとポンプON)
int over = 17; //水の上限(この値を下回るとポンプOFF)
boolean up=true; // create a boolean variable
unsigned long time; // create a time variable
unsigned long urmTimer = 0; // timer for managing the sensor reading flash rate
unsigned int Distance=0; //水面距離
uint8_t EnPwmCmd[4]={0x44,0x22,0xbb,0x01}; // distance measure command
////////////////////////////////////////////超音波センサの初期設定/////////////////////////////////////////
void setup(){ // Serial initialization
Serial.begin(9600); // Sets the baud rate to 9600
myservo.attach(9); // Pin 9 to control servo
PWM_Mode_Setup();
pinMode(RL, OUTPUT);
}
///////////////////////////////////////////main/////////////////////////////////////////
void loop(){
if(millis()-time>=20){ // interval 0.02 seconds
time=millis(); // get the current time of programme
if(up){ // judge the condition
if(pos>=0 && pos<=179){
pos=pos+1; // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
}
if(pos>179) up= false; // assign the variable again
}
else {
if(pos>=1 && pos<=180){
pos=pos-1;
myservo.write(pos);
}
if(pos<1) up=true;
}
}
if(millis()-urmTimer>50){
urmTimer=millis();
PWM_Mode();
}
WaterSurface(); //リレー操作
delay(10);
}
void PWM_Mode_Setup(){
pinMode(URTRIG,OUTPUT); // A low pull on pin COMP/TRIG
digitalWrite(URTRIG,HIGH); // Set to HIGH
pinMode(URPWM, INPUT); // Sending Enable PWM mode command
for(int i=0;i<4;i++){
Serial.write(EnPwmCmd[i]);
}
}
void PWM_Mode(){ // a low pull on pin COMP/TRIG triggering a sensor reading
digitalWrite(URTRIG, LOW);
digitalWrite(URTRIG, HIGH); // reading Pin PWM will output pulses
unsigned long DistanceMeasured=pulseIn(URPWM,LOW);
if(DistanceMeasured==50000){ // the reading is invalid.
Serial.print("Invalid");
}
else{
Distance=DistanceMeasured/50; // every 50us low level stands for 1cm
}
Serial.print("Distance=");
Serial.print(Distance);
Serial.println("cm");
}
////////////////////////////////////////////水面高さの条件分岐/////////////////////////////////////////
void WaterSurface(){
if(Distance>=under && RLfrag==OFF) //水面が規定値よりも低い場合でリレーがオフの場合 リレーをオン
{
digitalWrite(RL, HIGH);
RLfrag=ON;
}
else if(Distance<=over && RLfrag==ON) //水面が規定値よりも高い場合でリレーがオンの場合 リレーをオフ
{
digitalWrite(RL, LOW);
RLfrag=OFF;
}
}
////////////////////////////////////////////水面高さの条件分岐/////////////////////////////////////////
水槽へ設置してテストやケースへの組み込み

最低限配線したArduinoを水槽にクリップアームで固定して動作を確認してみます。超音波が水槽の壁面に反射してしまうため、位置決めがシビアでしたが位置さえ決めてしまえばこちらの期待通り動いてくれます。

上手く動くのが確認できたため、一式をケースに組み込みます。TAKACHIのアルミケースケースを加工してArduinoや超音波センサ、リレーを組み込みます。

まとめ
今回は、Arduinoで水面高さを検知してコンセントをON・OFFさせるという事に挑戦してみました。
ちょっと不安だった水面検知も問題なく動作しており、水があふれたことはありません。しかし、本来ならセンサーが破損したりArduinoがフリーズした場合などを想定し、別のセンサーを組み込むなどして二重化するべきなのですが、超音波以外のいいセンサーが見当たりません。今後の課題です。







