Edited at

AWS IoT/MQTTで3Dをグリグリ動かそうとした話

More than 1 year has passed since last update.


初めに

こんにちは。CYBIRDエンジニア Advent Calendar、19日目のcy-katsuhiro-miuraです。

18日目は@cy-hiroshi-chibaさんの「Amazon QuickSightを試してみる」でした。

QuickSightは僕も試したくてアカウントだけは作ったんですが、そこから先に進めていなかったので、こういう記事はタメになりますね!

そういえば、記事を書き始めて気づきましたが、去年@cy-hiroshi-chibaさんの翌日だったので、僕も2年連続19日目でしたね。


IoT

さて、これからはIoTの時代だそうです。

ネットにそう書いてあったので間違いないようです。

僕も時代にのって、IoTとやらをやってみたい、そう思いました。


構成


構成

+--------+          +--------+          +---------+

| Things |--(MQTT)->| Broker |--(MQTT)->| Browser |
+--------+ Pub +--------+ Sub +---------+

とりあえずこんな構成を考えてみます。

IoTならよくある構成ですね。

ここのThingsには、ArudinoとかRaspberryPiとかがよく使われるようですが、

僕の乏しいお小遣いではとても買えませんし、妻にはおもちゃにしか見えないガジェットの購入申請が通るとも思えません。

しょうがないので、手持ちの資産でなんとかしてみましょう。


9軸センサー

IoTでよくやるのは何かしらのセンサーの情報を取得するとかでしょうか。

例えば、9軸センサー。

重力加速度センサーで、3軸の重力加速度。

回転速度センサーで、3軸のジャイロ。

地磁気センサーで、3軸のコンパス。

これら全部合わせてで9軸。

センサーモジュールであれば、MPU-9250/9150とかがメジャーでしょうか。

Arudinoがあれば、モーションシールドを購入してもいいでしょう。

でも僕にはそういうのはないので、手持ちのiPhoneとJavascriptでどうにかしてみましょう。

重力加速度や回転速度を取得するには、"devicemotion"、コンパスを取得するには"deviceorientation"を利用します。


javascript

