工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定

必要な部品と材料

必要な工具と機器

使用するアプリとオンラインサービス

プロジェクト概要

このプロジェクトについて

湿度測定には様々な方法がありますが、最も一般的なのは静電容量式センサです。しかし、高湿環境で連続使用すると精度が急速に低下します。冷却ミラー式湿度計(チルドミラーヒグロメーター)はこの問題がなく、特に高湿域で高精度です。市販品は数十万円しますが、原理はシンプルなので自作可能です。市販品ほどの0.1℃精度は出せませんが、ほとんどの用途で十分実用的です。本プロジェクトは概念実証(PoC)であり、量産レベルではありませんが、動作することを証明しています。

原理

ペルチェ素子(TEC)でミラー表面を冷却し、結露が現れる温度(露点)を検出します。光源(LEDまたはレーザー)と光センサ(OPT101)でミラー表面の反射光量を監視し、結露で反射光が減少した瞬間のミラー温度=露点とみなします。露点と周囲温度から相対湿度を算出します。

市販品との違い(簡易化ポイント)

組み立て手順

  1. ペルチェとヒートシンクの固定:両面を清掃し、熱伝導接着剤(なければ熱伝導グリス+端に瞬間接着剤少量)を均一に塗布、ヒートシンクを押し当て乾燥。
  2. ミラーの取り付け:同様にペルチェ冷却面とミラーを接着。熱伝導グリスを均一に、気泡なきよう注意。不均一だと結露パターンが偏る。
  3. ファン取り付け:ヒートシンクにファンを固定(グルーガン等)。十分な風量が必要。
  4. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定
  5. 結露パターンの確認:ファン→ペルチェの順で通電し、ミラー上で「同時に結露が現れる領域」を確認。長時間通電すると全面結露してわからなくなるので注意。写真撮影かマーキングしておく。
  6. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定
    自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定

    筆者の場合、熱伝導グリスの塗りムラで不均一な結露パターンになりました(上写真)。

  7. 温度センサ(Si7021)のミラー貼り付け:センサ基板に非導電性熱伝導グリスを大量に塗り、基板四隅にグルーガンで大きな接着点を作り、結露が同時に現れた位置に水平に強く押し付け固定。基板に結露したらグルーやスプレー絶縁で保護。
  8. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定
  9. ファン制御:IRF520 MOSFETモジュールでPWM制御。
  10. 光源と光センサ:OPT101は高感度・低ノイズ・扱いやすい。光源は低出力レーザーダイオードまたは指向性のあるLED。出力が強すぎる場合は直列抵抗で減光(PWMだとセンサにノイズが入るため)。銅線を捩って剛性を持たせ、両端をグルーで固定して位置決め(試作レベル)。本格運用なら3Dプリントホルダー兼遮光ケース推奨。
  11. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定
  12. ペルチェ駆動:BTS7960モータードライバでPWM駆動(理想は可変電流駆動だが入手性優先)。
  13. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定
  14. 動作確認・調整:スケッチ書き込み後、OPT101感度を半固定抵抗で調整(データシートFig.3参照)。デバッグ時はミラーに息を吹きかけたり物体をかざしたりして結露擬似。エアコンのオンオフで湿度変化を観測可能。
  15. 自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定

安全上の注意

現在のコードは冷却のみ対応ですが、ハードウェアはペルチェ極性反転で加熱も可能です。結露除去で応答速度向上や汚れ除去に有効ですが、ミラー側にヒートシンクがないため、暴走すると接着剤溶解や配線溶融・火災のリスクがあります。加熱機能を実装する場合は十分な安全策を講じてください。

精度について

Arduinoスケッチ(Chilled Mirror Hygrometer)

#include <math.h>
#include <avr/wdt.h> // Watchdog for safety
// Custom libraries
#include "Si7021.h"
#include <OneWire.h>
#include <DallasTemperature.h>
// Timer library: https://github.com/brunocalou/Timer
#include "timer.h"
#include "timerManager.h"

// Hardware pins
#define coolingPWM 6
#define heatingPWM 5
#define coolingEnable 13
#define heatingEnable 12
#define tecFan 7
#define opticalSensor 0 // Analog in
#define oneWireBus A3

// TEC states
#define COOLING 0
#define HEATING 1
#define OFF 2

// Timers
Timer timerMainLoop;
Timer timerTecCooling;
Timer timerSampleNoise;

// Sensors
Si7021 si7021;
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);

float humidity = 0;
float ambientTemp = 0;
float opticalDewpoint = 0;
float mirrorTemp = 30;
float optical = 30;
float dewPoint = 15; // initial < mirrorTemp
float relativeHumidity = 30;
int tecState = OFF;
bool cooling = false;
int intervalTecCooling = 200; // ms
float opticalThreshold = 0.5f; // condensation detection threshold
int pwmIncrement = 1;
int startPwm = 100;
int maxPwm = 255;
int intervalMainLoop = 200;
int tecPwm = 0;
int noiseSampleIndex = 0;
int noiseSampleAmount = 10;
float noiseSampleHighest = 0;
float noiseSampleLowest = 10000;
bool noiseSampling = false;

// August-Roche-Magnus approximation for RH calculation
float calculateHumidity(float TD, float T) {
  if (TD > T) TD = T;
  float rh = 100 * (exp((17.625 * TD) / (243.04 + TD)) / exp((17.625 * T) / (243.04 + T)));
  return rh;
}

