Grove VOC and eCO2 Gas SensorをRaspberry Piで使ってみた

GroveはSeeedが開発したハードウェアのコネクターのシステムです。

最近は多くのセンサーがGroveに対応するようになってGroveで大抵のセンサー測定は事足ります。

その昔、秋葉原で初めてGroveのきっとを見たときは「こんなの買ってもやれること限られるだろ?」と思って買おうと思わなかったんです。(当時はRaspberry PiでGroveが使えることを知りませんでした)

しかし、とあるハッカソンでGroveの心拍センサーを使ったときに「なんか使いやすいなこれ」と思ったんです。

心拍センサーなんてあんまり他で見たことありませんし、なんか扱いが面倒くさそうでしたけどGroveで使えるように設計されていてよくできてるなと感心しました。

それ以来、いろんなGroveのモジュールを買い集めては試すようになり、すっかりGroveの虜になりました。

特にRaspberry Piで使うときにはピンの番号をいちいち調べるのが面倒なのでGrove Base Hat を使ってGroveと連携すればRaspberry PiでGroveモジュールを使うのが簡単になります。

前置きが長くなりましたが、今じゃ気になったGroveモジュールを見つけては買っているとあんまり使う機会がなくそのまま積みモジュールが増えていくわけですw。

で、今回はその積みモジュールの一つである「Grove VOC and eCO2 Gas Sensor」を触ってみたいと思います。

ドキュメント

Seeedから出している大抵のGroveモジュールにはドキュメントが存在します。

もちろん、このモジュールにもドキュメントがあります。

それがこちら↓

wiki.seeedstudio.com

きほんはこれをベースにすすめていきます。

インストール

grove.py

今回は「Grove Base HAT for Raspberry Pi」を使うので、以下のコマンドでgrove.pyをインストールします。

curl -sL https://github.com/Seeed-Studio/grove.py/raw/master/install.sh | sudo bash -s -

ライブラリのインストール

このセンサーにはSGP-30が使われています。そしてこのセンサーを使うときには別途ライブラリーをインストールする必要があります。 ライブラリは以下のコマンドでライブラリをクローンします。

git clone https://github.com/Seeed-Studio/Seeed_Python_SGP30.git
cd Seeed_Python_SGP30
sudo python3 setup.py install

サンプルコードの実行

サンプルコードは公式ドキュメントにある以下のコードを動かしてします。

import seeed_sgp30
from grove.i2c import Bus
 
sgp30 = seeed_sgp30.grove_sgp30(Bus())
while True:
  data = sgp30.read_measurements()
  co2_eq_ppm, tvoc_ppb = data.data
  print("\r  tVOC = {} ppb CO2eq = {}  ".format(
                               tvoc_ppb, co2_eq_ppm))

実行すると以下のエラーが出ました。

ImportError: cannot import name 'SMBusWrapper' from 'smbus2' (/usr/local/lib/python3.7/dist-packages/smbus2/__init__.py)

ドキュメント通りに実行してこんなことになることあるのか?と思うのですが、オープンソースってたまにそういうことありますねw。

で、さすがにこのまま終わるわけにはいかないので、なんとかすることにしました。

なんとかしてみた

このセンサーにはI2Cが使われており、seeed_sgp30の大元のライブラリであるsgp30にはsmbus2が使用されています。

そのときにSMBusWrapperを呼び出そうとしているようです。

とりあえずsmbus2でSMBusWrapperがメソッドとしてあるのか調べてみましたが、それらしき記述は見当たりませんでした。 (それはエラーになるな…)

github.com

そして、sgp30のライブラリのソースを確認してSMBusWrapperがどこで使われるのか確認したら以下のmain関数で使われていました。

def main():
    with SMBusWrapper(1) as bus:
        sgp=Sgp30(bus,baseline_filename=BASELINE_FILENAME+".TESTING")
        print("resetting all i2c devices")
        sgp.i2c_geral_call()
        print(sgp.read_features())
        print(sgp.read_serial())
        sgp.init_sgp()
        print(sgp.read_measurements())
    bus.close()

1箇所だけしか使われていなかったのでこれは修正はそこまで大変ではありませんね。 でもどう修正すればいいのか悩みつつもう一回smbus2のレポジトリのREADMEにあるサンプルコードを眺めてたら以下の記述を見つけました。

from smbus2 import SMBus

with SMBus(1) as bus:
    bus.pec = 1  # Enable PEC
    b = bus.read_byte_data(80, 0)
    print(b)

さっきのmain関数によく似ています。

なんだ、簡単に修正できるじゃないかw。

ライブラリの修正

というわけでRaspberry Piにインストールしたライブラリのソースを直に修正しちゃいます!

修正するのは、/usr/local/lib/python3.7/dist-packages/sgp30/sgp30.pyです。

まずは2行目のライブラリのインポートの記述を以下のように修正します。

from smbus2 import SMBus, i2c_msg

そして、118行目からのmain関数にあるwith構文を以下のように修正します。

修正点としては、SMBusWrapper(1)SMBus(1)にしました。

ついでにwith構文を使っているので関数の一番下にあるbus.close()を削除します。

def main():
    with SMBus(1) as bus:
        sgp=Sgp30(bus,baseline_filename=BASELINE_FILENAME+".TESTING")
        print("resetting all i2c devices")
        sgp.i2c_geral_call()
        print(sgp.read_features())
        print(sgp.read_serial())
        sgp.init_sgp()
        print(sgp.read_measurements())

もう一回動かしてみた

ライブラリを修正できたところでもう一回サンプルコードを動かしてみます。

するとセンサーの値がスムーズに取れました。

いい感じですね👍

  tVOC = 13 ppb CO2eq = 400
  tVOC = 8 ppb CO2eq = 401
  tVOC = 18 ppb CO2eq = 413
  tVOC = 11 ppb CO2eq = 408
  tVOC = 14 ppb CO2eq = 409
  tVOC = 8 ppb CO2eq = 413
  tVOC = 14 ppb CO2eq = 407
  tVOC = 9 ppb CO2eq = 407
  tVOC = 8 ppb CO2eq = 401
  tVOC = 6 ppb CO2eq = 403

センサーの値が変わらないときにはセンサーに軽く息を吹きかけるとセンサーの値が変化すると思います。

まとめ

今回はGrove VOC and eCO2 Gas SensorをRaspberry Piで動かしてみました。

ライブラリの問題でうまく動きませんでしたが、原因が単純で修正も簡単で拍子抜けしました。

ただ動かしてみたネタを書きたかったのに、図らずもエラー対処記録になってしまいましたがネタとしては程よい感じでしたw。

さて、修正をPRしないと…