2022 年度 OSS リテラシ 3 : Raspberry Pi でのセンサー利用

はじめに: 利用するセンサー

高性能なセンサーは I2C(アイ・スクエア・シー, アイ・アイ・シー, アイ・ツー・シー)規格が使われていることが多い. I2C は低速な周辺機器をマイコンに接続するためのものであり, 組み込みシステムや携帯電話などで利用される.

  • 通信速度 : 0 ~ 100 kbps (標準モード)
  • 信号線 : SDA (データ), SCL (クロック)
  • 備考 : スレーブの識別にはアドレスを使う. 信号線にはプルアップ抵抗が必要.

本演習での IoT システム構築においては,以下の I2C 規格のセンサーを利用する.

  • 気温・湿度センサー: Adafruit Si7021
    • 精度: -0.4 ~ +0.4 度 (温度), -3.0 ~ +3.0 % (湿度)
    • I2C アドレス: 0x40
  • 照度センサー: Adafruit TSL2561
    • ダイナミックレンジ: 0.1 ~ 40,000 Lux
    • I2C アドレス: 0x39 (0x29, 0x49)
  • 気圧・温度センサー: Adafruit BMP180
    • 精度: -4 ~ 2 hPa (圧力 (絶対値)), -2 ~ +2 度 (温度)
    • I2C アドレス: 0x77

I2C のセンサーは全てラズパイの GPIO 2, 3 (ピン番号 3, 5) に接続されている.

センサーの接続方法

本演習ではセンサーを簡単に接続するために, ラズパイに専用基板を利用する. I2C 規格のセンサーは演習用基板の CON 1, CON 2, CON 3 のどれかに接続するすれば良い. これらのポートはラズパイの GPIO 2, GPIO 3 (ピン番号 3, 5) に並列に接続されている.

I2C の有効化

"メニュー" => "設定" => "Raspberry Pi の設定" を選択し, "インターフェイス" タブより I2C を有効にする

I2C で接続された周辺機器には固有のアドレスが付与される. 接続した I2C 機器に割り当てられたアドレスを確認するためには i1x 接続した I2C 機器に振られたアドレスを確認するためには, i2cdetect コマンドを使う. 機器ごとにアドレスが決まっているので, アドレスが表示されるか確認をする. 以下の例では, 0x39 が TSL2561, 0x40 が Si7021 である. 自分の接続したセンサーのアドレスが表示されていることを確認すること.

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

必要なライブラリのインストール

各センサーの python ライブラリが配布されているので, それをインストールする. pip コマンドは Python のパッケージ管理システムである. 近年は言語ごとにパッケージ管理システムを持ち, OS が用意している以外のライブラリをインストールことが容易になっている (例えば ruby なら gem).

TSL2561

$ sudo pip install tsl2561

このライブラリを導入することで,以下のような Python プログラムでデータ取得することができる. なお,ファイル名を tsl2561.py とはしないこと.

$ vi sensor-tsl2561.py

  import time
  from tsl2561 import TSL2561

  #インスタンス作成
  tsl = TSL2561(debug=True)

  #無限ループ
  while True:
    # 値の取得
    light = tsl.lux()
    # 表示
    print(str(light))
    # 1秒待つ
    time.sleep(1)

実行してみる.

$ python sensor-tsl2561.py

  455
  455
  455
  ...
練習) センサーの前に手をかざしたり, センサーを蛍光灯に向けると照度が変化することを確認せよ.

Si7021

$ sudo pip install pi-si7021

このライブラリを導入することで,以下のような Python プログラムでデータ取得することができる.

$ vi sensor-si7021.py

  import time
  from pi_si7021 import Si7021

  # インスタンス作成
  si = Si7021()

  # 無限ループ
  while True:
     # データ取得
     temp = si.temperature
     humi = si.relative_humidity

     # 小数点以下 2 桁まで表示
     print("Temperature: " + str(round(temp, 2)) + u" \u00B0C")
     print("Relative humidity: " + str(round(humi, 2)) + " %")

     # 1秒待つ
     time.sleep(1)

Si7021 を使うためには, まず pigpiod を起動する必要がある (1 回行えば良い).

$ sudo pigpiod

その後, 実行する.

$ python sensor-si7021.py

  Temperature: 23.54 °C
  Relative humidity: 63.0 %
  ... 

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

$ sudo pip install adafruit-bmp

このライブラリを導入することで,以下のような Python プログラムでデータ取得することができる.

$ vi sensor-bmp180.py

  import time
  from Adafruit_BMP.BMP085 import BMP085

  # インスタンス作成
  bmp180 = BMP085()

  # 無限ループ
  while True:
       # データ取得
       temp = bmp180.read_temperature()
       pres = bmp180.read_pressure()

       # 小数点以下 2 桁まで表示
       print('Temp = {0:0.2f} *C'.format( temp ))
       print('Pressure = {0:0.2f} Pa'.format( pres ))

       # 1秒待つ
       time.sleep(1)

