新しいものづくりがわかるメディア

RSS


「土日で完成! 趣味のラズパイ」

土日で完成! 趣味のラズパイ BME680の測定データを小型ディスプレイに表示させる

前回までで、「BME680」を利用して気温と湿度、気圧、空気の汚染度を測ってきました。今回はこの測定値をCSVファイルに記録したり、小型ディスプレイに表示させたりしてみましょう。

まずはデータをCSVファイルに出力できるようにしましょう。このあたりは「今さらきけない『ラズパイってなんですか?』の『キャラクターディスプレイモジュールって何ですか』」で紹介した手順とほぼ同じです。「気温と湿度、気圧を計測する」で紹介したプログラム「sokutei.py」を下地に、プログラムを実行したら1度だけ値を返すようにプログラムを改造します。

改造のポイントは、まずwhile文の無限ループをやめて気温と湿度、気圧の変数をそれぞれtemp、hum、pressとして定義し、時刻と共に表示させたところにあります。

#!usr/bin/env python
# -*- coding: utf-8 -*-
import bme680
import datetime

command = 0x00

d = datetime.datetime.now() # datetime変数で日付と時刻を取得

sensor = bme680.BME680()

sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)

temp = sensor.data.temperature # 気温の変数
hum = sensor.data.humidity # 湿度の変数
press = sensor.data.pressure # 気圧の変数

def main():
    # データ取得
    output = '{0:.2f},{1:.2f},{2:.2f}'.format(temp, hum, press) # 変数をoutputに代入
    
    # 温度、湿度、気圧の表示
    print(d.strftime("%Y/%m/%d,%H:%M,"),output)

    return

if __name__ == "__main__":
    main()

これを実行すると以下のように表示されます。

-----------
$ python pth_measure.py
2023/03/15,11:07, 25.46,51.81,1026.95
-----------

温度、湿度、気圧がこのように表示される 温度、湿度、気圧がこのように表示される

左から日付、時間、気温、湿度、気圧の順です。例えばこれを定期的にCSVに出力し、グラフなどを作ってもよいですね。この場合は「cron」という仕組みを使います。cronは定期的にプログラムを動かすように設定できるコマンドです。今回は以下のように設定します。

まず「crontab -e」と入力して、cronをエディターモードで起動します。初期設定の場合、利用するエディターが聞かれますが、「1」のnanoを選んでください。

cronが開いたら「#」が続いている行の最後に以下の内容を記述します。

*/10 * * * * python /home/pi/pth_measure.py >> /home/pi/data.csv

記述したら「Ctrl+x」でファイルを閉じ、記述するか聞かれるので「y」と入力します。

この画像のように記述する この画像のように記述する

この記述の中で「*/10 * * * *」は「10分おきにこのコマンドを実行します」という意味です。それぞれの「*」は分(0~29)、時(0~23)、日(1~31)、月(1~12)の順番で最後が曜日です。曜日は0、1、2、3、4、5、6にそれぞれ日、月、火、水、木、金、土が割り当てられています。

このほかに「ステップ値(/)」と「値リストセパレーター(,)」「値の範囲(-)」を設定できます。例えば以下の通りです。

0 0,6 * * * 0時0分と6時0分
0 9-17 * * * 9時から17時までの毎0分
0 */6 * * * 0時から6時間おきの毎0分
0 9-17/2 * * * 9時から17時の間に2時間おきの毎0分

なおファイル名は“絶対パス”で書く必要があります。絶対パスとはディレクトリが作成されているパスを省略せずにフルに記述するという意味です。ユーザーフォルダは「pi」にありますので、「/home/pi」から始まるように書いていきます。ファイル名をつないでいる「>>」は、これは記述したファイルの最後に内容を追記していくという意味になります。

このように測定データを記録できる このように測定データを記録できる
測定データをExcelでグラフにした 測定データをExcelでグラフにした

測定データを小型ディスプレイに表示させる

続いて小型ディスプレイへの表示に取りかかります。先ほど挙げた「キャラクターディスプレイモジュールって何ですか」でたどった道とほぼ同じです。秋月電子通商で販売されている「有機ELキャラクタディスプレイモジュール 16×2行 黄色」を使って表示させます。

なお今回は、測定したデータを文字列として変数の中に保管し、それを利用して小型ディスプレイに表示させるので、「round」文で得たデータを小数点1桁で四捨五入し、それを「str」文で文字列に変換し、表示させます。これを踏まえたプログラムが以下になります。測定データを10秒表示して消えるようになっています。

