Arduino UNO と keyestudio TDS Meter で TDS を測定する方法
ここでは Arduino UNO (R3) と keyestudio の TDS Meter (V1.0) モジュールを利用して、水の TDS (総溶解固形分) を測定する方法を示します。
TDS とは?
TDS とは Total Dissolved Solids (総溶解固形分) の略です。TDS は 1 リットルの水に何ミリグラムの可溶性固形物が溶けているかを表す数字です。単位は mg/l または ppm になります。
TDS は水質の目安になります。米国環境保護庁 (EPA) の水道飲料水の規制ガイドラインでは、TDS は 500 ppm 以内とされています。
しかし、TDS 値が低ければ水がキレイで、高ければ水は汚い、とは単純には言えません。なぜなら、体に良いとされる物質が溶けていても TDS の値は高くなりますし、逆に TDS の値が低くても、水に溶けない有害な物質がある場合もあるからです。
このページでは TDS そのものについては深入りせず、 Arduino UNO と keyestudio TDS Meter を利用する方法について説明します。
keyestudio TDS Meter V1.0
keyestudio TDS Meter V1.0 は水の導電性物質の量で TDS を測定します。
耐水性のプローブも付属しています。
keyestudio の Wiki (https://wiki.keyestudio.com/KS0429_keyestudio_TDS_Meter_V1.0) によれば仕様は下記の通りです。
- 入力電圧: DC 3.3 - 5.5V
- 出力電圧: 0 - 2.3V
- 動作電流: 3 - 6mA
- TDS 測定範囲: 0 - 1000ppm
- TDS 測定精度: +/- 10% FS (25°C)
- モジュールインターフェイス: XH2.54-3P
- 電極インターフェイス: XH2.54-2P
Arduio での keyestudio TDS Meter の利用例
ここでは TDS Meter で読み取った値を LCD に表示してみましょう。
ちなみに、TDS の結果の値については、厳密に正しいかどうか調べる手段がなかったので、基本的には keyestudio で公開されているサンプルコードの利用例をそのまま使い、同様の値が表示できればよしとしました。
LCD は 1602A を利用しました。I2C アダプターを使い接続します。
1602A I2C アダプターの利用については「1602A I2C アダプターの利用」 をご覧ください。
Arduino UNO、 TDS Meter、 LCD 1602A (I2C) のフックアップはざっくり、こんな感じです。
純正 Arduino UNO R3 では V5 が 1 ピンしかなかったので、ここでは 5V の出力が複数ある Arduino UNO クローンを使用しました。
Arduino のスケッチは次の通りです。基本的には keyestudio のサンプルコードのままですが、いくつか好みで直しています。
#include <LiquidCrystal_I2C.h>
#define PIN_TDS_SENSOR A1
#define VREF (5.0)
#define SAMPLE_COUNT (35) // データのサンプル数 (奇数で設定)
#define TEMPERATURE (25.0f) // 25度を想定
LiquidCrystal_I2C lcd(0x27, 16, 2);
int analogBuffer[SAMPLE_COUNT];
int analogBufferIndex = 0;
unsigned long analogSampleTimepoint = 0UL;
unsigned long printTimepoint = 0UL;
String pad = String( " " );
void setup() {
// LCD の準備
lcd.init();
lcd.backlight();
lcd.clear();
// センサーピンの設定
pinMode( PIN_TDS_SENSOR, INPUT );
// サンプル取得と表示のタイミング
analogSampleTimepoint = millis();
printTimepoint - millis();
}
void loop() {
// データ収集 (40ms毎)
if( millis() - analogSampleTimepoint > 40UL ) {
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex++] = analogRead( PIN_TDS_SENSOR );
if( SAMPLE_COUNT == analogBufferIndex ) {
analogBufferIndex = 0;
}
}
// 表示 (1.5秒毎)
if( millis() - printTimepoint > 1500UL ) {
printTimepoint = millis();
// 収集したデータをソートして中央値を取得
qsort( analogBuffer, SAMPLE_COUNT, sizeof(int), comparator_ints );
int median = analogBuffer[ (SAMPLE_COUNT - 1)/2 ];
// TDS 値の計算
// (a) 電圧に変換 Arduino UNO は 0 から 1023 まで
float averageVoltage = median * (float) VREF / ( 1024.0 - 1.0 );
// (b) 温度補正
float compensationCoefficient = 1.0 + 0.02 * ( TEMPERATURE - 25.0 );
float compensationVolatge = averageVoltage / compensationCoefficient;
// (c) 電圧から TDS 値に変換
float tdsValue = ( 133.42 * compensationVolatge * compensationVolatge * compensationVolatge
- 255.86 * compensationVolatge * compensationVolatge
+ 857.39 * compensationVolatge) * 0.5;
// LCD への表示
String v = String( tdsValue, 0 );
String s = String( "TDS:" + v + "ppm" + pad );
lcd.setCursor(0,0);
lcd.print( s );
}
}
// qsort のための比較関数
int comparator_ints( const void *p, const void *q ) {
int x = *(const int*) p;
int y = *(const int*) q;
if( x < y ) {
return -1;
}
else if( x > y ) {
return 1;
}
return 0;
}
LCD に表示するという点を除き、元のコードから変更した主な点は次の通りです。
(1) analogRead で読み取った値を電圧に変換する箇所は、元のコードは 1024 で割っていました。
しかし、10ビットのアナログ・デジタルコンバータで得られる値は 0 から 1023 までの 1024 個の値ですので、1023 で割るべきと思い変更しています。
analogRead については Arduino で電圧を測る (アナログ入力を読取る) をご覧ください。
(2) 配列に格納した値の、中央値を取得する際のソートは自前で実施せずに、ライブラリ関数の qsort() を利用するよう変更しました。
そのため、 qsort で使うための比較関数 comparator_inits を実装しています。
(3) 単純化のためサンプル数を奇数個に限定し、計測値を格納している配列要素の中央の要素を取得しています。(元のコードは偶数個の時は中央付近の二つの値の平均値を取得していました)
温度による補正
温度の補正は次の式で実施できるようです。
上記コード (及び元のサンプルコード) では 25°C を想定していますが、温度センサーと併用することでより正しい値が得られることが期待できます。
TDS Meter の動作確認
常温のミネラルウォーターを測定してみると、次のように 60ppm と出ました。
水道水では 341ppm となりました。
これは私のロサンゼルスの自宅の水道水です。単純に何か汚いのかもしれませんが、基本的にアメリカでは、硬水のため、数値が高めにでるそうです。
これらの数値は、元のサンプルコードと比較して同様の値となりました。
以上、ここでは keyestudio TDS Meter V1.0 の使用例を紹介しました。 大変使いやすく、実用的なので、面白いですね。