冷水塔RaySui-kun作成/温湿度計、スケッチ

冷水塔の運転条件の一つを、湿球温度と水槽温の差5℃と一旦決めました。湿球温度の計算は冷水塔作成の前回で作れたので、これを使って水温との差dTを計算し、while関数でdTが5℃以下となるまで冷水塔のブロアと水中ポンプを起動するスケッチを作成します。

DHT22

まずは、乾球温度、相対湿度を測定するための温湿度計です。多分定番なんだと思いますがDHT22を選びました。似たような温湿度計にDHT11がありますが、こちらは相対湿度の指示が95%までしかありません。これでは湿球温度が計算できる範囲が狭まってしまうので、相対湿度100%まで指示出来るDHT22としました。

DHT22 Humidity and Temperature Sensor / OSOYOO

使用するのは、プルアップや接続ピンの整備されたOSOYOO製温湿度センサーモジュールです。それはそうと、OSOYOOってどういう意味なんでしょうね。カナダの会社なので日本語の”おはよう”とは関係ないとは思います。

DHT Sensor Libraryをインストールすると使えるようになるスケッチ例にはDHT_Unified_SensorとDHTtesterの二種類ありますが、違いはよく分かりませんでした。今回はDHTtesterをほぼそのまま使っています。ただ、冷水塔は5分に一回程度の温湿度測定として、その間はdeep sleepを入れたいので、全てsetup()内に書き込んでいます。

#include <DHT.h>
#include <DHT_U.h>
#include <Adafruit_Sensor.h>
#define DHT_pin D0
#define DHTTYPE DHT22
DHT dht(DHT_pin, DHTTYPE);

void setup() {
  unsigned long start_time = millis();
  dht.begin();
  Serial.begin(115200);

  pinMode(DHT_pin, INPUT);   
    
  delay(2000);

  float humi = dht.readHumidity();
  float Amb_Temp = dht.readTemperature();
  Serial.print("humidity = ");
  Serial.print(humi);
  Serial.println(" %");
  Serial.print("Amb Temp = ");
  Serial.print(Amb_Temp);
  Serial.println(" C");
}

void loop() {
}

測定の前に2秒の待機を入れているのは、OSOYOO社のTutorialに、DHT22のサンプリングレートは0.5Hzなので2秒の待機を入れる、と注意書きがある為です。

Learn Coding with Arduino IDE — DHT22 Humidity and Temperature Sensor/OSOYOO
https://osoyoo.com/2018/03/15/arduino-lesson-dht22-humidity-and-temperature-sensor/

0.5Hzなので2秒で1回ですね。他のサイトでもDHT22は測定に時間がかかるので、待機時間を入れないと思った時とは違う時の数字が出る、という注意も見かけました。

これで乾球温度と相対湿度を取り出すことが出来るようになりました。なお、上のスケッチを実行すると、setup()で一回測定してシリアルに一回結果を表示をしたら、その後何もしません。何かがずっとループしているシリアル表示に見慣れてくると、何もしないスケッチがなんだか清々しく感じます。

湿球温度Tと水槽温との差dTの計算

前回の冷水塔の記事(湿球温度計算)で誘導した相関式と、DHT22で測定した乾球温度、相対湿度を使って湿球温度を計算し、別途サーミスタで測定した水槽温との差をとるだけなので、ここはあまり悩まないですね。

#include <math.h>

#include <OneWire.h>  // For Water Temp.
#include <DallasTemperature.h>
#define ONE_WIRE_BUS D3
#define SENSOR_BIT 9  // resolution of temp meter

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

#include <DHT.h>  //ambient temp, humidity
#include <DHT_U.h>
#include <Adafruit_Sensor.h>
#define DHT_pin D0
#define DHTTYPE DHT22
DHT dht(DHT_pin, DHTTYPE);

float a;
float b;
float c;

void setup() {
  unsigned long start_time = millis();
  dht.begin();
  Serial.begin(115200);
  pinMode(DHT_pin, INPUT);       //D0 --DHT sensor
  pinMode(ONE_WIRE_BUS, INPUT);  //D3 --ONE WIRE BUS, DS18B20
                                                             
  sensors.setResolution(SENSOR_BIT);

  float Water_Temp;  //Water Temp
  sensors.requestTemperatures();

  Water_Temp = sensors.getTempCByIndex(0);
  Serial.print("Water Temp = ");
  Serial.print(Water_Temp);
  Serial.println(" C");

  delay(2000);

  float humi = dht.readHumidity();
  float Amb_Temp = dht.readTemperature();

  Serial.print("humidity = ");
  Serial.print(humi);
  Serial.println(" %");
  Serial.print("Amb Temp = ");
  Serial.print(Amb_Temp);
  Serial.println(" C");

a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;

Serial.print("a, b, c = ");
Serial.print(a);
Serial.print(" , ");
Serial.print(b);
Serial.print(" , ");
Serial.println(c);

float T = a * humi * humi + b * humi + c;

Serial.print("Wet bulb Temp = ");
Serial.print(T);
Serial.println(" C");

float dT = Water_Temp - T;

Serial.print("dT = ");
Serial.print(dT);
Serial.println(" C");
}

