chakokuのブログ(rev4)

テック・コミック・ごくまれにチャリ

Sensirion のCO2センサ(SCD30)を接続

やりたいこと:SensirionのCO2センサ(SCD30)を購入した(マルツオンラインで)。SCD30をESP32に接続してCO2を計測したい。
結果:いつものようにハマりポイントにはまったが、最終的にはCO2が計測できた

SCD30は結構高いセンサですが、高精度らしいです。ここ一か月ぐらいMH-Z19Cで部屋のCO2を計測していますが、計測誤差が蓄積されるようで*1、SCD30とどの程度差が出るのかを確認したいと思っています。あとは、、BME280の温湿度と、SCD30の温湿度でどのぐらい差が出るかを確認する予定。

センサ類はキャリブレーションがキモと理解しているのですが、どうやって補正するのか仕組みがよくわからず、理解のためにマニュアルを和訳
1.4.6 (De-)Activate Automatic Self-Calibration (ASC)

  • 下記のコマンドにより、継続的な自動セルフキャリブレーションを有効化できます
  • 初めてASCを有効化した時、アルゴリズムがASC用の初期パラメーターセットを検知できるまで最低7日間かかります
  • 毎日少なくとも 1 時間、センサーを新鮮な空気にさらす必要があります。その間センサーの電源を切ることができません。もし電源を切った場合、キャリブレーションパラメータの検知する処理が中断されてしまい、最初からやり直す必要があります。
  • 正常に計算されたパラメータは SCD30 の不揮発性メモリに保存されます。センサを再起動した後も、最後に検知されたASC のパラメータが再利用されます。
  • この機能のステータスに関係なく、セルフキャリブレーションにおいて最後に検出されたセルフキャリブレーションパラメータが有効値として使用されることに注意してください。(??)
  • ASCより新しいパラメータセットが検知されると、外部再キャリブレーション (第 0 章を参照) で設定された値に対して上書きされます。その逆も同様です(後に外部再キャリブレーションが行われると、セルフキャリブレーション(ASC?)による値に対して上書きされる)。
  • この機能(ASC?)はデフォルトでオフになっています。
  • SCD30 が適切に機能するためには、SCD30を定期的に新鮮な空気にさらす必要があります。センサーを毎日 1 時間新鮮な空気をにさらすことで最適な作業条件が整い、ASCが常に再校正可能になります。
  • ASCは連続測定モードでのみ機能します。
  • ASCの状態は不揮発性メモリに保存されます。
  • ASC が有効になっているときにセンサーの電源がオフになると、SCD30 はコマンドを送信せずに再電源投入後に自動セルフキャリブレーションを続行します。

Set Forced Recalibration value (FRC)

  • 強制再校正 (FRC) は、SCD30 が置かれている環境のCO2濃度の計測値が利用可能な場合に、センサーのドリフトを補正するために使用されます。
  • 最良の結果を得るには、FRCコマンドを適用して基準値を送信する前に、安定した環境にセンサーを設置し、少なくとも2 分間、2秒の測定レート連続モードを実行する必要があります。
  • 本章で説明する方法(FRC)でCO2 濃度を設定すると、ASCによる校正に対して上書きされます (1.4.6 章を参照)、その逆も同様です(FRCで設定後、ASCを実行するとASCの結果で上書きされる)。
  • 基準となるCO2濃度は、400 ppm ≦ cref(CO2) ≦ 2000 ppm の範囲内である必要があります。
  • センサーの電源再投入後も持続される CO2 キャリブレーション曲線に対して、FRC方式は恒久的な更新がなされます(??)。
  • 最後に使用された基準値は揮発性メモリに保持され、以下に示すコマンド シーケンスで読み取ることができます。
  • センサーの電源再投入後にコマンドを実行すると、標準参照値である400ppmを返します。

自分の理解まとめ

  • キャリブレーションには自動(ASC)と強制(FRC)がある
  • ASCでは定期的に新鮮な空気(CO2が400ppm)にセンサを置くことで、自動的に400ppmに補正される。だから、新鮮な空気に触れさせる必要ががある(一日1回、1H)
  • FRCでは現在のCO2値が分かっている場合、センサにCO2濃度を伝えることで、センサが補正される

