こんにちは、ENGかぴです。
Arduino環境ではアナログ電圧をAD変換する標準ライブラリが実装されています。においセンサーであるTGS8100(フィガロ技研)を使ってArduinoのアナログ電圧値から検知可能なガス(エタノールや水素)などを検出することができます。
においセンサモジュールキットAE-TGS8100(秋月電子)を使用しています。AE-TGS8100モジュールの使用方法とアナログ電圧を抵抗に換算してエタノールと水素を検出します。
エタノールは除菌シートを使用します。水素は私が毎日使用している手軽に水素水が生成できる水素水生成器を使用しています。
Arduino UNOの拡張基板であるSD CARD SHIELDを使ってSDカードにセンサ抵抗のログを保存します。SD CARD SHIELDはアイキャッチ画像のようにArduino UNOに差し込むだけで使用することができます。SDカードにファイルを保存する方法を下記記事にまとめています。
Arduino UNO(以下Arduinoとします。)を対象とします。Arduinoのライブラリを使用して動作確認したことをまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
においセンサーの情報を取得する

TGS8100はフィガロ技研のにおいセンサーです。酸化物半導体式の検知の原理によって空気の汚れ(水素やアルコール)を検知します。
ヒータ電圧と回路電圧の2つの印加電圧が必要です。ヒータ電圧のDC1.8Vが印加されると検出対象のガスを検出するのに最適な動作温度に感ガス素子が加熱されます。
回路電圧は、センサと直列に接続される負荷抵抗(RL)の電圧(Vout)を測定するために印加されます。負荷抵抗は対象ガスの検知濃度域における分解能が最適になるように抵抗値(10kΩ以上)を選定します。AE-TGS8100モジュールは10kΩが実装されています。
回路電圧はArduinoからパルス電圧で印加します。パルスの印加時間は2msでありパルスの印加間隔は1sec以上必要です。1秒周期のパルスに対してデューティー比が2:1000になるようなパルスを生成する必要があります。
AE-TGS8100はヒータ電圧の電源やDC3.3V~5.0VのArduinoの電源に対応する電源が実装されているため便利です。(以下ではセンサー単品の説明はTGS8100とし、AE-TGS8100を指す場合はセンサモジュールとします。)
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
センサー情報取得の例
void TimerCnt(void){
if( sencnt == 0)
{
digitalWrite(A0, HIGH);
}
else if( sencnt == 1 )
{
sensor.buf[sensor.wp] = analogRead(A1);
if( ++sensor.wp >= AI_MAX )
{
sensor.wp = 0;
sensor.sdflg = true;
}
}
else if( sencnt == 2 )
{
digitalWrite(A0, LOW);
}
if( ++sencnt >= TIM_SEN_FREQ )
{
sencnt = 0;
}
}
TimerCnt()関数はMsTimer2ライブラリの割り込みで遷移する自作関数です。ライブラリで1ms毎に割り込みに遷移するようにします。MsTimer2ライブラリは標準ライブラリではないので追加する必要があります。
パルス生成用の変数としてsencntを準備します。sencnt は割り込み毎にカウントを更新し処理を分岐させるのに使用します。
sencntが0の時はパルスを出力するためdigitalWrite()関数でパルス出力ピン(A0)をHIGHにします。次の割り込み発生時はsencntが1に更新されているので7行目の処理を行います。analogRead()関数の引数にアナログピンを指定してセンサの出力電圧(デジット値)を取得します。戻り値にAD変換値がセットされるので変数に格納します。
1秒毎に測定値が取得していますが、アナログ入力がノイズなどの外部要因による影響を受けて振れることがあるため移動平均を取っています。例ではAI_MAX 回(10回 11行~15行目)データを取得してからセンサ抵抗値に換算する処理に移るようにしています。
出力電圧を取得した後の割り込みではsencntが2に更新されているので17行目の処理を行います。digitalWrite()関数でパルス出力ピン(A0)をLOWにします。
22行~25行目は割り込みに遷移した回数の更新を行っています。sencntが1000以上になった時1秒経過したことになるのでカウントをクリアします。
この処理を繰り返すことで1秒周期で2ms間HIGHとなるパルスを生成することができます。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
動作検証(エージング)
TGS8100は初めて使用する場合や長く通電していなかった場合、周囲の空気の状況に関わらず出力電圧が低下します。数分間電源を入れたままにして周囲の空気環境に対してセンサの出力電圧を安定させる(エージング)必要があります。
TECHNICAL INFORMATION FOR TGS8100を確認すると標準回路条件下で1時間以上予熱が必要とあるため、室内の窓際の雰囲気で90分間程度のエージングを行いました。シリアルモニターで抵抗換算した値を確認しました。

エージングの開始時は10kΩ程度の値でしたが数分しないうちに20kΩ程度になりました。20kΩ以降は緩やかな上昇となりました。SDカードにログとして保存しているエージングのでデータを確認します。