void loop() {
}

サーミスタ温度計DS18B20は1kΩのプルアップ抵抗が必要です。スケッチを試すときに毎回忘れます。上記のスケッチを実行すると、setupで一回だけ水温測定、二秒後に気温、相対湿度を測定、相関式に従って湿球温度Tを計算、引き算して水温との差dTを計算、係数a,b,cと合わせてシリアルに表示し、その後なにもしません。いやー、清々しい。

Deep Sleep

冷水塔は測定の間にDeep Sleepを入れて、5分に一回のdT測定にしようとしています。なので、Deep Sleepをsetup()の最後に入れています。正直、Deep Sleep自体は命令文を記入するだけで、これと言って悩むところはありませんでした。ただ、毎回5分Deep Sleepを入れていると、WiFi接続時間や測定時間分だけ後ろにずれていくことになります。5分ごとの起動とdT測定をするため、インターバルを設定し、そこからsetup()が最後まで来るまでの時間を差っ引いてsleep timeを設定することにします。

これは参考にしたサイトがあったのですが、ずいぶん前のことで、どちらのサイトを参考にしたかわからなくなってしまいました。ごめんなさい。似てる内容を見かけたら教えてもらえると幸いです。

sleep timeの計算は下のような感じです。setup()開始直後に開始時間(start_time)を記録、setup()の一番最後、sleep_timeの計算の中で現在時刻を測定し、setup()に要した時間と設定したインターバルとの差をsleep timeにする、というものです。

void setup() {
  unsigned long start_time = millis();

 /* 省略(WiFi.beginとか温湿度測定とか、計算とか諸々) */

  unsigned long sleep_time = Interval * 1000000 - (millis() - start_time) * 1000;  // interval - processing time

  esp_deep_sleep(sleep_time);

}

void loop() {
}
while構文

冷水塔のスケッチ作成で一番ハマったのが、この”while構文”です。いや、きっと基本的な文法なので、皆さんあまり躓かないのだとは思いますが、while内のループから抜けられなくなりました。

やろうとしたのは、冷水塔の運転期間の条件設定で、「水温と湿球温度の差dTが6℃以上になったら冷水塔運転開始、dTが5℃以上の間、又は水温23℃以上の間は運転継続(= dTが5℃以下もしくは水温23度以下になったら運転停止)」です。

while構文の部分は、冷水塔を動かす為に作成した関数CoolingTower()の中に入れてあります。温度条件が整って、関数CoolingTower()を呼び出し、実行する、まではよかったのですが、そこからwhile構文がうまく働いてくれませんでした。

