2018 年度 OSS リテラシー 3 : 第 7 回 センサーの利用 & 監視

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

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

演習では以下の I2C 規格のセンサーを利用する. これらのセンサー が全てラズパイの GPIO 2, 3 (ピン番号 3, 5) に接続されている.

  • 気圧・温度センサー: Adafruit BMP180
    • 精度: -4 ~ 2 hPa (圧力 (絶対値)), -2 ~ +2 度 (温度)
    • I2C アドレス: 0x77
  • 照度センサー: Adafruit TSL2561
    • ダイナミックレンジ: 0.1 ~ 40,000 Lux
    • I2C アドレス: 0x39 (0x29, 0x49)
  • 非接触型温度計 (放射温度計): Adafruit TMP007
    • I2C アドレス: 0x40 (0x47)

なお, I2C 規格ではないが, 本演習では温度・湿度センサー SENSIRION SHT75 も用いる. このセンサーは精度が良く, I2C 規格のそれに比べてノイズに強い (ケーブル長を長くとれる) という利点がある. 松江高専の環境モニタリングシステムの主力はこの SHT75 である.

  • 温度・湿度センサー: SENSIRION SHT75
    • 精度: -0.3 ~ +0.3 度 (温度), -1.8 ~ +1.8 % (湿度)

センサーの接続方法

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

温度・湿度センサーは練習用基盤の CON6 ポートに接続する. このポートは GPIO 23 ピンと GPIO 24 ピンに接続されている. 今回は使わないが, CON 4 ポートは GPIO17 ピンと GPIO18 ピンに, CON5 ポートは GPIO27 ピンと GPIO22 ピンに接続されている.

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

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

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

$ sudo pip install adafruit-bmp

  Collecting adafruit-bmp
  ... (中略)...
  Successfully built adafruit-bmp Adafruit-GPIO adafruit-pureio
  Installing collected packages: adafruit-pureio, Adafruit-GPIO, adafruit-bmp
  Successfully installed Adafruit-GPIO-1.0.3 adafruit-bmp-1.5.4 adafruit-pureio-0.2.3

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

$ sudo pip install adafruit-tmp

  Collecting adafruit-tmp
  ... (中略)...
  Successfully built adafruit-tmp
  Installing collected packages: adafruit-tmp
  Successfully installed adafruit-tmp-1.6.3

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

$ sudo pip install tsl2561

  Collecting tsl2561
  ... (中略)...
  Installing collected packages: tsl2561
  Successfully installed tsl2561-3.3

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

$ sudo pip install sht-sensor

  Collecting sht-sensor
  ... (中略)...    
  Successfully built sht-sensor
  Installing collected packages: sht-sensor
  Successfully installed sht-sensor-18.4.2

$ sudo pip install future

  Collecting future
  ... (中略)...    
  Successfully built future
  Installing collected packages: future
  Successfully installed future-0.17.1

実習用サンプルスクリプト

実習用サンプルスクリプトを GitHub から入手する.

$ git clone https://github.com/sugiymki/iotex-sensor.git

clone した iotex-sensor の bin 以下にサンプルスクリプトが存在する. 以下の手順に従って, 接続したセンサーが実際に動作するか確認せよ.

温度湿度センサー SHT75 の利用

SHT75 は, pip install sht-sensor を行うことで, 実行ファイルが /usr/local/bin/sht としてインストールされる. 従って, /usr/local/bin 以下にインストールされた sht コマンドを用ることで温度, 湿度, 露点温度, を測定することができる.

$ /usr/local/bin/sht -v -trd 24 23

  temperature: 24.48
  rh: 55.7499717405
  dew_point: 15.0566070705

なお引数は以下の通りである.

-t: 温度 (temperature)
-r: 相対湿度 (relative humidity)
-d: 露点温度 (dew point)

なお, 今回は関係ないが, CON4 と CON5 に SHT75 を接続した場合は以下のように実行する.

$ /usr/local/bin/sht -v -trd 18 17
$ /usr/local/bin/sht -v -trd 27 22

I2C 規格のセンサーの利用

注1) I2C 規格のセンサーは 6 セットしか無いので, 順番に使ってください. 電源を切ってからセンサーを接続すること.
注2) 本日の課題にあるように, I2C 規格のセンサーの利用についてはスクリーンショットを何度も撮ってもらいます. 課題内容を先に確認しておくこと.

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

