bme280結果

センサ(BME280)で気温・気圧・湿度を測る

どうもしっぽにちは、Kです。

今回は「あぐりっち~その2~」です。
BME280というセンサを使って植物の育成環境(気温、気圧、湿度)を計測する方法を紹介します。

はじめに

作物を育てるのに大事なことってなんでしょうか。愛...でしょうか。
冗談はこれくらいにしておきましょう笑

農業が難しい理由の一つに、作物の育成にノウハウを要することがあるでしょう。
多くの植物は光合成によって生長しますが、この光合成は光量、波長、温度、湿度、CO2濃度など、実に様々なパラメータに影響を受けます。
しかも生長のフェーズによって最適パラメータが異なるようです。もちろん光合成の他にも気にしなければいけないことはたくさんあります。

これらを農家の方々が長年の歳月を費やしてノウハウとして構築しているのです。しかも多くの場合は定量的なデータとしては残されていないのです。
これを想像すると無理やろ~って思っちゃいますね...

前回の記事でも少し書きましたが、Kがこれからやろうとしているアグリッチでは、植物の生長に影響しているパラメータをできる限り記録し、一人一人の好みに合わせた味、大きさ、食感などが再現できるようになることを目指します。

つまり、センサが大事ということでしょうか。

センサの使い方

概要

今回使用するのは以下の4点です。
・ラズベリーパイ3B+ [秋月電子] [Amazon]
・センサ(BME280) [秋月電子] [Amazon]
・ブレッドボード [秋月電子] [Amazon]
・ジャンパーワイヤー [秋月電子]

製品

作業としては、簡易な電子工作(ちょっとだけはんだ付け)とコーディング(Githubなどから拾ってこれます)が必要です。
これまでほとんど電子工作をやってこなかったKですが、そんなに苦労することなくできたのでたぶん簡単だと思います。

ハードの準備

まずBME280を組み立てていきます。
マイコンとの通信方式設定のため、表面のJ3(赤枠)にはんだを流し込みます。

I2Cはんだ

通信方式はI2CとSPIから選択できるようで、SPIの場合はこの流し込みは不要です。Kはぶっちゃけこの通信方式の違いはあまりわかっていないです汗
FUJITSUさんが説明してくれています。

I2Cの方が配線をシンプルにできるようですね、ここではんだを流し込んどいた方が後々楽そうということで今回はI2Cに。いいのかそんな安易な理由で。勉強します...

続いてセンサに、付属のピンを付けます(下図)。
穴は6個あるので付属のピン(7本)のうち1本をちぎって穴に挿しましょう。図の例のように間違って2本ちぎったりしないように笑
挿した穴からきちんと導通するようにそれぞれはんだ付けをしましょう。
※隣の穴とくっつかないように!

ピン

ピン付けができたら後はそのままブレッドボードに挿すだけです(下図)。

画像4

つづいてセンサとラズパイをつなぎます。完成形はこんな感じ↓

画像5

ブレッドボードはだいたい下図のように、両端の列が横につながってて(青線)、真ん中が縦につながっています(赤線)。赤線に垂直にさされたセンサのそれぞれの列にラズパイのピンをあてがう感じです。

ブレッドボード

ラズパイのピン配置はこんな感じです↓今回使うのは赤丸のピンです。

ピン配置

下図のように①、⑥ピンでセンサに電力供給(3.3V)し、③、⑤で計測値を拾います。

結線説明

ソフトの準備

ここまで来たらハード面は完了なのですが、センサの計測値を取得し、数値データとして出力しなければなりません。センサの計測値はそのままではよくわからない数字の羅列になっており、そもそもどのような形で値が格納されているのかもわかりません。
これを調べるところからやるのは骨が折れるので、公開されているコードを使用することに。
”BME280 Git"とか調べると、出てきました。SWITCHSCIENCEさんのPythonコード。ありがたくつかわせていただきますm(._.)m

#coding: utf-8
# hh:mm:ss, temperature, pressure, humidity

from smbus2 import SMBus
# import time
import csv
import datetime

bus_number  = 1
i2c_address = 0x76
DATA_DIR = '/home/pi/Desktop/agri/'
bus = SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0