ログはテキスト形式で保存しているためファイル名:TGS8100.TXTの拡張子をcsvに変更しCSVファイルとしてエクセルで開きグラフ化しました。
グラフを確認するとエージング開始時と300s経過時当たりで抵抗値に振れていることが分かりました。これは室内の窓際に配置していましたが空調の風やドアの開閉によって空気の流れができてしまったためだと推測しています。
300s付近の最大値と400s付近の抵抗の値が31.5kΩで近似しているためこれを基準の雰囲気として採用します。
PR:RUNTEQ(ランテック )- マイベスト3年連続1位を獲得した実績を持つWebエンジニア養成プログラミングスクール
出力電圧を抵抗値に換算する

センサ抵抗は製品情報に換算式の記載があります。この式は分圧の法則からVout(VRL)の式を作りRsの式にすると得られるものです。
VRLはArduinoのアナログ入力で取得した電圧値、Vcは回路電圧のDC3.0V、RLは10kΩです。Arduinoから取得したアナログ値を電圧に換算すると10ビットのAD変換なので
$$V_{RL} = \frac{A1}{1024}×5V$$
になります。A1はデジット値、5VはArduinoの電源電圧です。Arduinoの電源電圧は厳密にいうと電源ラインに逆流防止のダイオードが実装されているため5Vよりも低い4.7V程度になります。
そのためデジット値から5Vで換算すると電圧値が高めになってしまいますが、基準の雰囲気に対して検出抵抗を任意で決めるためとくに問題としません。
for( i=0; i<AI_MAX; i++ )
{ //出力電圧の合計
ave += sensor.buf[i];
}
sensor.ana = ave / AI_MAX; //平均値
sensor.sen_f = 6144.0 / sensor.ana - 10;
Serial.println(sensor.sen_f, 1);
出力電圧の取得は1秒毎に行いますが、センサ抵抗値の換算は1出力電圧を移動平均化した値を使用します。10回分の出力電圧の合計を算出した値を10で除算して平均値を算出します。平均値をセンサ抵抗の換算式によって得られる式(7行目)から抵抗値に換算します。
PR:(即戦力のスキルを身に着ける:DMM WEBCAMP 学習コース(はじめてのプログラミングコース))
ガス特性から検出抵抗を決定する

ガス特性によると清浄大気中(基準の雰囲気)でのセンサ抵抗値に対するガス中のセンサ抵抗値の比によって検出するガス濃度が決まります。
本記事で動作確認する水素とエタノールを10ppm程度検出したと判断する場合のセンサ抵抗の閾値を求めます。ガス特性から10ppmとなる比を確認すると約0.3になります。
基準の雰囲気でのセンサ抵抗値を31.5kΩにしているので比が0.3になるセンサ抵抗値は9.45kΩになりますが、誤差等を考慮して10kΩを検出の閾値とします。
#define SEN_JUDGE float(10.0)
if( sensor.sen_f < SEN_JUDGE)
{
digitalWrite(PIN_DO, HIGH);
}
else
{
digitalWrite(PIN_DO, LOW);
}
センサ抵抗値が検出の閾値の10.0kΩを下回るとHIGHを出力してLEDを点灯させます。ガス濃度が低くなって10.0kΩ以上になるとLEDを消灯します。
動作確認

Arduinoの拡張ボードを使用しているためSDカードに使用するDOやSPIの専用ピン以外をセンサモジュールに使用します。A0をパルス出力に使用し、A1を出力電圧の取得に使用します。
電源を入れるとSDカードが存在することを確認し、存在が確認できればセンサ抵抗の測定を行います。電源を入れて間もなくはセンサ抵抗が低くなるため5分間はガスの検出の判定をしないようにしています。
水素が検出できるかを確認します。水素水生成器の蓋を開けた状態にしてペットボトルの底の部分をかぶせて水素水発生器から水素が発生しているかを確認します。

水素水発生器から漏れた水素をペットボトルに貯めた状態でセンサモジュールを覆います。覆いかぶせるとセンサ抵抗が低くなり10kΩを下回るとLEDが点灯して水素に反応したことが分かりました。シリアルモニタを確認するとセンサ抵抗が低くなる様子が分かります。
次にエタノールを配合している除菌シートを近づけて動作確認を行いました。

除菌シートを取り出してセンサモジュールに近づけるとセンサ抵抗が低くなりLEDが点灯してエタノールに反応したことが分かりました。シリアルモニタを確認するとセンサ抵抗が低くなっている様子が分かります。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
関連リンク
Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方
ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方
最後まで、読んでいただきありがとうございました。
いつも常用している水素水発生器から水素が検出できてホッとしました。これからも健康のため水素水を適度に飲んでいこうと思うばかりです。