#!usr/bin/env python
# -*- coding: utf-8 -*-
import bme680
import time
import so1602

# ディスプレイ初期化
so1602.setaddr(0x3c)
so1602.command(0x0c)
so1602.command(0x01)
command = 0x00

sensor = bme680.BME680()

sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)

temp = str(round(sensor.data.temperature,1)) # 四捨五入して文字列に
hum = str(round(sensor.data.humidity,1)) # 四捨五入して文字列に
press = str(round(sensor.data.pressure,1)) # 四捨五入して文字列に

def main():

    #ディスプレイに表示
    so1602.command(0x80)
    so1602.write("T=" + temp + "°C")
    so1602.command(0x89)
    so1602.write("H=" + hum + "%")
    so1602.command(0xa0)
    so1602.write("P=" + press + "hPa")

    time.sleep(10)

    # ディスプレイ初期化
    so1602.command(0x0c)
    so1602.command(0x01)

    return

if __name__ == "__main__":
    main()

このプログラムを「pth_disp.py」などのように名付けて保存したら、以下のようにプログラムを実行します。

$ python pth_disp.py

すると下の写真のように小型ディスプレイに表示されます。

小型ディスプレイに表示された気温と湿度、気圧 小型ディスプレイに表示された気温と湿度、気圧

空気の汚染度を小型ディスプレイに表示させる

では次に、BME680による、空気の汚染度をディスプレイに表示する仕組みを作っていきましょう。BME680で得られるのはガス抵抗値です。このためしばらく動作させて平衡になったところの値を求め、そこからどのように変化するのかによって空気の汚染度を測ります。そのため、先ほど述べたような1発測定では正確な値を得ることができません。代わりに5秒置きに表示が切り替わるように設定します。一定時間ごとに測定するためには、前回のようなwhile文でプログラムを構成する必要があります。

このあたりをプログラムにまとめると以下のようになります。

#!usr/bin/env python
# -*- coding: utf-8 -*-
import bme680
import so1602
import time

# ディスプレイ初期化
so1602.setaddr(0x3c)
so1602.command(0x0c)
so1602.command(0x01)
command = 0x00

sensor = bme680.BME680()
sensor.set_filter(bme680.FILTER_SIZE_3)
sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
sensor.set_gas_heater_temperature(320)
sensor.set_gas_heater_duration(150)
sensor.select_gas_heater_profile(0)


try:
    while True:
        if sensor.get_sensor_data():
            if sensor.data.heat_stable:

                gas_resist = str(round(sensor.data.gas_resistance,2))

                # ディスプレイ初期化
                so1602.command(0x0c)
                so1602.command(0x01)

                # ディスプレイ表示
                so1602.command(0x80)
                so1602.write("Air Registance")
                so1602.command(0xa0)
                so1602.write(gas_resist + "Ω")

                time.sleep(1)

        else:
            # ディスプレイ初期化
            so1602.command(0x0c)
            so1602.command(0x01)
            
            # ディスプレイ表示
            so1602.command(0x80)
            so1602.write("Measurement")
            so1602.command(0xa0)
            so1602.write("preparation")

            time.sleep(1)

except:KeyboardInterrupt

# ディスプレイを初期化して終了
so1602.command(0x0c)
so1602.command(0x01)

しつこいくらいに小型ディスプレイの初期化をしていますが、これをやらないと表示にゴミ(不要な表示)が残ってしまうためです。

このプログラムをair_register.pyなどのように名前を付けて保存します。以下のようにすると実行できます。

$ python air_register.py

1秒置きにガス抵抗値が小型ディスプレイに表示されます。Ctrl+Cで終了できます。

測定準備中と表示されたあと…… 測定準備中と表示されたあと……
ガス抵抗値が表示される ガス抵抗値が表示される

難しそうに感じますが、やってみると意外と簡単にできます。プログラムがうまくいっており、コンソールにも表示されるのにOLEDに表示されない場合は、接触不良を疑ってください。ブレッドボードで組んでいきますので、残念ながらこういう事象はままあります。ただそれを含めても楽しい工作です。ラズパイ以外のパーツはそれほど値段がかかりませんので、チャレンジして頂けるとうれしいです。

ニュース

編集部のおすすめ

連載・シリーズ

注目のキーワード

もっと見る