// TEC control via BTS7960
void SetTEC(int state, int amount) {
  tecState = state;
  // Note: both enable pins need HIGH for BTS7960
  switch (state) {
    case COOLING:
      digitalWrite(heatingEnable, HIGH); analogWrite(heatingPWM, 0);
      digitalWrite(coolingEnable, HIGH); analogWrite(coolingPWM, amount);
      break;
    case HEATING:
      digitalWrite(coolingEnable, HIGH); analogWrite(coolingPWM, 0);
      digitalWrite(heatingEnable, HIGH); analogWrite(heatingPWM, amount);
      break;
    case OFF:
    default:
      digitalWrite(coolingEnable, LOW); analogWrite(coolingPWM, 0);
      digitalWrite(heatingEnable, LOW); analogWrite(heatingPWM, 0);
  }
}

void setup() {
  wdt_enable(WDTO_2S); // Safety watchdog
  Serial.begin(9600);
  pinMode(coolingPWM, OUTPUT);
  pinMode(heatingPWM, OUTPUT);
  pinMode(coolingEnable, OUTPUT);
  pinMode(heatingEnable, OUTPUT);
  pinMode(tecFan, OUTPUT);
  pinMode(opticalSensor, INPUT);

  // Timers
  timerMainLoop.setInterval(intervalMainLoop);
  timerMainLoop.setCallback(mainLoop);
  timerMainLoop.start();
  timerTecCooling.setInterval(intervalTecCooling);
  timerTecCooling.setCallback(tecCoolingCallback);
  timerSampleNoise.setInterval(intervalTecCooling);
  timerSampleNoise.setCallback(sampleNoiseCallback);

  si7021.begin();
  uint64_t serialNumber = si7021.getSerialNumber();
  sensors.begin();
  startNoiseSampling();
}

float getOptical() {
  int opt = analogRead(opticalSensor);
  return (float)opt / 30.0f;
}

void tecCoolingCallback() {
  digitalWrite(tecFan, HIGH);
  tecPwm += pwmIncrement;
  if (tecPwm > maxPwm) tecPwm = maxPwm;
  SetTEC(COOLING, tecPwm);
  // Condensation detected?
  if (optical <= (noiseSampleLowest - opticalThreshold)) {
    dewPoint = mirrorTemp;
    opticalDewpoint = optical;
    stopTec();
  }
}

void startNoiseSampling() {
  noiseSampling = true;
  noiseSampleHighest = 0;
  noiseSampleLowest = 10000;
  timerSampleNoise.start();
}

void sampleNoiseReset() {
  timerSampleNoise.stop();
  noiseSampleIndex = 0;
  noiseSampling = false;
}

void sampleNoiseCallback() {
  if (noiseSampleIndex > noiseSampleAmount) {
    sampleNoiseReset();
    startTecCooling();
  } else {
    if (optical > noiseSampleHighest) noiseSampleHighest = optical;
    if (optical < noiseSampleLowest) noiseSampleLowest = optical;
  }
  noiseSampleIndex++;
}

void startTecCooling() {
  cooling = true;
  digitalWrite(tecFan, HIGH);
  tecPwm = startPwm;
  timerTecCooling.start();
}

void stopTec() {
  cooling = false;
  digitalWrite(tecFan, LOW);
  timerTecCooling.stop();
  SetTEC(OFF, 0);
}

void mainLoop() {
  // Ambient temp (DS18B20)
  sensors.setResolution(10);
  sensors.requestTemperatures();
  ambientTemp = sensors.getTempCByIndex(0);
  // Mirror temp (Si7021)
  mirrorTemp = si7021.measureTemperature();
  // Optical reading
  optical = getOptical();
  relativeHumidity = calculateHumidity(dewPoint, ambientTemp);

  // Serial Plotter output
  Serial.print(mirrorTemp, 2); Serial.print(" ");
  Serial.print(optical, 2); Serial.print(" ");
  Serial.println(dewPoint, 2);

  // Restart cooling when condensation clears
  if (!cooling && !noiseSampling && (optical >= noiseSampleLowest)) {
    startNoiseSampling();
  }
}

void loop() {
  wdt_reset(); // Watchdog feed
  TimerManager::instance().update();
}

回路図

自作冷却ミラー式湿度計(チルドミラーヒグロメーター)──Arduinoで高精度な温湿度測定

製造プロセス

  1. 現代ミラーの科学と技術:古代から最新コーティングまで
  2. Bluetooth操作のArduinoスパイボットを自作する
  3. FlickMote:ジェスチャー操作のIRリモコンでスマートホームを制御
  4. 自作Arduino TV-B-Gone:全テレビ対応の万能リモコン
  5. DIY万華鏡インフィニティミラー - Arduino 101で作る美しいLEDライトディスプレイ
  6. 12メートル先から見える大型LEDマスタークロック(アラーム機能付き)を自作しよう
  7. ArduinoとBluetoothで作るスマート紛失防止タグ「Find Me」
  8. Arduinoプロジェクトのための最適化電源ソリューション
  9. Arduino三目並べ:MAX7219 LEDマトリクスと段ボールケースで自作
  10. スマートArduino四足歩行ロボットの製作:ステップバイステップガイド
  11. ゲーム用カスタムArduinoジョイスティックハンドルの製作