I2C で接続された周辺機器には固有のアドレスが付与される. 接続した I2C 機器に振られたアドレスを確認するためには, i2cdetect コマンドを使う. 機器ごとにアドレスが決まっているので, アドレスが表示されるか確認をする. 0x39 が TSL2561, 0x40 が TMP007, 0x77 が BMP180 である.

$ 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: -- -- -- -- -- -- -- 77                         

bmp180

bmp180 を用いると温度 (Temp), 圧力 (Pressure) が得られる.

$ ./iotex-sensor/bin/bmp180
Temp = 17.00 *C
Pressure = 101521.00 Pa

オプション -t, -p をつけるとそれぞれ温度と圧力の値のみが出力される.

$ ./iotex-sensor/bin/bmp180 -t
17.00

$ ./iotex-sensor/bin/bmp180 -p
101521.00

TMP007

tmp007 を用いると基板の温度 (Die temperature) と TMP007 を向けている方向の壁か何かの放射温度 (Object temperature) が表示される.

$ ./iotex-sensor/bin/tmp007
Object temperature: 18.714 *C
Die temperature: 17.219 *C

オプション -t, -r をつけるとそれぞれ基板の温度と放射温度の値のみが出力される.

$ ./iotex-sensor/bin/tmp007 -t
17.219

$ ./iotex-sensor/bin/tmp007 -r
18.714

練習:センサーの前に手をかざすと放射温度 (Object temperature) が変化することを確認せよ.

TSL2561

tsl2561 を用いると照度を Lux 単位で測ることができる.

$ ./iotex-sensor/bin/tsl2561
LUX: 262

オプション -l をつけると照度の値のみが出力される.

$ ./iotex-sensor/bin/tsl2561
262

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

センサーの監視:zabbix の設定

遠隔地に配置された多数のセンサーを一元的に管理するためには zabbix のようなサーバ監視ソフトウェアが欠かせない. 本演習では zabbix agent (パッケージ名 zabbix-agent) は 1 週目にインストール済みである.

設定ファイルを編集する. 既存の sky.epi.it.matsue-ct.jp で稼働している zabbix サーバに接続するための設定である. zabbix では, HostMetadat が IoTeX2018 となっているサーバを自動登録する設定が入っている.

$ sudo -s

# cd /etc/zabbix

# cp zabbix_agentd.conf zabbix_agentd.conf.bk

# vi zabbix_agentd.conf  

  (以下の項目のみ設定. 必要に応じてコメントアウトする/コメントアウトを外す)

  Server=sky.epi.it.matsue-ct.jp

  ServerActive=sky.epi.it.matsue-ct.jp

  # Hostname=Zabbix server       (コメントアウト)

  HostnameItem=system.hostname

  HostMetadata=IoTeX2018

再起動

# /etc/init.d/zabbix-agent restart

zabbix サーバ <URL:http://sky.epi.it.matsue-ct.jp/zabbix/> に guest でログインし, 以下のように選択して自分のラズパイの状態を確認せよ. なお, グラフの横軸を最新 1 時間にしておくと良いだろう (マウスで表示領域を柔軟に変更できるので試してみよ).

  • [監視データ] => [スクリーン] => IoTeX => ホスト : <自分のラズパイのホスト名>

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

これ以下の演習では, 温度湿度センサー SHT75 のみを接続して行うこと.

データの送信

10 秒ごとにデータを取得して 1 分平均のデータを作り, それをサーバ (sky.epi.it.matsue-ct.jp) に送信する. 先に git clone したリポジトリの中にデータ取得スクリプトが含まれているのでそれを利用する. このスクリプトでは HTTP GET を用いてデータをサーバに送っている.

$ cd ~/    (ホームディレクトリに移動)