I2CでESP32とSCD30は接続できて、疎通は正常と思えるのだが、SCD30のセンサデータがReadyにならない。どうしてだろうか。。

>>> sensor_get_data_ready_status(i2c)
sensor_get_ready_status
write: c2 02 02
stat:03
value: 00 00 81
sensor data is not ready

■追記
なぜSensor がReadyにならないのかいろいろ調べたが分からず、自力でどうにかする気力がなくなって、先人のドライバとサンプルコードをつかってみることにした。例えば、、以下のドライバがあるのでこれを使わせていただく。
GitHub - agners/micropython-scd30: MicroPython I2C driver for SCD30 CO2 sensor module

I2CバスでSCD30は検出されたので、以下のループで計測値を出力させようとしたが、status_readyの判断が成立せずずっと待ちになってしまう。だから、、自分のプログラムの問題ではなくて、デバイス内で何か強固に動きたくない状態になっているか、変なモードに入れてしまっているか。。

=== while True:
===     while scd30.get_status_ready() != 1:
===         time.sleep_ms(200)
===     scd30.read_measurement()
===
===
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
KeyboardInterrupt:
>>>

購入後、センサのパラメータを変えなかったら、電源を投入した時点でLEDが点滅して計測を始めるのでは??と思えるのだが、どうやってもLEDが点滅しない。うーん。。困ったものだ。。

今後の取り組み
0. マニュアルをプリントアウトして全部読む
1. Python版のドライバがあるのでそれを使って制御してみる。
2. それでもだめなら、、サポート対応も可能なようなので、、「LEDが点滅せず、Readyにならない」旨質問、
3. 回答がない場合はもう一つ同じのを買うか、、
4. 後継機のSCD40を買う。

マニュアルを読み直して、修正すべき点を2点見つけて改修した。結果、以下のようにデータを取れるようになった。

>>> sensor_read_measurement(i2c)
sensor_read_measurement
write: c2 03 00
stat:03
value: 44 0a 50 08 8b 26 41 fc 03 c7 36 e6 42 78 90 e4 e1 84

今回のハマりポイント(もちろん自分が悪いのだが)

  1. I2Cの転送レートについて、マニュアルでは推奨50KHz以下と書かれているのに対して、桁を間違って400KHzで設定していた。まちがうのにも程があるが。。
  2. Get data ready statusコマンドにおいて、コマンドを送信してから、ステータスを受信操作するまでの間、3ms以上待つべしと書かれているが、待ち無しですぐに受信操作していた。
  3. 計測用のLEDはチカチカ光ると思っていて、光らないので計測自体行われていないと思っていた(目で見て分からないもの?)*2

値は取れたので、それが妥当な値であるかどうかを確認する。CO2については400ppm前後になっているはずなのだが。

MicroPythonのunpack関数を使うことで4byteの配列からfloat型に変換できる。CO2/温度/湿度を変換してみた。

>>> get_co2_tmp_hum(i2c)
sensor_read_measurement
write: c2 03 00
stat:03
value: 43 f8 1e cb 3d b8 41 ff 50 47 c2 83 42 66 cc ee 21 2d
None
43 f8 1e cb 3d b8 41 ff 50 47 c2 83 42 66 cc ee 21 2d
(497.5878, 31.91004, 57.73255)

上記より、CO2:497ppm、温度:31.9℃、湿度:57.7%と報告されている
BME280 + MH-Z19Cの結果は以下
CO2: 400ppm、温度:31.04℃、湿度:60.33% 気圧:983.15hPa
温湿度について多少の誤差はあるが、大枠は合っている。 CO2については20%の誤差がある。これは少し大きいと思う。センサーのキャリブレーションを正しく行っていないためかも。長期的に変化の傾向を比べるべきかもしれない。窓開けっぱなしで外気がどんどん入ってる状態なので、理想値は410~420ppmなのではないかと、。と、考えると、SCD30の計測値(497ppm)が高すぎるのではないかと思える。強制再校正(FRC)の設定値がまずいのかもしれない。

■CO2計測値が高い件
外気による換気中なのに、497ppmは高いと判断して、FRCを実行した。

