Node.jsでWindows 10 IoT Coreのセンサーを使う
いやぁ…私がこのブログでJavaScriptとかNode.jsの事を書く時代が来るとはね…
Raspberry PI2で動く、Windows 10 IoT Coreでは、C#、VB、VC++に加えて、Node.js、PythonでUniversal Windows Applicationの開発が可能です。
Node.jsを使うには、https://ms-iot.github.io/content/en-US/win10/samples/NodejsWU.htm で紹介されているように、Visual Studio 2015 RC に IoT Core用のMSIツールをインストール後、追加で、NTVS(Node.js Tools for Visual Studio)Bundle VS2015を更にインストール。
このツールを使うと、Node.js用のプロジェクトテンプレートが出現します。
プロジェクトの作成は、
と、プロジェクトテンプレートで、カテゴリを”JavaScript”→”Node.js”を選択して表示されたテンプレートの”(Windows Universal)”と名前の後ろについているテンプレートを使います。
npmを使うには、ソリューションエクスプローラーで、プロジェクト直下のnpmアイコンを右クリックして、”Install New npm Packages... を選択すれば、所望のパッケージをインストール可能です。
更に、実機(例えば、Raspberry PI2)で動かすには、ソリューションエクスプローラーでプロジェクトを右クリックし、”プロパティ”を選択し、表示されたページの、”Remote Machine”の項目にWindows IoT CoreデバイスのIPアドレスを入力すればOK。
では、センサーのデータを取得するJavaScriptコードをお見せしましょう。センサーは、加速度センサーのADXL345を使います。https://ms-iot.github.io/content/en-US/win10/samples/I2CAccelerometer.htm や、私の以前のポストを参照して、配線してください。
おっと、元々私は、JavaScriptやNode.jsはまるっきり素人なので、どれぐらい素人かというと、Node.jsがサーバーサイド向けのライブラリだと知ったのがこれを書いているつい最近(でもNode.jsと知らないうちから使ってはいましたが)知ったというぐらい、素人です。だから、「普通JavaScriptだったら、そんな風に書かねぇよ」とかいう方がいたら、「この方が楽よ」と、コメント頂ければ幸い。
現状のサンプルには、Node.jsでI2Cセンサーを使うサンプルは公開されていないのと、ま、私がジャバスク素人で普段はC#使いでもあるので、ロゼッタストーン的にC#と並べて、紹介することにします。早速ロゼッタストーンです。
C# | JavaScript Node.js |
string aqs = I2cDevice.GetDeviceSelector("I2C1");var dis = await DeviceInformation.FindAllAsync(aqs); var settings = new I2cConnectionSettings(0x53);I2CAccel = await I2cDevice.FromIdAsync(dis[0].Id, settings); byte[] WriteBuf_DataFormat = new byte[] { 0x31, 0x01 };byte[] WriteBuf_PowerControl = new byte[] { 0x2d, 0x08 };I2CAccel.Write(WriteBuf_DataFormat);I2CAccel.Write(WriteBuf_PowerControl); |
// Universal Windows Platform 用パッケージの取得var uwp = require("uwp");uwp.projectNamespace("Windows"); // メンバー名は最初の文字が小文字にvar aqs = Windows.Devices.I2c.I2cDevice.getDeviceSelector("I2C1");var i2cAccel = null; // 非同期のawait は、done(func(result){...});で受けるWindows.Devices.Enumeration.DeviceInformation.findAllAsync(aqs).done(function (dis) { var settings = new Windows.Devices.I2c.I2cConnectionSettings(0x53); settings.BusSpeed = Windows.Devices.I2c.I2cBusSpeed.FastMode; var disI2C; for (var i=0; i < dis.length; i++) { if (dis[i].id.indexOf("I2C1") != -1) { disI2C = dis[i]; break; } } Windows.Devices.I2c.I2cDevice.fromIdAsync(disI2C.id, settings).done( function (i2cdev) { i2cAccel = i2cdev; var writebuf_dataFormat = [0x31, 0x01]; var writebuf_powerControl = [0x2d, 0x08]; i2cAccel.write(writebuf_dataFormat); i2cAccel.write(writebuf_powerControl); });}); |
左と右を見比べるとだいたいパターンは判りますね?JavaScript側は名前空間込なのでちょっと文字が多めに見えますね。DeviceInformationクラスのfindAllAsyncメソッドは、C#の場合には戻り値として1項目だけ返ってくるのに対し、2015年6月中旬時点では、JavaScriptは(多分)全部のデバイス情報が返ってきてしまうので(多分不具合)、I2C1という文字列を持っている項目を検索してます。
加速度情報の取出し部分は、
C# | JavaScript |
byte[] RegAddrBuf = new byte[] { 0x32 };byte[] ReadBuf = new byte[6];I2CAccel.WriteRead(RegAddrBuf, ReadBuf); short rx = BitConverter.ToInt16(ReadBuf, 0);short ry = BitConverter.ToInt16(ReadBuf, 2);short rz = BitConverter.ToInt16(ReadBuf, 4);double accelX = (double)rx / (1024.0/8.0);double accelY = (double)ry / (1024.0/8.0);double accelZ = (double)rz / (1024.0/8.0); |
var readbuf_addr = [0x32];var readbuf_rcvd = [0, 0, 0, 0, 0, 0];i2cAccel.writeRead(readbuf_addr, readbuf_rcvd);var rx = readbuf_rcvd[0] + (readbuf_rcvd[1] << 8); var ry = readbuf_rcvd[2] + (readbuf_rcvd[3] << 8);var rz = readbuf_rcvd[4] + (readbuf_rcvd[5] << 8);if ((rx & 0x80) != 0) { rx = rx | 0xffff0000;}if ((ry & 0x80) != 0) { ry = ry | 0xffff0000;}if ((rz & 0x80) != 0) { rz = rz | 0xffff0000;} var ax = rx /( 1024.0 / 8.0);var ay = ry / (1024.0 / 8.0);var az = rz / (1024.0 / 8.0); |
WriteReadメソッドを0x32という1バイトでコールすると、X、Y、Z方向の加速度の値が2バイトずつ入って返ってきます。これそれぞれ符号付の16ビット整数なので、C#の場合はBitConverterというクラスを使って変換をかけてます。JavaScriptでこのクラスに相当するものを知らなかったので、ここでは、ビットシフトや論理和演算で書いてます。もっとスマートな書き方ご存知の方、教えてくれるとありがたい。
最後に1024.0/8.0で割っているのは、返ってくるのがこの値で割り算すると、地球の重力を基準にした値が得られるから。
こんな感じで、C#のサンプルを置き換えていけば、JavaScript、Node.jsでもコードが書けるはず。インテリセンスが利かないのと、JavaScript不慣れなため、ちゃんと動くコードを作るのにかなり時間がかかりました。インテリセンスが利いて、ある程度デファクトのパッケージやライブラリ知っていれば、そこそこ私にも書けそう。
他に、”request”パッケージを使うと、HTTP REST APIへのアクセスはかなりシンプルに書けることはわかりました。
言語の選択は適材適所で。