void setup(){

/* 省略 */

if (dT >= 6.0){                /* dT ≧ 6.0℃でCoolingTower()呼び出し
  CoolingTower();
 }

  delay(15000);

}

void CoolingTower(){
    float humi = dht.readHumidity();
    float Amb_Temp = dht.readTemperature();

    float a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
    float b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
    float c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;

    float T = a * humi * humi + b * humi + c;

    sensors.requestTemperatures();
    float Water_Temp = sensors.getTempCByIndex(0);

    float dT = Water_Temp - T;

  while(dT >= 5){
    digitalWrite(D8, HIGH); //cooling tower motion check LED
    digitalWrite(P3, HIGH); //cooling tower pump start
    digitalWrite(B2, HIGH); //cooling tower blower start
    Serial.println("Cooling Tower has been started.");

    delay(5000);

    float humi = dht.readHumidity();
    float Amb_Temp = dht.readTemperature();

    float a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
    float b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
    float c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;

    float T = a * humi * humi + b * humi + c;

    sensors.requestTemperatures();
    float Water_Temp = sensors.getTempCByIndex(0);

    float dT = Water_Temp - T;

    Serial.print("dT = ");
    Serial.print(dT);
    Serial.println(" C");

    ambient.set(4, dT);
    ambient.set(5, P3);
    ambient.send();    //←ここまでは来るが、while内を無限ループ
  }

  digitalWrite(P3, LOW);
  digitalWrite(B2, LOW);
  digitalWrite(D8, LOW);
  Serial.println("Cooling Tower was stopped.");

  delay(1000);

  esp_deep_sleep(20000);
}
void loop() {
}

コンパイルは出来るので、文法が違っている訳では無さそうです。ただ、dTが5℃以下になっても、水温を23℃以下にしても、ループから抜けられません。水温23℃の条件を外しても、不等号の向きを反対にしても、状況は変わりませんでした。

while構文の条件判定で何故かfalseにならないので、諦めてbool関数に置き換える事にしました。

void CoolingTower(){
  bool CTjudge = true;
  while(CTjudge){
    digitalWrite(D8, HIGH); //cooling tower motion check LED
    digitalWrite(P3, HIGH); //cooling tower pump start
    digitalWrite(B2, HIGH); //cooling tower blower start
    Serial.println("Cooling Tower has been started.");

    delay(5000);

    float humi = dht.readHumidity();
    float Amb_Temp = dht.readTemperature();
    float a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
    float b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
    float c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;
    float T = a * humi * humi + b * humi + c;

    sensors.requestTemperatures();
    float Water_Temp = sensors.getTempCByIndex(0);

    float dT = Water_Temp - T;

    Serial.print("Water Temp = ");
    Serial.print(Water_Temp);
    Serial.println(" C");

    Serial.print("humidity = ");
    Serial.print(humi);
    Serial.println(" %");
    Serial.print("Amb Temp = ");
    Serial.print(Amb_Temp);
    Serial.println(" C");

    Serial.print("Wet bulb Temp = ");
    Serial.print(T);
    Serial.println(" C");

    Serial.print("dT = ");
    Serial.print(dT);
    Serial.println(" C");

    if(dT < 5){
      CTjudge = false;
    }

    Serial.println(CTjudge);
  }

  digitalWrite(P3, LOW);
  digitalWrite(B2, LOW);
  digitalWrite(D8, LOW);
  Serial.println("Cooling Tower was stopped.");

  delay(1000);

  esp_deep_sleep(20000000);

}

void loop() {
}

みたいな感じです。これならちゃんとwhile文の条件に対してfalseとすることが出来たので、ループから抜け出すことが出来るようになりました。bool CTjudgeがfalseになったか確認するのに、Serial.println(CTjudge);を入れているところに、苦悩ぶりが感じられますね。

そもそもなんでwhile(dT >= 5)が上手く機能しなかったのかは、謎のままです。調べてみると、whileの条件式に小数を使ってもいい、という説と、使ってはいけないという説があって、よくわかりませんでした。bool CTjudgeはif (dT < 5)でfalseに切り替わるようにしていますが、そもそもdTの型はfloatなので、if文の条件式に浮動小数点があることになって、それはそれでダメなはず。。。詳しい方教えてください。。。

ただ、目的は冷水塔を作ることなので、機能するようになればそれ以上の追及は後回しです。ここまでをすべて合わせ、WiFi接続/再接続とambientを追加して、とりあえずスケッチは下の形で完成としました。intervalとdeep sleepの時間は60秒と20秒で入っていますが、設置するときに再設定します。

#include <Wire.h>
#include <math.h>

#include <OneWire.h>  // For Water Temp.
#include <DallasTemperature.h>
#define ONE_WIRE_BUS D3
#define SENSOR_BIT 9  // resolution of temp meter

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

#include <DHT.h>  //ambient temp, humidity
#include <DHT_U.h>
#include <Adafruit_Sensor.h>
#define DHT_pin D0
#define DHTTYPE DHT22

float a;
float b;
float c;

#include <WiFi.h>  //wifi setting
const char SSID[] = "******";
const char PASSWORD[] = "************";

#include <Ambient.h>  //Ambient setting
unsigned int channelId = *****; //Channel name "Cooling Tower"
const char* writeKey = "*****************";

WiFiClient client;
Ambient ambient;
DHT dht(DHT_pin, DHTTYPE);

int Interval = 60; //seconds

const int P3 = D1; //cooling tower pump
const int B2 = D2; //cooling tower blower


void setup() {
  unsigned long start_time = millis();

  dht.begin();
  Serial.begin(115200);

  pinMode(DHT_pin, INPUT);       //D0 --DHT sensor, ambient temp/humidity
  pinMode(P3, OUTPUT);           //D1 --cooling tower pump
  pinMode(B2, OUTPUT);           //D2 --cooling tower blower
  pinMode(ONE_WIRE_BUS, INPUT);  //D3 --ONE WIRE BUS, DS18B20
                                 //D4 --vacant
                                 //D5 --vacant
                                 //D6 --vacant
                                 //D7 --vacant
  pinMode(D8, OUTPUT);           //D8 --Cooling Tower Motion Check LED
                                 //D9 --vacant/caution when you use as LED pin
  pinMode(D10, OUTPUT);          //D10 --Asleep Signal LED

  digitalWrite(D10, HIGH);                               
  sensors.setResolution(SENSOR_BIT);

  bool connecting = true;
  WiFi.begin(SSID, PASSWORD);
  while (connecting){
    Serial.print("WiFi connecting to the AP: ");
    Serial.println(SSID);
    unsigned long connect_start = millis();
    while (WiFi.status() != WL_CONNECTED && connect_start + 20000 > millis() ){
      Serial.print(".");
      delay(500);
    }
    if (WiFi.status() == WL_CONNECTED){
      connecting = false;
      delay(500);
    } else {
      Serial.println("retry");
      delay(500);
      esp_deep_sleep(500);
    }
  }

  Serial.println("connected.");
  Serial.print("IP adress:");
  Serial.println(WiFi.localIP());

  ambient.begin(channelId, writeKey, &client);


  float Water_Temp;  //Water Temp

  sensors.requestTemperatures();
  Water_Temp = sensors.getTempCByIndex(0);
  Serial.print("Water Temp = ");
  Serial.print(Water_Temp);
  Serial.println(" C");

    ambient.set(1, Water_Temp);

  delay(2000);

  float humi = dht.readHumidity();
  float Amb_Temp = dht.readTemperature();
  Serial.print("humidity = ");
  Serial.print(humi);
  Serial.println(" %");
  Serial.print("Amb Temp = ");
  Serial.print(Amb_Temp);
  Serial.println(" C");

    ambient.set(2, humi);
    ambient.set(3, Amb_Temp);


a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;

Serial.print("a, b, c = ");
Serial.print(a);
Serial.print(" , ");
Serial.print(b);
Serial.print(" , ");
Serial.println(c);

float T = a * humi * humi + b * humi + c;

Serial.print("Wet bulb Temp = ");
Serial.print(T);
Serial.println(" C");

ambient.set(4, T);

float dT = Water_Temp - T;

Serial.print("dT = ");
Serial.print(dT);
Serial.println(" C");

    ambient.set(5, dT);

    ambient.send();

if (dT >= 6.0 && Water_Temp >= 23){
  CoolingTower();
}

  delay(15000);

  digitalWrite(D10, LOW);
  unsigned long sleep_time = Interval * 1000000 - (millis() - start_time) * 1000 - 15000000; // interval - processing time - delay
  esp_deep_sleep(sleep_time);

}

void CoolingTower(){
  bool CTjudge = true;
  while(CTjudge){
    digitalWrite(D8, HIGH); //cooling tower motion check LED
    digitalWrite(P3, HIGH); //cooling tower pump start
    digitalWrite(B2, HIGH); //cooling tower blower start
    Serial.println("Cooling Tower has been started.");

    delay(5000);

    float humi = dht.readHumidity();
    float Amb_Temp = dht.readTemperature();
    float a = -7.8802E-7 * Amb_Temp * Amb_Temp + 4.3768E-6 * Amb_Temp - 1.0326E-4;
    float b = 9.881E-5 * Amb_Temp * Amb_Temp + 3.5766E-3 * Amb_Temp + 6.1947E-2;
    float c = -2.4411E-3 * Amb_Temp * Amb_Temp + 6.0908E-1 * Amb_Temp - 5.2169;
    float T = a * humi * humi + b * humi + c;

    sensors.requestTemperatures();
    float Water_Temp = sensors.getTempCByIndex(0);

    float dT = Water_Temp - T;

    Serial.print("Water Temp = ");
    Serial.print(Water_Temp);
    Serial.println(" C");

    ambient.set(1, Water_Temp);

    Serial.print("humidity = ");
    Serial.print(humi);
    Serial.println(" %");
    Serial.print("Amb Temp = ");
    Serial.print(Amb_Temp);
    Serial.println(" C");

    ambient.set(2, humi);
    ambient.set(3, Amb_Temp);

    Serial.print("Wet bulb Temp = ");
    Serial.print(T);
    Serial.println(" C");

    ambient.set(4, T);

    Serial.print("dT = ");
    Serial.print(dT);
    Serial.println(" C");

    ambient.set(5, dT);
    ambient.set(6, P3);

    ambient.send();

    if(dT < 5 || Water_Temp < 23){
      CTjudge = false;
    }

    Serial.println(CTjudge);
  }

  digitalWrite(P3, LOW);
  digitalWrite(B2, LOW);
  digitalWrite(D8, LOW);
  Serial.println("Cooling Tower was stopped.");

  delay(1000);

  esp_deep_sleep(20000000);

}

void loop() {
}

長くなったので、とりあえずここまで。次は基板作成かな。

コメントを残す

しろすけ技術研究所
主任研究員

こんにちは。市民農園で野菜作りをしているしろすけです。極小規模の栽培管理システム開発をいつかやってみたいと思っていました。2024年から育苗ケース給排気温調や、水耕栽培管理システムの試作を電子工作で始めました。想像以上に検討することがあったので、記録を残すことにします。バイク(SR400)と耕運機(FV200)の整備記録もついでに記録に残しておきます。


しろすけ技術研究所をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む