IoTで水耕栽培研究

水耕栽培とかIoTの備忘録

ECと水温測定

arduinoを使ってEC(電気伝導度)と水温を測定する回路を作成しました。

f:id:amesyabody:20220130222745j:plain
EC&水温測定系

ついでにFritzing(上の絵のように回路図を分かりやすく描けるアプリ)にもデビューしました! これは便利、回路図もすいすい描けちゃいます。 今回はこのFritzingを使って結線の様子を詳細に紹介しているので、ぜひご参考ください。

ECとは?

ECは水中の電気の通りやすさを表す値で、抵抗の逆数の次元を持っています。 水中の電気の通りやすさは水中のイオン量に相関があるので、 この値を測定することで、水中の液体肥料濃度を監視することができます。 ECはarduinoと一般的なコンセント電源、水温センサがあれば測定系を作ることができます。

必要なもの

回路

結線は単純です。 ECも水中温度もarduinoのアナログ測定機能を利用します。 回路上部に水温センサ、下部の端子台がEC測定電極を接続する箇所です。

f:id:amesyabody:20220130214351j:plain
ECと水温測定 回路図

f:id:amesyabody:20220130220411j:plain
回路図

プログラム

とても偉大な先人がいらっしゃったので、ほぼそのまま利用させて頂きました。 液体肥料の自動追加まで実現していてとても素晴らしいです! 将来的に実装したいのでそのままプログラムをコメントアウトして残しております。

/*
   このプログラムは、以下のURLを参考に作られました。
   有益なプログラムの公開に感謝いたします。
   https://hackaday.io/project/7008-fly-wars-a-hackers-solution-to-world-hunger/log/24646-three-dollar-ec-ppm-meter-arduino
   https://nadegata.info/ec-automation-how-to-make/
*/

//************************** ライブラリ ***************//

#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>


//***************************** 値などの設定変更 *****************************//
//動作させる時間等を変更させたい場合、この部分を変更ください。

int bps = 9600;
float setEC = 1.3; //ECを1.3から変更したい場合はここを変更
int pump_time = 2000; //ポンプを動かして、液肥を投入する時間 単位はミリ秒。ex)1秒=1000 1分=60000
long int interval = 5000; //測定するインターバル 単位はミリ秒 ex)1秒=1000 1分=60000
float temp_offset = 1.0; //適当な温度計で水温オフセット調整 ex)2.5度高くしたいとき=2.5



//##################################################################################
//-----------  300オーム未満の抵抗は使用しないでください    ------------
//##################################################################################

int R1 = 1000; //
int Ra = 25; //Arduino ピンの抵抗

//*****************************ピン  *****************************//
const int ECPin = A0;
const int ECGround = A1;
const int ECPower = A4;
const int Relay = 13; //ポンプを動かすリレー

#define ONE_WIRE_BUS 10 //DS18B20の黄色の線が刺さるピン


//***************************** LCD *****************************//
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//***************************** 温度補償 *****************************//
//溶液の導電率は液温によって変化します。
//そのため、25℃の導電率に補正した値を求めるようにしています。
float TemperatureCoef = 0.019;

//***************************** セル定数 *****************************//
//液体中に電極を差し込み、測定する場合はセル定数が必要です。
//1cm2の断面積と距離1cmの空間を切り出す場合は、センサのセル定数は1/cmです。
//日本国内で出回るプラグに合わせました。(穴があるタイプ)
float K = 2.8;
//***************************** ユーザーの変更可能部分 終了 *****************************//

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

float Temperature = 10;
float EC = 0;
float EC25 = 0;

float raw = 0;
float Vin = 5;
float Vdrop = 0;
float Rc = 0;

