Help us understand the problem. What is going on with this article?

Raspberry Pi で温湿度気圧センサを使う

More than 1 year has passed since last update.

概要

Raspberry Pi でSIM経由で通信する顔認証システムを作成し、認証結果を kintone で管理するシステムを構築します。
今回は、顔認証した時のオフィス環境データを取得するため Raspberry Pi で温湿度気圧センサの値を読み込むまでを行います。!
IMG_2017.JPG

顔認証システム構築シリーズ

Raspberry Pi で顔を認識しファイルに保存する
https://qiita.com/yukataoka/items/7510217f4b6efdefff06

Amazon Rekognition で顔が同じか比較判定し、感情などの情報を取得する
https://qiita.com/yukataoka/items/3fde5d6b22255ff1aed9

Raspberry Pi でCO2センサを使う
https://qiita.com/yukataoka/items/a3b4065e8210b8f372ff

Raspberry Pi で温湿度気圧センサを使う
https://qiita.com/yukataoka/items/8f9046587c978e91f689

利用する温湿度気圧センサについて

今回は1モジュールで、温度、湿度、気圧が計測できる、スイッチサイエンスのBME280搭載 温湿度・気圧センサモジュールを用います。
測定精度は温度が±1℃、湿度が±3%、気圧が±1hPa と、オフィス環境の計測には十分な性能です。

BME280搭載 温湿度・気圧センサモジュール
https://www.switch-science.com/catalog/2236/

配線について

BME280 は I2C か SPI 通信で測定値を取得します。
よくあるI2C温湿度センサでは SDI、SCK と 3.3v 、GND のみの配線ですが、今回は気圧センサもあるためか、6つの配線が必要です。
Raspberry Pi の配線は、以下のサイトを参考に行います。

Raspberry Pi 2で温湿度・気圧センサのBME280をPythonから使う
https://qiita.com/masato/items/027e5c824ae75ab417c1

私の場合は以下のように配線しました。

SDI (BME280)  -> SDA P03 (Raspberry Pi)
SCK (BME280)  -> SCL P05 (Raspberry Pi)
GND (BME280)  -> GND  P06 (Raspberry Pi)
SDO (BME280)  -> GND  P09 (Raspberry Pi)
Vio (BME280)  -> 3.3v P01 (Raspberry Pi)
CSB (BME280)  -> 3.3v P17 (Raspberry Pi)

環境の設定

先の作業で、Pyton3 と pip3 の設定までは完了しています。

  • I2C 通信の設定

sudo raspi-config で I2C 通信を設定します。
手順は以下です。
"5 Interfacing Option" を選択。
"P5 I2C" を選択。
"Yes" を選択し、raspi-config 完了後に再起動します。

再起動後に、センサが指定のI2Cアドレスで認識されているか確認します。

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --

I2Cアドレス76を使っていることが確認できます。

  • Python3 の設定

I2C 通信用のライブラリィ smbus2 をインストールします。

$ sudo pip3 install smbus2

スイッチサイエンスのGitHub BME280 より、bme280_sample.py を入手します。
https://github.com/SWITCHSCIENCE/BME280
https://github.com/SWITCHSCIENCE/BME280/blob/master/Python27/bme280_sample.py

bme280_sample.py は Python2.7 用のプログラムです。
そのまま Python3 で実行すると、以下のエラーになります。

$ python3 bme280_sample.py
  File "bme280_sample.py", line 95
    print "pressure : %7.2f hPa" % (pressure/100)
                               ^
SyntaxError: invalid syntax

以下のように print 文を修正すると、Python3 でも利用できます。

bme280_sample.py
前略
def compensate_P(adc_P):
        global  t_fine
        pressure = 0.0

        v1 = (t_fine / 2.0) - 64000.0
        v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
        v2 = v2 + ((v1 * digP[4]) * 2.0)
        v2 = (v2 / 4.0) + (digP[3] * 65536.0)
        v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
        v1 = ((32768 + v1) * digP[0]) / 32768

        if v1 == 0:
                return 0
        pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
        if pressure < 0x80000000:
                pressure = (pressure * 2.0) / v1
        else:
                pressure = (pressure / v1) * 2
        v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
        v2 = ((pressure / 4.0) * digP[7]) / 8192.0
        pressure = pressure + ((v1 + v2 + digP[6]) / 16.0)

        print("pressure : %7.2f hPa" % (pressure/100))