def writeReg(reg_address, data):
   bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
   calib = []
   
   for i in range (0x88,0x88+24):
       calib.append(bus.read_byte_data(i2c_address,i))
   calib.append(bus.read_byte_data(i2c_address,0xA1))
   for i in range (0xE1,0xE1+7):
       calib.append(bus.read_byte_data(i2c_address,i))

   digT.append((calib[1] << 8) | calib[0])
   digT.append((calib[3] << 8) | calib[2])
   digT.append((calib[5] << 8) | calib[4])
   digP.append((calib[7] << 8) | calib[6])
   digP.append((calib[9] << 8) | calib[8])
   digP.append((calib[11]<< 8) | calib[10])
   digP.append((calib[13]<< 8) | calib[12])
   digP.append((calib[15]<< 8) | calib[14])
   digP.append((calib[17]<< 8) | calib[16])
   digP.append((calib[19]<< 8) | calib[18])
   digP.append((calib[21]<< 8) | calib[20])
   digP.append((calib[23]<< 8) | calib[22])
   digH.append( calib[24] )
   digH.append((calib[26]<< 8) | calib[25])
   digH.append( calib[27] )
   digH.append((calib[28]<< 4) | (0x0F & calib[29]))
   digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
   digH.append( calib[31] )
   
   for i in range(1,2):
       if digT[i] & 0x8000:
           digT[i] = (-digT[i] ^ 0xFFFF) + 1

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

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

def readData():
   #get record time and date
   record_datetime = datetime.datetime.now()
   # record_file_name = record_datetime.strftime('%Y%m%d') + '_bme280.csv'
   record_file_name = 'bme280.csv'
   record_date = record_datetime.strftime('%Y-%m-%d')
   record_time = record_datetime.strftime('%X')
   
   data = []
   
   for i in range (0xF7, 0xF7+8):
       data.append(bus.read_byte_data(i2c_address,i))
   pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
   temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
   hum_raw  = (data[6] << 8)  |  data[7]
   
   T = compensate_T(temp_raw)
   P = compensate_P(pres_raw)
   H = compensate_H(hum_raw)
   
   writer = csv.writer(open(DATA_DIR + record_file_name, 'ab'))
   writer.writerow([record_date, record_time, T, P, H])
  
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)
   return pressure

def 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)
   return 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] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))
   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)
   return var_h

def setup():
   osrs_t = 1          #Temperature oversampling x 1
   osrs_p = 1          #Pressure oversampling x 1
   osrs_h = 1          #Humidity oversampling x 1
   mode   = 3          #Normal mode
   t_sb   = 5          #Tstandby 1000ms
   filter = 0          #Filter off
   spi3w_en = 0            #3-wire SPI Disable

   ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
   config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
   ctrl_hum_reg  = osrs_h

   writeReg(0xF2,ctrl_hum_reg)
   writeReg(0xF4,ctrl_meas_reg)
   writeReg(0xF5,config_reg)


setup()
get_calib_param()


if __name__ == '__main__':
   try:
       readData()
   except KeyboardInterrupt:
       pass

これをラズパイ上のpythonに書き込んで実行をすれば、下のように計測結果が出力されるはずです。

T= 18.39287 ℃
P= 1012.12736 hPa
H= 54.23974 %

これでいつでも環境条件を計測できるわけなのですが、いちいち実行を押さないといけないのは面倒ですよね。
ということでここでつくったpythonファイルを、自動で定期的に実行してくれるようにcrontabを設定することにしました。
crontabについてはリナックスアカデミーさんが丁寧にまとめてくれていますのでそちらを参照ください。
今回は1時間おきに計測する設定で、下のようにcrontabを設定しました。
*/AとすることでAおきに実行となります。
実行してほしいファイルのディレクトリパスを後ろで指定します。

0 */1 * * * pi python /home/pi/Desktop/agri/bme280.py
分 時 日 月 曜日

S!PPOメンバーにcrontabがうまく動かないと相談して、あれこれ作業をしてもらったんですが、なんと、、
動かなかった理由が、上のcrontab設定のpythonの後ろに数字の"3"が入っていたためでした笑
S!PPOメンバーのBBさんに教えてもらった通りに打ち込んでいたのですが、pythonのバージョンを勘違いしていたために生じたエラーでした。

あの手この手を尽くしてここまでできてるのに何で動かないんだろーってみんなで2時間くらい悩んでそんなチョイミスが原因とは... BBさん許すまじ
冗談です笑 自分がよくわかっていなかったのが悪かったんです笑

結果

ということで無事計測できたので、crontabを実行した状態で数日間ほったらかしてみました。
↓結果がこちら↓

bme280結果

赤が気温、青が湿度、黒が気圧です。
朝と夜の気温差で周期的な温度の上下があることがわかります。
また、気圧が下がっているときはだいたい雨なのですが、そのタイミングで湿度も上昇しているので、ちゃんと測れていそうですね!

今回は気温、湿度、気圧を計測しましたが、今後は水のpHやCO2濃度なども測っていこうと思います。

というか早く何か育てろよ!って感じですね笑
年明け頃から本格的に始めようと思います。

乞うご期待!

この記事が気に入ったらサポートをしてみませんか?