Raspberry PiでNode.jsを動作させ、Node.js上でSensorTagの、加速度計、ジャイロスコープ、磁力計の各センサー情報を受け取り、受け取ったセンサー情報を、WebSocketを用いて、PCで動作しているUnityに入力データとして転送します。
Node.js上でのSensorTagのセンサー情報の入力は、「node.js環境でのSensortagの情報の読み出し 」を参考にしてください。
UnityでWebSocketによるデータの受け渡しは、以前作成したwebsocket-sharp を使用しました。詳細については、「UnityとRaspberry Pi間でWebSocket通信 」に示します。
SensorTagの加速度計、ジャイロスコープ、磁力計の入力ソフト
RaspberryPiでこのソフト「unity.js」を動作します。UnityからWebSocketにより接続を受け取ると、SensorTagのセンサー情報の収集を開始します。まず、SensorTagを起動して接続を行います。接続が完了するとそれぞれのセンサーをアクティブにして、以降5秒ごとに各センサ値を読み出して、WebSoketを用いてUnityにセンサ値を転送します。
具体的には、受け取ったセンサー情報を変数SensorDataに保存し 、sendメソッドを用いてUnityに転送しています。
unity.js
var WebSocketServer = require('ws').Server, wss = new WebSocketServer({port: 8125}); var util = require('util'); var async = require('async'); var SensorTag = require('./index'); var SensorData = ''; wss.on('connection', function(ws) { ws.send('Start SensorTag'); SensorTag.discover(function(sensorTag) { sensorTag.on('disconnect', function() { console.log('disconnected!'); process.exit(0); }); console.log('connectAndSetUp'); sensorTag.connectAndSetUp(function() { console.log('enableAccelerometer'); sensorTag.enableAccelerometer(function() { console.log('enableMagnetometer'); sensorTag.enableMagnetometer(function() { console.log('enableGyroscope'); sensorTag.enableGyroscope(function() { setInterval(function() { async.series([ function(callback) { console.log('readAccelerometer'); sensorTag.readAccelerometer(function(error, x, y, z) { console.log('\tkx = %d G', x.toFixed(1)); console.log('\ty = %d G', y.toFixed(1)); console.log('\tz = %d G', z.toFixed(1)); SensorData = 'Accelerometer x:' + x.toFixed(1) + ' y:' + y.toFixed(1) + ' z:' + z.toFixed(1); callback(); }); }, function(callback) { console.log('readMagnetometer'); sensorTag.readMagnetometer(function(error, x, y, z) { console.log('\tx = %d μT', x.toFixed(1)); console.log('\ty = %d μT', y.toFixed(1)); console.log('\tz = %d μT', z.toFixed(1)); SensorData += ' Magnetometer x:' + x.toFixed(1) + ' y:' + y.toFixed(1) + ' z:' + z.toFixed(1); callback(); }); }, function(callback) { console.log('readGyroscope'); sensorTag.readGyroscope(function(error, x, y, z) { console.log('\tlx = %d °/s', x.toFixed(1)); console.log('\ty = %d °/s', y.toFixed(1)); console.log('\tz = %d °/s', z.toFixed(1)); SensorData += ' Gyroscope x:' + x.toFixed(1) + ' y:' + y.toFixed(1) + ' z:' + z.toFixed(1); ws.send(SensorData); callback(); }); }] ); }, 1000*5); }); }); }); }); }); });
UnityでSensorTagからのセンサー値を受け取るソフト
このソフトは、PCで動作するUnityのオブジェクトの入力データとしてセンサー情報を受け取るソフトです。Unityのプログラムを起動するとStartメソッドが呼ばれます。ここで、受信のイベント処理を登録し、ws.Connectメソッドにより、RaspberryPiに接続しに行きます。RaspberryPiからはセンサー情報は文字列で送られてくるので、受信のイベント処理の中でprintメソッドにより受け取った情報を、consoleウインドウに表示しています。
using UnityEngine; using System.Collections; using WebSocketSharp; public class q1 : MonoBehaviour { private WebSocket ws; // Use this for initialization void Start () { this.ws = new WebSocket("ws://192.168.0.50:8125"); this.ws.OnMessage += (object sender, MessageEventArgs e) => { print(e.Data); }; this.ws.Connect(); } // Update is called once per frame void Update () { rigidbody.MovePosition (new Vector3(Mathf.Sin(Time.time),0,0)); } }
RaspberryPiでのプログラムの実行
作成したunity.jsをnodeコマンドで実行します。次に、Unityのプログラムを実行します。bluetoothのアダプタ「PlanexのBT-Micro4」のドングルが青く光るので、SensorTagの側面のボタンを押すと、「connectAndSetUp」と端末に表示され、以降、次のように、受け取ったセンサ情報のダンプが繰り返されます。
$ sudo node unity.js connectAndSetUp enableAccelerometer enableMagnetometer enableGyroscope readAccelerometer kx = -0.1 G y = 0.3 G z = 4.1 G readMagnetometer x = -78.4 μT y = 35.7 μT z = 62.3 μT readGyroscope lx = -2 °/s y = 2.1 °/s z = -0.5 °/s readAccelerometer kx = -0.1 G y = 0.3 G z = 4.1 G readMagnetometer x = -78.5 μT y = 35.8 μT z = 62.3 μT readGyroscope lx = -2 °/s y = 2.1 °/s z = -0.6 °/s readAccelerometer kx = -0.1 G y = 0.3 G z = 4 G readMagnetometer x = -78.6 μT y = 35.7 μT z = 62.1 μT readGyroscope lx = -2.2 °/s y = 2.2 °/s z = -0.5 °/s . . .
UnityのConsoleウインドウへの表示
RaspberryPiから転送されたSensorTagのセンサー情報を受け取ると、Consoleウインドウに表示されます。
Start SensorTag Accelerometer x:-0.1 y:0.3 z:4.1 Magnetometer x:-78.4 y:35.7 z:62.3 Gyroscope x:-2.0 y:2.1 z:-0.5 Accelerometer x:-0.1 y:0.3 z:4.1 Magnetometer x:-78.4 y:35.7 z:62.3 Gyroscope x:-2.0 y:2.1 z:-0.5Accelerometer x:-0.1 y:0.3 z:4.1 Magnetometer x:-78.5 y:35.8 z:62.3 Gyroscope x:-2.0 y:2.1 z:-0.6 Accelerometer x:-0.1 y:0.3 z:4.1 Magnetometer x:-78.4 y:35.7 z:62.3 Gyroscope x:-2.0 y:2.1 z:-0.5Accelerometer x:-0.1 y:0.3 z:4.1 Magnetometer x:-78.5 y:35.8 z:62.3 Gyroscope x:-2.0 y:2.1 z:-0.6Accelerometer x:-0.1 y:0.3 z:4.0 Magnetometer x:-78.6 y:35.7 z:62.1 Gyroscope x:-2.2 y:2.2 z:-0.5 . .
エラーメッセージ「throw er; // Unhandled ‘error’ event」
このエラーメッセージは、RaspberryPi側で実行しているnode.jsで起こったもので、次のように表示されます。
$ sudo node unity.js events.js:85 throw er; // Unhandled 'error' event ^ Error: listen EADDRINUSE at exports._errnoException (util.js:746:11) at Server._listen2 (net.js:1156:14) at listen (net.js:1182:10) at net.js:1280:9 at dns.js:85:18 at process._tickCallback (node.js:355:11) at Function.Module.runMain (module.js:503:11) at startup (node.js:129:16) at node.js:814:3
原因は、node.jsが動作して終了してない状態で、再度node.jsを起動したときに発生します。従って、次のようにpsコマンドで実行しているunity.jsのプロセスIDを見つけて、killコマンドで削除すれば解決します。
$ ps aux | grep node root 6139 0.0 0.5 4592 2652 pts/0 T 05:23 0:00 sudo node unity.js root 6140 1.7 5.2 41668 23408 pts/0 T 05:23 0:10 node unity.js root 6141 0.0 0.4 3384 1864 pts/0 T 05:23 0:00 /home/pi/node_modules/unity/node_modules/noble-device/node_modules/noble/lib/linux/../../build/Release/hci-ble pi 6168 0.0 0.3 3548 1732 pts/0 S+ 05:33 0:00 grep --color=auto node $ sudo kill -9 6139 [1]+ Killed sudo node unity.js
エラーメッセージ「(node) warning: possible EventEmitter memory leak detected」
このエラーメッセージは、RaspberryPi側で実行しているnode.jsで起こったもので、次のように表示されます。
$ sudo node unity.js (node) warning: possible EventEmitter memory leak detected. 11 discover listeners added. Use emitter.setMaxListeners() to increase limit. Trace at EventEmitter.addListener (events.js:179:15) at Function.constructor.discoverAll (/home/pi/node_modules/unity/node_modules/noble-device/lib/util.js:49:27) at Function.SensorTag.discoverAll (/home/pi/node_modules/unity/lib/sensortag.js:8:19) at Function.SensorTag.discover (/home/pi/node_modules/unity/lib/sensortag.js:24:13) at WebSocketServer.(/home/pi/node_modules/unity/unity.js:9:11) at WebSocketServer.emit (events.js:107:17) at /home/pi/node_modules/ws/lib/WebSocketServer.js:79:14 at completeHybiUpgrade2 (/home/pi/node_modules/ws/lib/WebSocketServer.js:262:5) at completeHybiUpgrade1 (/home/pi/node_modules/ws/lib/WebSocketServer.js:287:13) at WebSocketServer.handleHybiUpgrade (/home/pi/node_modules/ws/lib/WebSocketServer.js:315:3) (node) warning: possible EventEmitter memory leak detected. 11 discover listeners added. Use emitter.setMaxListeners() to increase limit. Trace at EventEmitter.addListener (events.js:179:15) at Function.constructor.discoverAll (/home/pi/node_modules/unity/node_modules/noble-device/lib/util.js:49:27) at Function.SensorTag.discoverAll (/home/pi/node_modules/unity/lib/sensortag.js:9:19) at Function.SensorTag.discover (/home/pi/node_modules/unity/lib/sensortag.js:24:13) at WebSocketServer. (/home/pi/node_modules/unity/unity.js:9:11) at WebSocketServer.emit (events.js:107:17) at /home/pi/node_modules/ws/lib/WebSocketServer.js:79:14 at completeHybiUpgrade2 (/home/pi/node_modules/ws/lib/WebSocketServer.js:262:5) at completeHybiUpgrade1 (/home/pi/node_modules/ws/lib/WebSocketServer.js:287:13) at WebSocketServer.handleHybiUpgrade (/home/pi/node_modules/ws/lib/WebSocketServer.js:315:3) ^Z [1]+ Stopped sudo node unity.js
原因は、Unity側のソフトで、上記に示すws.Connectメソッドが、Updateメソッドで呼び出されていたため、フレームごとにws.Connectメソッドが実行され、WebSocketが大量に作成されてリソースが足りなくなり、警告が発生しました。これは、上記のソースコードに示すように、startメソッドから呼び出すことにより解決しました。