ef compensate_T(adc_T):
        global t_fine
        v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
        v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
        t_fine = v1 + v2
        temperature = t_fine / 5120.0
        print("temp : %-6.2f ℃" % (temperature) )

def compensate_H(adc_H):
        global t_fine
        var_h = t_fine - 76800.0
        if var_h != 0:
                var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] /$
        else:
                return 0
        var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)
        if var_h > 100.0:
                var_h = 100.0
        elif var_h < 0.0:
                var_h = 0.0
        print("hum : %6.2f %" % (var_h))
後略

修正後に実行すると、以下の結果を得ることができます。

$ python3 bme280.py
temp : 25.33  ℃
pressure :  997.92 hPa
hum :  58.60 %

Python3 の修正コード

スイッチサイエンスのサンプルはそのままだと使いづらいので、改良をしたものが以下です。

bme280.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-

from smbus2 import SMBus
import time

class Bme280:

    def __init__(self, busNumber=1, i2cAddress=0x76):

        self.bus = SMBus(busNumber)
        self.i2cAddress = i2cAddress
        self.digT = []
        self.digP = []
        self.digH = []
        self.timeFine = 0.0
        self.presRaw  = 0.0
        self.tempRaw  = 0.0
        self.humRaw   = 0.0

        osrsT   = 1         #Temperature oversampling x 1
        osrsP   = 1         #Pressure oversampling x 1
        osrsH   = 1         #Humidity oversampling x 1
        mode    = 3         #Normal mode
        tSb     = 5         #Tstandby 1000ms
        filter  = 0         #Filter off
        spi3wEn = 0         #3-wire SPI Disable

        ctrlMeasReg = (osrsT << 5) | (osrsP << 2) | mode
        configReg   = (tSb << 5) | (filter << 2) | spi3wEn
        ctrlHumReg  = osrsH

        self.writeReg(0xF2,ctrlHumReg)
        self.writeReg(0xF4,ctrlMeasReg)
        self.writeReg(0xF5,configReg)
        self.getCalibParam()

        self.readData()

    def writeReg(self, regAddress, data):
        self.bus.write_byte_data(self.i2cAddress, regAddress, data)

    def getCalibParam(self):
        calib = []

        for i in range (0x88,0x88+24):
            calib.append(self.bus.read_byte_data(self.i2cAddress,i))
        calib.append(self.bus.read_byte_data(self.i2cAddress,0xA1))
        for i in range (0xE1,0xE1+7):
            calib.append(self.bus.read_byte_data(self.i2cAddress,i))

        self.digT.append((calib[1] << 8) | calib[0])
        self.digT.append((calib[3] << 8) | calib[2])
        self.digT.append((calib[5] << 8) | calib[4])
        self.digP.append((calib[7] << 8) | calib[6])
        self.digP.append((calib[9] << 8) | calib[8])
        self.digP.append((calib[11]<< 8) | calib[10])
        self.digP.append((calib[13]<< 8) | calib[12])
        self.digP.append((calib[15]<< 8) | calib[14])
        self.digP.append((calib[17]<< 8) | calib[16])
        self.digP.append((calib[19]<< 8) | calib[18])
        self.digP.append((calib[21]<< 8) | calib[20])
        self.digP.append((calib[23]<< 8) | calib[22])
        self.digH.append( calib[24] )
        self.digH.append((calib[26]<< 8) | calib[25])
        self.digH.append( calib[27] )
        self.digH.append((calib[28]<< 4) | (0x0F & calib[29]))
        self.digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
        self.digH.append( calib[31] )

        for i in range(1,2):
            if self.digT[i] & 0x8000:
                self.digT[i] = (-self.digT[i] ^ 0xFFFF) + 1

        for i in range(1,8):
            if self.digP[i] & 0x8000:
                self.digP[i] = (-self.digP[i] ^ 0xFFFF) + 1

        for i in range(0,6):
            if self.digH[i] & 0x8000:
                self.digH[i] = (-self.digH[i] ^ 0xFFFF) + 1  

    def readData(self):
        data = []
        for i in range (0xF7, 0xF7+8):
            data.append(self.bus.read_byte_data(self.i2cAddress,i))
        self.presRaw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
        self.tempRaw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
        self.humRaw  = (data[6] << 8)  |  data[7]

    def getPressure(self):
        pressure = 0.0

        v1 = (self.timeFine / 2.0) - 64000.0
        v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * self.digP[5]
        v2 = v2 + ((v1 * self.digP[4]) * 2.0)
        v2 = (v2 / 4.0) + (self.digP[3] * 65536.0)
        v1 = (((self.digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((self.digP[1] * v1) / 2.0)) / 262144
        v1 = ((32768 + v1) * self.digP[0]) / 32768

        if v1 == 0:
            return 0
        pressure = ((1048576 - self.presRaw) - (v2 / 4096)) * 3125
        if pressure < 0x80000000:
            pressure = (pressure * 2.0) / v1
        else:
            pressure = (pressure / v1) * 2
        v1 = (self.digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
        v2 = ((pressure / 4.0) * self.digP[7]) / 8192.0
        pressure = pressure + ((v1 + v2 + self.digP[6]) / 16.0)
        return pressure/100

    def getTemperature(self):
        v1 = (self.tempRaw / 16384.0 - self.digT[0] / 1024.0) * self.digT[1]
        v2 = (self.tempRaw / 131072.0 - self.digT[0] / 8192.0) * (self.tempRaw / 131072.0 - self.digT[0] / 8192.0) * self.digT[2]
        self.timeFine = v1 + v2
        temperature = self.timeFine / 5120.0
        return temperature

    def getHumidity(self):
        varH = self.timeFine - 76800.0
        if varH != 0:
            varH = (self.humRaw - (self.digH[3] * 64.0 + self.digH[4]/16384.0 * varH)) * (self.digH[1] / 65536.0 * (1.0 + self.digH[5] / 67108864.0 * varH * (1.0 + self.digH[2] / 67108864.0 * varH)))
        else:
            return 0
        varH = varH * (1.0 - self.digH[0] * varH / 524288.0)
        if varH > 100.0:
            varH = 100.0
        elif varH < 0.0:
            varH = 0.0
        return varH

if __name__ == '__main__':
    sensor = Bme280()
    try:
        print("pressure    : %7.2f hPa" % sensor.getPressure())
        print("temperature :  %-6.2f ℃" % sensor.getTemperature())
        print("humidity    : %6.2f %" % sensor.getHumidity())
    except KeyboardInterrupt:
        pass

なお、利用させていただいたスイッチサイエンスのライセンスは以下となります。

# Copyright (c) 2018 Switch Science
# This software is released under the MIT License.
# http://opensource.org/licenses/mit-license.php

結果

改良後、以下のように計測値が確認できました。

$ python3 bme280.py
pressure    :  966.44 hPa
temperature :  23.64  ℃
humidity    :  58.99 %

参考サイト

BME280搭載 温湿度・気圧センサモジュール
https://www.switch-science.com/catalog/2236/

スイッチサイエンス / BME280
https://github.com/SWITCHSCIENCE/BME280

Raspberry Pi 2で温湿度・気圧センサのBME280をPythonから使う
https://qiita.com/masato/items/027e5c824ae75ab417c1

40: Raspberry Pi3 で BME280 温度、湿度、気圧計センサー
https://qiita.com/KZ2/items/68076fa6a086d89f668e

yukataoka
若い頃にUターンしたIT屋で、出身は高知県仁淀川町。IoTとクラウドを活用した地域課題解決などに挑戦。 コミュニティ活動の傍ら、サイボウズ公認 kintone エバンジェリスト も務める複業者。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away