//*********************************以下よりプログラム開始******************************************************//
void setup()
{
  Serial.begin(bps);
  pinMode(ECPin, INPUT);
  pinMode(ECPower, OUTPUT); 
  digitalWrite(ECPower, LOW); 
  pinMode(ECGround, OUTPUT); 
  digitalWrite(ECGround, LOW);

  pinMode(Relay, OUTPUT); 
  digitalWrite(Relay, LOW); 

  delay(100);// 待機時間
  sensors.begin();
  delay(100);

  R1 = (R1 + Ra); // Taking into acount Powering Pin Resitance

  Serial.println("EC測定システム");
  Serial.println("Michael Ratcliffe  Mike@MichaelRatcliffe.com を元に改良しました。");
  Serial.println("フリーソフトウェアです。再配布・変更可能。");
  Serial.println("注意:測定後、次の測定まで5秒は時間を空けてください。プローブを損傷します。");

  lcd.begin(16, 2);              
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("START");
  delay(1000);
}

void loop()
{
  GetEC();
  PrintReadings();
//  Pumpmove();
//  LCDprint();
//  Serial.println("待機に入ります");
  delay(interval);
}

void GetEC() {
//  Serial.println("測定を開始します");
  sensors.requestTemperatures();
  Temperature = sensors.getTempCByIndex(0) + temp_offset; //温度計の補正を加えています

  //***************** 電圧降下測定 **************************//

  digitalWrite(ECPower, HIGH);
  raw = analogRead(ECPin);
  raw = analogRead(ECPin); // これはミスではありません
  digitalWrite(ECPower, LOW);

  //***************** ECに変換 **************************//
  Vdrop = (Vin * raw) / 1024.0;
  Rc = (Vdrop * R1) / (Vin - Vdrop);
  Rc = Rc - Ra; //acounting for Digital Pin Resitance
  EC = 1000000 / (Rc * K);

  //*************温度補償********************//
  EC25  =  EC / (1 + TemperatureCoef * (Temperature - 25.0));
  delay(5000);//プローブの損傷を防ぐため、5000より少ない値にしないでください。
}

void PrintReadings() {

  Serial.print(EC25);
  Serial.print(",");
  Serial.print(EC);
  Serial.print(",");
  Serial.print(Rc);
  Serial.print(",");
  Serial.print(Temperature);
  Serial.print(",");
  Serial.print(Vdrop);
  Serial.print("\n");

    //********** デバッグ用 ************
    /*
    Serial.print("Vdrop: ");
    Serial.println(Vdrop);
    Serial.print("Rc: ");
    Serial.println(Rc);
    Serial.print(EC);
    Serial.println(" uS/cm ");
    */
    //********** デバッグ用終了 *********

}
void LCDprint() {
  lcd.setCursor(0, 0);
  lcd.print("TEMP:");
  lcd.setCursor(6, 0);
  lcd.print(Temperature);
  lcd.setCursor(0, 1);
  lcd.print("EC:");
  lcd.setCursor(4, 1);
  lcd.print(EC25);
}

void  Pumpmove() {
  if (EC25 < 0) {
    Serial.println("ECの値が異常です。配線などを確認してください。液肥は投入しませんでした。");
  }
  else if (EC25 < setEC) {
    Serial.println("ECはsetECよりも低い値のため、投入します。");
    digitalWrite(Relay, HIGH);
    delay(pump_time);
    digitalWrite(Relay, LOW);
  }
  else if (EC25 >= setEC) {
    Serial.println("ECはsetEC以上のため、投入しませんでした。");
  }
  digitalWrite(Relay, LOW);
}

測定結果

水道水で測定した結果を示します。 左からRc(水中抵抗値)、水温補正済EC25(uS/cm 25℃としてのEC)、水温(℃)、水中降下電圧(V)、補正前EC(uS/cm)です。 5秒間隔で5点ほどサンプリングしました。
1385.27 259.11 24.74 2.9 257.82
1385.27 258.8 24.80 2.9 257.82
1385.27 259.11 24.74 2.9 257.82
1385.27 259.11 24.74 2.9 257.82
1385.27 259.11 24.74 2.9 257.82

市販のEC測定機器と比較すると、ECは268uS/cm、水温は21.6℃を示しておりました。 水温は少しずれている気がしますが、ECはそこそこ合っていていい感じでした。

f:id:amesyabody:20220130225006j:plain
市販のEC測定機器

結構書いたので、実際に測定系を実装する記事は別にしようかなと思います。 読んで頂き、有難うございました!