$ ruby iotex-sensor/bin/monitoring

  2018-11-20 23:28:00 +0900
  Vector["17.41", "17.4", "17.38", "17.4", "17.42", "17.41"]
  17.403333333333336
  Vector["56.76301405", "56.76149805", "56.819344328", "56.822379528", "56.7949739845", "56.76301405"]
  56.78737066508334
  Vector["8.73601411145", "8.72627344345", "8.72266315683", "8.74214685852", "8.75369502689", "8.73601411145"]
  8.736134451431667

  "http://sky.epi.it.matsue-ct.jp/~sugiyama/php/iotex2018.php?hostname=raspberrypi&time=2018/11/20T23:28:00&experiment_id=IoTeX2018&essid=Wired&temp=17.40&humi=56.79&dp=8.74&pres=102261.33&bmptemp=17.70&objtemp=17.85&dietemp=17.19&lux=0.00"
  "INSERT INTO iotex2018 (hostname,time,temp,temp2,temp3,humi,humi2,humi3,\n    dp,dp2,dp3,bmptemp,dietemp,lux,objtemp,pres) values( \"raspberrypi\",\"2018/11/20T23:28:00\",17.40,null,null,56.79,null,null,8.74,null,null,17.70,17.19,0.00,17.85,102261.33 )"
  "INSERT INTO iotex2018_hosts VALUES(\"10.52.2.47\",\"raspberrypi\",\"2018/11/20T23:28:00\",\"Wired\") ON DUPLICATE KEY UPDATE ip=\"10.52.2.47\",time=\"2018/11/20T23:28:00\",essid=\"Wired\""
  ...(略)...
  #<Process::Status: pid 29939 exit 0>
  ...(後略)...

メッセージをよく見て, エラーが出ていないことを確認すること. SQL 文が出力されていることからわかるように, 送られたデータはサーバ上で MySQL に格納される.

可視化

MySQL に保管されたデータからグラフを作るのには grafana を用いる. 前期のデータベース技術で用いた grafana サーバ <URL:http://sky.epi.it.matsue-ct.jp:3000> を用いる. もしパスワードを忘れた場合は, "Forgot your password?" をクリックすれば パスワードを再設定するための URL がメールで送られてくる.

データベース IoTeX には以下のテーブルが存在する.

テーブル: iotex2018
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| hostname | varchar(20) | NO   | PRI | NULL    |       |  ホスト名
| time     | datetime    | NO   | PRI | NULL    |       |  時刻
| temp     | double      | YES  |     | NULL    |       |  温度
| temp2    | double      | YES  |     | NULL    |       |  温度 (2 台目)
| temp3    | double      | YES  |     | NULL    |       |  温度 (3 台目)
| humi     | double      | YES  |     | NULL    |       |  湿度
| humi2    | double      | YES  |     | NULL    |       |  湿度 (2 台目)
| humi3    | double      | YES  |     | NULL    |       |  湿度 (2 台目)
| dp       | double      | YES  |     | NULL    |       |  露点温度 
| dp2      | double      | YES  |     | NULL    |       |  露点温度 (2 台目)
| dp3      | double      | YES  |     | NULL    |       |  露点温度 (3 台目)
| bmptemp  | double      | YES  |     | NULL    |       |  温度 (bmp180)
| dietemp  | double      | YES  |     | NULL    |       |  温度 (tmp007)
| lux      | double      | YES  |     | NULL    |       |  照度
| objtemp  | double      | YES  |     | NULL    |       |  放射温度 (tmp007)
| pres     | double      | YES  |     | NULL    |       |  圧力
| winddir  | int(11)     | YES  |     | NULL    |       |  風向
| windvel  | double      | YES  |     | NULL    |       |  風速
+----------+-------------+------+-----+---------+-------+

テーブル: iotex2018_hosts
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| ip       | varchar(15) | YES  |     | NULL    |       |  IP
| hostname | varchar(20) | NO   | PRI | NULL    |       |  ホスト名
| time     | datetime    | YES  |     | NULL    |       |  時刻
| essid    | varchar(20) | YES  |     | NULL    |       |  無線 LAN SSID
+----------+-------------+------+-----+---------+-------+

テーブル iotex2018 の temp (温度), humi (湿度), dp (露点温度) のグラフや, テーブル iotex_hosts の ip (IP), ホスト名 (hostname), essid (SSID) を grafana で表示せよ (→ 課題). 作ったダッシュボードは自分の学生番号のフォルダに入れること.

grafana の使い方は J4 前期 DB 技術の資料 <URL:./grafana.pdf> を参照のこと.

cron での実行

先のデータ送信スクリプト (monitoring) を起動時に実行するように変更する.

cron の設定を行う前に, スクリプト monitoring が標準出力に何も出さないように変更する. データ送信スクリプト (monitoring) 中の "p " で始まる行をコメントアウトする.