実行してみる.

$ python sensor-bmp180.py

  Temp = 27.80 *C
  Pressure = 101361.00 Pa
  ...

センサーで取得したデータの送信と可視化

可視化サーバ

教員の用意した可視化用サーバがあるので,それに自分のラズパイからデータを送ってもらう. 教員のサーバでは grafana というサーバソフトウェアが動作しており, 自動的に送信されたデータがグラフ化される. このサーバに自分のデータ (センサーの値,ホスト名,IP アドレス)が表示されるようにすることが現時点のゴールである.

<URL:http://grafana.matsue-ct.jp:3000/d/b9fc40a7-b54e-41d1-86c8-07f57c4925c1/2023-oss3?orgId=1&from=now-15m&to=now>

データ送信方法

可視化サーバへのデータ送信には HTTP GET メソッドを用いる.書式は以下である.

http://grafana.matsue-ct.jp/monitoring.php?hostname=<ホスト名>&time=<日時>&temp=<温度>&humi=<湿度>&pres=<気圧>&lux=<照度>

具体的には以下のような形となる.

http://grafana.matsue-ct.jp/monitoring.php?hostname=jxxxx&time=2023-10-01T00:00:00&temp=10.0&humi=80&pres=10130.0&lux=200

この文字列をそのままブラウザに入れてみると,サーバが反応し,内部で実行される SQL 文を確認することができるので,試してみよ.

データ送信プログラムの作成

ラズパイでデータ送信プログラムを作成する.プログラム内で最終的には

http://grafana.matsue-ct.jp/monitoring.php?hostname=jxxxx&time=2023-10-01T00:00:00&temp=10.0&humi=80&pres=10130.0&lux=200

のような文字列を作成して,それをサーバに送信する命令の引数に与えれば良い.

プログラムで利用すると良いクラス

urllib

Python では HTTP の GET メソッドに対応したクラスは多数あるが, ここでは標準で組み込まれている urllib を紹介する

import urllib.request

# 送信する文字列の作成
url = "http://www.gfd-dennou.org/"

# 送信
response = urllib.request.urlopen( url )

# リターンコードの表示 (デバッグ用)
print(response.getcode())

# サーバからの戻り値の表示
html = response.read()
print(html.decode('utf-8'))

datetime

日時を扱うためのクラス.フォーマット指定や,分だけ取得することなどもできる.

import datetime

# 現在の日付
now = datetime.datetime.now()
print(now)  # --> 2023-04-08 23:08:13.873520

# 年を表示
print(now.year)  # --> 2023

# 分を表示
print(now.minute)  # --> 8

# フォーマット指定
now2 = now.strftime('%Y-%m-%dT%H:%M:%S')
print(now2)  #--> 2023-04-08T23:08:13.873520

文字列連結

いろいろ書き方がある.自分の好みのものを使って欲しい.

moji  = 'Alice'
suuji = 25.12345

print('Alice is %d years old' % suuji)
# --> Alice is 25 years old

print("Alice is " + str(round(suuji, 2)) + " years old")
# --> Alice is 25.12 years old

print('%s is %f years old' % (moji, suuji))
# --> Alice is 25.12345 years old

print( f'?hostname={moji}&temp={suuji:.2f}' )
# --> ?hostname=Alice&temp=25.12

プログラムの構造

1 分毎にデータを取得して送信するようなプログラムは, 例えば以下のような構造にすればよい. このプログラム例では 1 分毎にデータの取得・送信を行っているが, センサーの値がふらつくのは普通のことなので, 数秒おきにデータを取得して 1 分平均値を計算し,平均値を送信するようにして欲しい.

# インポート

# センサ用のインスタンス作成

# 初期化:
#   * ホスト名の設置
#   * サーバ名の設定
#     server = "http://grafana.matsue-ct.jp/monitoring.php"
#   * 初期時刻の取得
#     初期時刻の「分」を min0 に代入

# 無限ループ
while True:
   # 時刻の取得
   #   現在時刻,現在の「分」を min1 に代入

   # 1 分毎にデータ送信
   if (min0 != min1) :
      # センサーからデータ取得

      # データ送信

      # デバッグ出力

   # 変数の更新
   # min0 = min1

   # 少し待つ

課題 5

  • ラズパイのデータ送信プログラムを作成しなさい.自分の使っているセンサー 2 種類について 3 つの物理量を 1 分毎に教員のサーバに送信すること. 但し,各物理量は小数点以下 1 桁までで表すこと.また,瞬間値ではなく平均値を送信するようにして欲しい.
    • Si7021 → 温度,湿度
    • TSL2561 → 照度
    • BMP180 → 温度,圧力
  • 作成したプログラムと grafana のダッシュボードのスナップショットを wbt より提出せよ.
    • スナップショットには必ず自分のホスト名 (学生番号) が 3 つのグラフに含まれていること.
    • スナップショットには自分のホスト名と IP が必ず含まれていること