window.addEventListener('devicemotion', function(e){

//重力加速度センサー
gravity = e.accelerationIncludingGravity;
gx = gravity.x;
gy = gravity.y;
gz = gravity.z;

//回転速度センサー
rotation = e.rotationRate;
rx = rotation.beta;
ry = rotation.gamma;
rz = rotation.alpha;
}
window.addEventListener('deviceorientation',function(e){
//地磁気センサー
mx = e.beta;
my = e.gamma;
mz = e.alpha;
}


IMG_5995.PNG

サンプル:端末で9dof取得


MQTT Broker

集めた9軸センサー情報をMQTTで送るためには、MQTT Broker Serverが必要ですが、サーバとか立てるとお金かかっちゃいますよね。

そこで、サーバ立てずにすむMQTT Brokerサービスを探してみました。

ニフティクラウド MQTT

今年の3月31日まではβということで無料だったのですが、4月からは有料になってしまいました。

時雨堂 sango

時雨堂さんのMQTTブローカー「Akane」のホスティングサービスです。

ライトプランなら0円!スタンダード・プランでも500円/月!

AWS IoT Message Broker

AWSさんのIoTプラットフォームに対するPub/Sub/メッセージの送受信サービスです。

従量課金の為、使わなければ0円で、初めの1年は無料利用枠が使えます。

まあ、有料でも100万通で6$程なので、僕のお小遣いでもなんとかなる範囲です。

今回は、AWS IoTを使ってみましょう。


AWS IoT

9軸センサーの取得をJavascriptでやってしまったので、MQTT ClientもJavascriptで実装してみます。

とゆうか、クラスメソッドさんの「AWS IoTのMQTT over WebSocketをCognito(Unauth)で認証して使ってみた」をほぼそのまま使いました。

ポイントは、AWS IoTの認証をCognitoを使って一時的なAWS Credentialsで実行してるところ。これでJavascriptのソースを見られても、まあ。

実はsangoもMQTT over WebSocketで使えるんですが、ユーザ名とパスワードをソースに埋め込まないと行けないので、今回はちょっと。

サンプル:Aws IoTにCognitoのUnauth認証使ってMQTT over WebSocket


Publish

上記のサンプルを使って、9軸センサーの情報をPublishしてみます。

サンプル:端末で9dof取得してMQTT over WebsocketでAws IoTにPub


subscribe

さらに送られた9軸センサーの情報を別ブラウザで受けてみます。

数字だけだとちょっとさみしいので、なんとなく重力加速度だけグラフ表示してみました。

スクリーンショット 2016-12-18 21.40.24.png

サンプル:Aws IoTにMQTT接続してSubした9dofデータを表示


完成?

これで、一応完成です。わりとさくっとできてしまいますね。

javascriptで取得してるところをarudinoあたりで実装すれば、それはもうIoT。

AWS IoT SDKには

・Arduino

・組み込みC

・javascript

が用意されているので、お好きなものを使って頂けると良いかと思います。


UnityでMQTT

あれ?って思った方、いらっしゃるかと思います。

そうですね。対応しているSDK少なくね?ってことですね。

実は、単純にMQTTやるだけならもっと全然対応している言語いっぱいあります。

MQTTクライアントで最大手というとpahoでしょうか。

言語毎の対応表を見ると、いっぱいあるので、まあ各自実装してください、ということでしょう。

.Net(C#)のクライアントもちゃんとありますので、UnityでもMQTTできるんじゃないの?ってちょっと思いますよね。

9軸センサーの情報をMQTTでUnityに送って、Unity内部の3Dオブジェクトをグリグリ動かせるんじゃねって?ってちょっと思いますよね。

そうですね。まあ、MQTTだけならなんとかなります。


Unityで AWS IoT

問題はMQTTブローカーがAWS IoTの場合です。

実はAWS IoTはMQTTの場合TLSv1.2しか対応していません。

AWS IoT Hardware Program FAQ


Q. What are different authentication mechanisms for AWS IoT?

Devices/Clients will be able to connect to the IoT service via 4 main authentication mechanisms: MQTT/HTTP via TLS 1.2 Certs (Recommended), HTTP via Sigv4, HTTPS via Cognito or IAM user.


pahoの.Net MQTT Clientはv4.3.0.0でTLSv1.2に対応しているのですが、Unityは.Net3.5準拠でして、TLS1.1、TLS1.2は選択できず、TLS1.0までしかありません。

このため、単純にパッケージを導入してもTLS1.2を使おうとするとビルドエラーになってしまいます。

エラーの原因は.NET Framework 3.5 では TLS1.1 および TLS1.2 が SecurityProtocolType 列挙体に宣言がないためなので、以下のような実装を行えば、ビルドエラーは回避できましたが・・・、きちんと動かすところまで検証できていません。

誰か是非トライしてみてください。(他力本願)


SecurityProtocolTypeExtensions.cs

namespace System.Net

{
using System.Security.Authentication;
public static class SecurityProtocolTypeExtensions
{
public const SecurityProtocolType Tls12 = (SecurityProtocolType)SslProtocolsExtensions.Tls12;
public const SecurityProtocolType Tls11 = (SecurityProtocolType)SslProtocolsExtensions.Tls11;
public const SecurityProtocolType SystemDefault = (SecurityProtocolType)0;
}
}


SslProtocolsExtensions.cs

namespace System.Security.Authentication

{
public static class SslProtocolsExtensions
{
public const SslProtocols Tls12 = (SslProtocols)0x00000C00;
public const SslProtocols Tls11 = (SslProtocols)0x00000300;
}
}


Net/MqttNetworkChannel.cs

        public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)

{
switch (mqttSslProtocol)
{
case MqttSslProtocols.None:
return SslProtocols.None;
case MqttSslProtocols.SSLv3:
return SslProtocols.Ssl3;
case MqttSslProtocols.TLSv1_0:
return SslProtocols.Tls;
case MqttSslProtocols.TLSv1_1:
return SslProtocolsExtensions.Tls11;
case MqttSslProtocols.TLSv1_2:
return SslProtocolsExtensions.Tls12;
default:
throw new ArgumentException("SSL/TLS protocol version not supported");
}
}

参考:.NET Framework で TLS1.1 および 1.2 を有効化する方法


クォータニオン

さて、UnityでMQTTするのは諦めるとして、3Dオブジェクトをグリグリする件です。

3Dオブジェクトをグリグリするには、クォータニオンというのが必要なんです。

僕にはよくわからないですが、yyama2さんが言っていたので、間違いないです。

なんか行列とか使って、計算すれば自分でもクォータニオン取得できるらしいのですが、世の中にはjavascriptでクォータニオン取得できるライブラリもあるようでして。

https://github.com/infusion/Quaternion.js

もうコレを使えばいいんじゃないかと。

そんなわけで、Quaternion.jsのサンプルをちょこっといじって、

IMG_5997.PNG

端末側で取得したQuaternionデータをMQTTでPubして、

スクリーンショット 2016-12-19 0.14.25.png

PCのブラウザでSubして受けとって、同期して動かしてみました。

サンプル:端末でQuaternion取得してMQTT over WebsocketでAws IoTにPub

サンプル:Aws IoTにMQTT接続してSubしたQuaternionデータでQuaternion.jsを動かす


最後に。

これで、一応、「IoTで3Dをグリグリ動かす」というお題はクリアになりますでしょうか。

ホントはWebGLとかにもチャレンジしたかったんですが、時間切れでそこまでたどり着けませんでした。

Unityでなんとかしたかったんですが、.Netの壁は厚かった・・・

それでも、Javascriptだけでここまでできるってのもすごいですね。

CYBIRDエンジニア Advent Calendar 明日は、僕のUnityの師匠のyyama2さんです!楽しみですね!