$ vi iotex-sensor/bin/monitoring

  # p date  (該当行はたくさんある)

cron の設定を行う. 以下のように書き換える. 書き換えた後に再起動する.

$ crontab -e

   # m h  dom mon dow   command
   MAILTO=""
   PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
   @reboot ./iotex-sensor/bin/monitoring

$ sudo reboot

再起動後に自動的にスクリプトが実行されるはずである. ps aux コマンドを実行し, 以下のようにスクリプト monitoring が実行されていることが確認できれば良い.

$ ps aux | grep monitoring

  hogehoge 31768  5.4  0.7  25028  7016 pts/1    Sl   01:33   0:00 ruby ./iotex-sensor/bin/monitoring

また, grafana のダッシュボードを開き, データが増えていることを確認すること.

ラズパイをセンサー化するための追加設定 (1) : ディスプレイの出力設定

ラズパイは起動してすぐに HDMI で接続された機器とネゴシエーションを行い, その結果に基づいて画面表示を開始する. ネゴシエーションに失敗すると コンポジット(いわゆるビデオ信号)での表示となる. そのため, ラズパイを起動した後に HDMI ディスプレイを接続しても画面に何も映らないことになる. ラズパイを用いたセンサーは, 普段はディスプレイを接続する必要はないが, トラブルシューティングの際にディスプレイが必要となる. 今回はディスプレイの出力を HDMI 出力を固定することにする.

$ sudo -s 
# cd /boot
# cp config.txt  config.txt.bk   (バックアップ) 

# vi config.txt

  # uncomment if hdmi display is not detected and composite is being output
  hdmi_force_hotplug=1    (コメントアウトを外す)

  # uncomment to force a specific HDMI mode (this will force VGA)
  hdmi_group=1    (コメントアウトを外す)
  hdmi_mode=4     (コメントアウトを外し, 値を 4 にする)

# reboot

hdmi_force_hotplug=1 をすることで, 強制的に HDMI から出力することができる. また, 上記は hdmi_group=1 と hdmi_mode=4 とすることで, 解像度を 720p60 (1280x760) に固定することができる. 解像度に関する設定は以下を参考にすること. <URL:https://www.raspberrypi.org/forums/viewtopic.php?f=5&t=5851>

再起動後に HDMI ケーブルを抜き差しせよ. 設定がうまくいっていれば, HDMI ディスプレイに再びデスクトップ画面が映る.

ラズパイをセンサー化するための追加設定 (2) : SD カードへの書き込みの抑制

ラズパイの SD カードに常時頻繁に書き込みを行うと, SD カードが壊れることがある. 2016, 2017 年度の IoT 演習では, 10 秒おきにデータをファイル出力したところ, 稼働開始から数ヶ月で SD カードが壊れる事態が頻発した. また, ラズパイをセンサーとして運用していると電源ケーブルを抜き差しして ラズパイを再起動したくなることがあるが, SD カードの読み書き中に電源を切ると SD カードが壊れることがある.

そこで SD カードへの書き込みしないようにする. overlayfs を用いることで, Readonly な下の層 (この場合は SD カード) と, Writable な上の層 (この場合はメモリー) を重ね合わせ 1 つのファイルシステムに見せることができる. データの書き出しは全てメモリ上に行われるので, 例え電源が抜き差ししても SD カードが壊れることはない.

実装の仕方は色々あるが, 今回は導入やメンテナンスが簡単な root-ro (Read-only Root-FS with overlayfs for Raspian) を用いる. 以下の作業は root-ro の README に基づいている.

root-ro の取得

root-ro は GitHub から入手する. それ以外は raspbian のパッケージを用いる (本演習では第 1 週目に, rsync, git, gawk, busybox, bindfs をインストール済み).

$ sudo -s 

# git clone https://github.com/josepsanzcamp/root-ro.git

swap 領域の無効化

まずは swap 領域を無効にして SD カードへの退避書き込みを無くす. swap はメモリ不足の時にディスクをメモリ代わりに使うものである. 今回はデータを全てメモリ上に置くので, swap を使う意味がない.

まずはメモリと swap の状態を確認する. swap が 100 MB あることがわかる.

# free
               total       used       free     shared    buffers     cached
  Mem:        947732     745712     202020      49428     167380     332228
  -/+ buffers/cache:     246104     701628
  Swap:       102396          0     102396