415ppmを引数としてFRCを実行する。

>>> sensor_set_FRC(i2c,415)
sensor_set_FRC (415)
write: c2 52 04 01 9f 62

>>> sensor_get_FRC(i2c)
sensor_get_FRC
write: c2 52 04
value: 01 9f 62
CO2 concentration: 415 ppm

この状態で再度計測。
FRCで強制校正したせいか、CO2の計測値は414ppmになった。

>>> get_co2_tmp_hum(i2c)
sensor_read_measurement
write: c2 03 00
value: 43 cf 4c 43 f1 96 41 f9 f6 d1 7b a3 42 6a b1 18 a3 77
(414.5308, 31.22729, 58.52406)

■電源投入後に安定して起動できない件
SCD30でCO2を計測できるようになったが、電源投入後はすぐには動作せず、何か特定のシーケンスでコマンドを実行しないといけないようであった。どのコマンドシーケンスを使うと確実に動作できるのかを確認する。→不揮発性メモリに記録されたパラメータがSCD30にとって都合がいいのか、電源を投入すると勝手に計測が始まるようになった。だから、、異常状態からの復帰方法がテストできない。

仕様書には起動シーケンスが書かれていないのでどのコマンドをどういう順番で投入したら確実に動作するのかちょっと分からない。経験的に動作がおかしい場合は以下で正常化するような感じ(異常動作を再現できていないので自分用のメモレベル)

  1. Soft reset (0xD304)
  2. Stop continuous measurement (0x0104)
  3. Set measurement interval (0x4600)
  4. Trigger continuous measurement (0x0010)

Sensirion社からサンプルコードが出ているのでそれをよく読むと分かるかもしれない。

■ご参考URL
Sensirionのドキュメント類
SCD30 - CO₂ accuracy of ±(30 ppm + 3% MV) @400-10000 ppm
https://sensirion.com/media/documents/4EAF6AF8/61652C3C/Sensirion_CO2_Sensors_SCD30_Datasheet.pdf
https://sensirion.com/media/documents/D7CEEF4A/6165372F/Sensirion_CO2_Sensors_SCD30_Interface_Description.pdf
GitHub - Sensirion/python-i2c-scd30: Python I2C driver for Sensirion SCD30 sensor

情報が整理されていて助かるAdafruitのサイト(SCD30)
Overview | Adafruit SCD-30 - NDIR CO2 Temperature and Humidity Sensor | Adafruit Learning System

CRCメモ
CRC の計算方法 : kei@sodan
GitHub - agners/micropython-scd30: MicroPython I2C driver for SCD30 CO2 sensor module
CO2 meter on your mobile with ESP32 and Sensirion SCD30 sensor [BASIC VERSION] - eMariete
Grove 湿度、温度とCO2センサー(SCD30) - Seeedウィキ(日本語版)

■追記
やはりSCD30の起動方法をミスするとCO2の計測がReadyにならない。補足すると、電源Onの後、前回不揮発性メモリに記録した状態を維持したまま何も変更せずに自動計測に入るのは問題ないだろうが、電源On以降で何か下手に設定するとCO2計測がReadyにならない。この場合、自分がやった復帰方法は以下(無駄な操作も多そうで何が必須なのか不明)

  1. 計測周期を2秒に設定
  2. soft reset
  3. 自動計測stop
  4. 自動計測start
  5. この操作だけではCO2計測が正常化せず
  6. 電源Off/On
  7. CO2計測正常化(2秒周期でLED点滅)

ひょっとして、、計測周期を変える場合は、自動計測をStopする必要がある??

■CO2濃度ご参考
屋外のCO2濃度は一般的に410ppmらしいです(細かい話をすると、毎年計測されていて気象庁からデータが公開されている。それによると毎年少しずつ上昇しているようだ)。室内のCO2濃度は1000ppmが基準値で、1000ppmを超えると換気が望ましい。24時間換気が導入されている家は500ppm程度に抑えられるらしいです。
気象庁 | 二酸化炭素

*1:キャリブレーションを正しく設定してないせいか?

*2:電源を5Vにして、周期を2秒で運用するとLEDが点滅している。安定して動作するための必須条件が何なのか、まだ確認できず