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メソッドから呼び出すことにより解決しました。