swap 領域の無効化を行う.

# dphys-swapfile swapoff

# dphys-swapfile uninstall

# update-rc.d dphys-swapfile disable

# systemctl disable dphys-swapfile

  dphys-swapfile.service is not a native service, redirecting to systemd-sysv-install.
  Executing: /lib/systemd/systemd-sysv-install disable dphys-swapfile

swap 領域が無効化されたことを確認する. 以下のように Swap の total が 0 になっていれば良い.

# free
                total        used        free      shared  buff/cache   available
  Mem:         949580      113572      499352       16012      336656      765948
  Swap:             0           0           0

root-ro の設定

GitHub から入手した root-ro のファイル群をシステム領域にコピーし, initramfs を作成し, 設定ファイル (/boot/config.txt) に修正を加える.

# rsync -va root-ro/etc/initramfs-tools/* /etc/initramfs-tools/

  sending incremental file list
  modules
  hooks/
  hooks/root-ro
  scripts/
  scripts/init-bottom/
  scripts/init-bottom/root-ro

  sent 10,494 bytes  received 93 bytes  21,174.00 bytes/sec
  total size is 10,130  speedup is 0.96

# mkinitramfs -o /boot/initrd.gz

# echo initramfs initrd.gz >> /boot/config.txt   (起動時に必要な設定をファイル末尾に書き込む)

再起動

# reboot

再起動後にホームディレクトリにファイルを作成してみる.

できるはずである. 存在することを確認したら, 再びラズパイを再起動せよ.

$ touch test.txt

$ ls -l test.txt 

  -rw-r--r-- 1 hogehoge hogehoge 0 11月 20 17:23 test.txt

# reboot

再起動した直後, ホームディレクトリに test.txt が存在しないことを確認せよ. このように新たなデータは全てメモリ上に保管されるので, 再起動するとそれらのデータは全て失われる.

$ ls -l test.txt

  ls -l test.txt
  ls: 'test.txt' にアクセスできません: そのようなファイルやディレクトリはありません

参考: SD カードを再び書き込み可能にする方法

SD カードに書き込みする場合には, ルートのファイルシステムを rw (read write) でマウントし直して, 設定ファイル (/boot/config.txt) を元に戻す. 但し, 絶対パスが /mnt/boot-ro/config.txt になることに注意せよ.

$ sudo mount -o remount,rw /mnt/boot-ro

$ sudo vi /mnt/boot-ro/config.txt

  # initramfs initrd.gz  (末尾の命令をコメントアウトする)

$ sudo reboot

再び SD カードに書き込みできない状態に戻すには, 設定ファイル (/boot/config.txt) の末尾の命令を有効にして再起動する.

$ sudo vi /boot/config.txt

  initramfs initrd.gz  (コメントアウトを外す)

$ sudo reboot

課題

  • I2C センサーの利用について, 以下を行なった結果のスナップショットを提出せよ (ターミナル上でコマンドを実行し, 以下のコマンド出力全てが含まれるスナップショットを得ること).
    • i2cdetect -y 1 コマンドの出力. 3 種類のセンサーが全て接続されていることがわかるようにすること.
    • 3 種類のセンサ (bmp180, tmp007, tsl2561) で取得したデータ. データ取得には, 教員 (sugiymki) の github のスクリプトを使うこと.
  • zabbix で自分のラズパイの状況を表示し, そのスナップショットを提出せよ. さらに, このページに何が表示されているか・表示内容から何が読み取れるかをオンラインテキストにまとめよ.
  • SD カードへの書き込み抑制 (overlayfs の利用) を行う前後での df -h コマンドの出力結果をオンラインテキストにまとめよ. さらに df コマンドによって何が出力されるか・出力から何がわかるかを調べてまとめよ.
  • SD カードへの書き込み抑制 (overlayfs の利用) を行った後, free コマンドを実行し, その出力結果をオンラインテキストにまとめよ. さらに free コマンドによって何が出力されるか・出力から何がわかるかを調べてまとめよ.
  • grafana のダッシュボードを作成する. テーブル iotex2018 のデータ (気温・湿度・露天温度) から作成したグラフと, テーブル iotex2018_hosts のデータ (IP, ホスト名, 無線 LAN SSID を, ダッシュボード上に表示せよ. 作成したダッシュボード画面のスナップショットを提出せよ.