センサモジュール単体でのデータの取り込み方法
センサモジュールにあらかじめ搭載されたセンサ(オンボードI2Cで接続)のデータを読み込む方法について説明します。
①センサモジュールのディップスイッチをMode-Dに設定し、電源を再投入します。
②予め接続するPCにターミナルソフト(WIN:teraterm, LINUX系:gtkterm等)をインストールしておきます。
通信コンディションは以下の通りです。
- ポート:お使いの環境に合わせてください
- 通信速度:1000000bps(1Mbps)
- データ:8 bit
- パリティー:none
- USBケーブル(micro USB)を用いて、パソコンと接続します。
③USBケーブルでセンサモジュールとPCを接続します。
センサモジュールには、プログラムはプリインストール(HPでも提供)されおり、USB接続(電源投入)と同時に計測が始まります。
ターミナルソフトのモニター画面に計測データが順次表示されることを確認します。図3.1にターミナルソフト(windowsPC上)の出力例を示します。文字化けなどせずにデータが正しく表示されたら、接続確認終了です。
図3.1 ターミナルソフト(TeraTerm)の出力例
この後は、PC内でプログラムを記述することで、シリアルポートからデータを読み込むことが出来ます。ロボットの制御等、リアルタイムフィードバックデータとしてお使いください。参考例として、python3で記述した例を示します。センサボード上に搭載した環境センサ(BME860)の温度、湿度、気圧、ガスのデータを読み込み、リアルタイムでグラフ表示します。以下に、グラフ表示の例とそのプログラムを示します。
#
# preMSMからデータを読込み、表示するプログラム
# インタラクティブ表示可能版 グラフ縦表示版
# Coding at
# Ver 0.01: 2021/07/11
#
import serial
import json
import numpy as np
import matplotlib.pyplot as plt
# メイン処理
def main():
# 定数設定
COM = "/dev/ttyUSB0" # シリアルポート名
BaudRate = 1000000 # Baud Rate
loop = 2000 # データ取り込み回数
sens_name = 'BME680' # 取得センサーの名称
data_name = ['temp', 'humid', 'press', 'gas'] # 取得するデータの名称
unit = ['[deg]', '[%]', '[hPa]', '[IAQ]'] # y軸の単位を設定
color = ['r', 'g', 'b', 'm'] # 線の色を設定
ymin = [0, 30, 800, 0] # グラフY軸の最小値
ymax = [50, 100, 1300, 100] # グラフY軸の最大値
data_num = 100 # 表示用データ取得数
# 開始処理
# グラフ表示用データ領域確保
t = np.zeros(data_num) # 時間
data = np.zeros(len(data_name)*data_num).reshape(len(data_name), data_num)
plt.ion() # グラフ表示のインタラクティブモード許可
# グラフ表示画面設定
fig, axes = plt.subplots(len(data_name), 1, figsize=(14, 10), sharex=True)
graph_title = "preMSM Output (sensor : " + sens_name + ")"
fig.suptitle(graph_title, fontsize=14)
# グラフ表示情報をまとめる
p_info = {"data_name":data_name, "unit":unit, "color":color, "ymin":ymin, "ymax":ymax}
get_info_num = 0 # 取得した情報数
print("Open Port") # シリアル通信オープン
with serial.Serial(COM, BaudRate) as ser:
# データの読込みループ
for ln in range(loop):
try:
line = ser.readline() # preMSMのデータを1行読込み
dict_data = json.loads(line) # JSON形式を辞書型に変換
info = get_info(dict_data, sens_name, data_name) # 辞書データから対象データを取得
if info != False: # 対象のデータがあったら
t, data = update_data(t, data, info, data_name) # グラフ表示用データの更新
get_info_num += 1 # データ取得回数インクリメント
print('Getting data : ', get_info_num, ' / ', ln) # 取得したデータの回数表示
Plot_data(t, data, p_info, fig, axes) # グラフ表示
except KeyboardInterrupt:
break
# 終了処理
print("Close Port") # シリアル通信クローズ
# グラフの表示
def Plot_data(t, data, p_info, fig, axes):
color = p_info['color'] # 線の色を設定
unit = p_info['unit'] # y軸の単位を設定
kword = p_info['data_name'] # データの名称
ymin = p_info['ymin'] # Y軸の最小値
ymax = p_info['ymax'] # Y軸の最大値
one_dimension_axes = axes.ravel() # for文を使うために、1次元配列に変換
for i, ax in enumerate(one_dimension_axes):
line, = ax.plot(t, data[i], color=color[i], linewidth=1) # データを表示
ax.set_xlim(min(t), max(t)) # X軸の設定
ax.set_ylim(ymin[i], ymax[i]) # Y軸の設定
if i == len(kword) - 1:
ax.set_xlabel('Time', fontsize=10) # X軸の表記
ax.set_ylabel(kword[i]+unit[i]) # Y軸の表記
title = kword[i] +": "+ str(data[i][-1]) + " " + unit[i] # 最新データも表示
ax.set_title(title) # タイトルの表記
fig.canvas.draw()
fig.canvas.flush_events()
# グラフ表示用データ更新
def update_data(t, data, info, kword):
buf = np.zeros(len(kword)) # 一時バッファの作成
t = np.append(t, info['timestamp']) # 時間情報の追加
t = np.delete(t, 0) # 古いデータの削除
for i in range(len(kword)): # リストのデータの取り出し
buf[i] = info[kword[i]]
buf = buf.reshape(len(kword), 1) # データの追加準備(行と列の変換)
data = np.append(data, buf, axis=1) # データの追加
data = np.delete(data, 0, axis=1) # 古いデータの削除
return (t, data)
# preMSMから所得したデータから時刻と数値データを取得
def get_info(data, sname, kword):
if data['sensor'] == sname: # センサーの名称が一致したら
local_dict = {'timestamp': data['timestamp']} # 時刻を取り出す
for i in range(len(kword)): # リストのデータを取り出す
local_dict.update({kword[i] : data[kword[i]]['val']})
return(local_dict) # 作った辞書型データを返す
else:
return False # センサーの名称が一致しなかった
if __name__ == "__main__":
main()
通信中にはセンサモジュールのLEDが点滅しています。
通信が途絶えるなどの異常時には、WDT(Watch Dog Timer)によりセンサモジュールは自動的に再起動します。
そのため、データの先頭にあるタイムスタンプは元に戻ります。リアルタイムフィードバック系では、このタイムスタンプを使用することは稀だと思いますが、後述するIoT系のデータ処理の際には、時系列の解析などタイムスタンプに注目する用途が多いので、データ処理の際にはご注意ください。長時間連続稼働の場合も、カウンターが一周すると元に戻ります。