センサからリアルタイムデータを取得する
はじめに
マイクロコントローラのボードは通常小さいセンサおよびパソコンの両方と通信することができ,WiFiを介して通信できることもある.そのため,センサから実際のデータを取得するのに,センサとコンピュータとの直接のインターフェースがない場合に便利である.
このプロジェクトでは,Arduino Yunマイクロコントローラボードを使い,MPU-6050センサからWolfram Data Dropリポジトリにデータを流す.MPU-6050は3軸加速度計,3軸ジャイロスコープ,および温度センサを搭載したI2Cデバイスである.Arduino YunボードはWiFiインターフェースからデータをアップロードする.マイクロコントローラはセンサを初期化し,そこからデータを取得し,リポジトリにデータをアップロードするようにプログラムされる.これでリアルタイムデータにリポジトリからアクセスできるようになる.
電気配線
I2C
まずマイクロコントローラがMPU-6050センサからデータを受信するように設定する.
MPU-6050のI2Cアドレス.
addr = "0x68";データシートから,加速度計3つ,サーモスタット1つ,ジャイロスコープ3つの測定値は,アドレス0x3Bからそれぞれ2バイトで保存されることが分かる.そのためマイクロコントローラは全部で14バイト読み取る必要があるが,最後の測定値以外は,読み取った後に確認を送信する.
i2cread = Join[{"START", "0x3B", "START"}, Sequence@@Table[{"READ", "ACK"}, {13}], {"READ", "STOP"}]センサもデータを送信する前に初期化する必要がある.
i2cinit = "Initialization" -> {"START", "0x6B", "0x0", "STOP"};センサのすべてのI2C指定.
i2cspecs = addr -> {i2cread, i2cinit};加速度と角速度は2の補数値として送信される.2の補数値から10進数に変換するユーティリティを作成する.
Needs["SymbolicC`"]
co = COperator;
ca = CAssign;
a[rhs_] := ca[rhs, co[BitOr, {co[BitShiftLeft, {"hbyte", 8}], "lbyte"}]];from2C = CFunction["double", "twosC_To_D", {{"uint8_t", "hbyte"}, {"uint8_t", "lbyte"}}, {CDeclare["double", "d"], CDeclare["uint16_t", a["sxtnBit"]],
CIf[co[BitAnd, {"hbyte", "0x80"}], {ca["sxtnBit", co[BitXor, {"sxtnBit", "0xFFFF"}]], co[Increment, "sxtnBit"], ca["d", co[Times, {-1.0, "sxtnBit"}]]}, ca["d", co[Times, {1.0, "sxtnBit"}]]], CReturn["d"]}];ToCCodeString[from2C]//StringTrimutils = {from2C};このような変換が必要かどうかに基づいてすべての測定値を扱う2つ目のマスタユーティリティ.
from2B = CFunction["double", "sxtnb_To_D", {{"uint8_t", "hbyte"}, {"uint8_t", "lbyte"}, {"uint8_t", "i"}}, {CDeclare["double", "d"], CIf[co[Equal, {"i", 3}], a["d"], ca["d", CCall["twosC_To_D", {"hbyte", "lbyte"}]]], CReturn["d"]}];ToCCodeString[from2B]//StringTrimAppendTo[utils, from2B];マスタユーティリティ関数は14バイトを7つの10進数値に変換するのに使われる.
MapIndexed[(#1[Repeated[_, 2 #2 - 2], byte1_, byte2_, ___] := CCall["sxtnb_To_D", {byte1, byte2, #2 - 1}])&, {aX, aY, aZ, T, wX, wY, wZ}];Grid[Table[{f, ToCCodeString[f@@Table["b" <> ToString@i, {i, 0, 13}]]}, {f, {aX, aY, aZ, T, wX, wY, wZ}}], Background -> {None, {{LightBlue, White}}}, Frame -> All]7つの値は同じデータ線SDAから取得するが,これはArduino Yunの2番ピンである.
ics = Table["2" -> <|"Type" -> "I2C", "SlaveAddress" -> "0x68", "Conversion" -> fn|>, {fn, {aX, aY, aZ, T, wX, wY, wZ}}];ics//Length10進数値から単位を加速度はm/s2に,温度は°Cに,角速度はrad/sに変換するモデル.
sys = NonlinearStateSpaceModel[{{}, {u1 * (9.8 / 16384.), u2 * (9.8 / 16384.), u3 * (9.8 / 16384.),
36.53 + u4 / 340.0, u5 * (3.14 / (131 * 180)), u6 * (3.14 / (131 * 180)), u7 * (3.14 / (131 * 180))}},
{}, {{u1, 0}, {u2, 0}, {u3, 9.8}, {u4, 0}, {u5, 0}, {u6, 0}, {u7, 0}},
SamplingPeriod -> 0.1]データビン
データビンを作成し,ArduinoのBridgeライブラリを使ってデータをWolfram Data Dropリポジトリにアップロードする出力チャンネルを設定する.
データビンを作成する.
bin = CreateDatabin[<|"Name" -> "mpu6050"|>]データビンに値をアップロードするために必要なBridgeライブラリの場所.
bridgeLib = FileNameJoin[{"/Applications", "Arduino.app", "Contents", "Java", "libraries", "Bridge", "src"}];ヘッダファイル,ユーティリティ,初期化コード.
i = {"Bridge.h"};
AppendTo[utils, "Process p"];
inits = {"USBDevice.attach()", "Bridge.begin()", "double val"};データビンにデータを加えるRESTful API コード.
ocs = Table[<|"Type" -> "ExternalLibrary", "Loop" -> {"val", "p.begin(\"curl\")", "p.addParameter(\"--insecure\")", "p.addParameter(\"--location\")", "p.addParameter(\"https://datadrop.wolframcloud.com/api/v1.0/Add?bin=" <> bin[[1]] <> "&" <> m <> "=\"+String(val))", "p.run()"}|>, {m, {"ax", "ay", "az", "tp", "wx", "wy", "wz"}}];データの最初の項目をアップロードするコードスニペット.
ocs[[1]]["Loop"]//ToCCodeStringコードの埋込み
パッケージをロードする.
Needs["MicrocontrollerKit`"]BridgeライブラリによってArduinoのコアライブラリが使用されるので,これをタイマとCDC機能としても使用する.
μc = <|"Target" -> "ArduinoYun", "Inputs" -> ics, "Outputs" -> ocs, "IncludeFiles" -> i, "Initializations" -> inits, "Utilities" -> utils, "Timer" -> "delay", "CDC" -> None|>;マイクロコントローラがデータの送受信を行うためには,MPU-6050 I2CデバイスとBridgeライブラリの指定が必要である.実行には影響のないコンパイラ警告は出力されないようにするために「-w」を使用する.
ℳ = MicrocontrollerEmbedCode[sys, μc, "/dev/tty.usbmodem1411", <|"I2C" -> i2cspecs, "Libraries" -> bridgeLib, "CompileOptions" -> {Automatic, "-w"}|>]データの可視化
加速度と角速度のデータをプロットする関数を作成する.
plotTuple[v_] := Module[{keys, legnds},
{keys, legnds} = Table[{v <> s, Subscript[v, s]}, {s, {"x", "y", "z"}}];ListLinePlot[ToExpression[Lookup[Values[bin], keys]], PlotLegends -> legnds, PlotTheme -> "Detailed", PlotRange -> All]]加速度,角速度,温度のデータを可視化する.
gridOpts = Sequence[Frame -> All, FrameStyle -> LightGray];Grid[{{Grid[{{plotTuple["a"]}, {plotTuple["w"]}}, gridOpts], ThermometerGauge[ToExpression[Last@Lookup[Values[bin], "tp"]], {0, 100}, GaugeLabels -> "Unit", TargetUnits -> "°C"]}}, gridOpts]以上,センサからI2Cデータを取得し,それをWolfram Data Dropリポジトリのデータビンにアップロードし,データビンの値を可視化する方法を示した.
発展
- データを可視化して解析する他の方法について調べる.
- データを平坦化するフィルタを実装する.
- チャンネルフレームワークを使ってデータを送信する.
- 仮想COMポートを使ってデータをコンピュータに直接送る.