aptpod Tech Blog

株式会社アプトポッドのテクノロジーブログです

Unityで簡単にintdash対応アプリケーションを開発できるようになりました

ネイティブアプリケーション開発を担当している上野です。

この度、弊社サービスの intdash と、ゲームエンジン Unity との連携を容易に実現するモジュールを公開することになりました。モジュールの公開に合わせて、その利用サンプルも公開しています。今回は、それらの使い方をご紹介いたします。

Unityで開発したアプリケーションからデータをリアルタイムに取り出して可視化したり、クラウドへ保存して活用したりしてみたいという方や、デジタルツイン開発を始めてみたいという方の第1歩として、このサンプルを活用いただければと思います。

今回公開したもの

今回公開したのは、以下2つです。Unity用のSDKと、そのサンプルの2つのリポジトリになります。

intdash SDK for Unity は、UnityのIDEにインポートして利用するSDKで、intdashサーバーのリアルタイム伝送のためのAPIに接続するモジュールや、REST APIにアクセスするためのモジュールが含まれています。

intdash SDK Samples for Unity は、intdash SDK for Unity の使い方を理解していただくためのサンプルです。詳しくはこれ以降で解説します。

※ 本記事は intdash-unity v1.0.0intdash-unity-samples v1.0.0 を想定しています。将来的に仕様が変更される可能性もありますのでご注意ください。

intdash SDK Samples for Unity について

youtu.be

ここからは、SDKのサンプルである intdash SDK Samples for Unity をとりあえず試してみたい方向けの内容になります。

今回のサンプルには、ビジュアライザー、コントローラー、シミュレーターが含まれます。

ビジュアライザーは、intdashを流れるデータをUnityを使用して可視化するアプリケーションのサンプルです。今回のサンプルは簡易的なものですが、Unityを使用することで点群データなど3D空間上での可視化表現を用意に実装することができます。

コントローラーは、intdashを介して制御データを送信する操縦アプリケーションのサンプルです。こちらもサンプルは簡易的なものですが、Unityを使用することで、VRゴーグルを活用したバーチャル操縦コックピットの開発など、高度なアプリケーションを開発することができます。

最後にシミュレーターは、Unityで実装した物理シュミレーションのサンプルです。ビジュアライザーやコントローラーは現実世界のデバイスの可視化、操縦のためにも使用できますが、実際のデバイスを用意するのが難しい場合には、こちらのシミュレーターサンプルのようにシミュレーション空間をUnityで作成して代替することも可能です。

ビジュアライザー、コントローラー、シミュレーターと、弊社サービスであるintdashとの間のデータの流れは以下のようになります。

すべてのサンプルプロジェクトがintdashサーバーを介してデータをやり取りしており、お互いのデータを相互に活用して動作します。

今回公開したサンプルでは、シミュレーター内にレース場を作成し、その上で走行する自動車のモデルを、コントローラーで操縦したりビジュアライザーで可視化したりするシナリオをご用意しました。

※ intdashサーバーとのデータ伝送を行うにはご契約が必要になります、無償のトライアルプログラムもございますのでぜひご活用ください。

シミュレーターのサンプル

シミュレータを作成する場合には、まずシミュレーションしたいシナリオを考えて、3D空間内に構築します。

このサンプルでは車の前方にカメラ配置し取得した映像をJPEG形式に圧縮した物と車体の位置、回転情報も収集しデータ伝送を行います。 また、遠隔制御を受け付ける為の操作データの受信方法も実装されています。

操縦アプリケーションのサンプル

操縦アプリケーションでは、操縦対象から取得したデータを可視化しつつ、逆に操作情報を送信することで操縦を実現します。

サンプルでは、コントローラーとは別のアプリケーションであるシミュレーターに配置された車を操縦していますが、intdashによるデータ伝送を用いれば、シミュレーターのかわりに現実世界の車や機械を制御することも可能です。サンプルでは2種類のデータしか扱っていませんが、可視化するデータの種類を増やしたり、Unityの3D空間上での表現力を活かして点群データなどを可視化すれば、より安全で効率のよい操作アプリケーションを実現することも可能になります。

可視化アプリケーションのサンプル

こちらは遠隔制御目的ではなく監視用途のアプリケーションです。

コントローラーのサンプルと見た目が似ているため違いが分かりにくくなっていますが、こちらは操縦ではなく可視化や監視を目的としたビジュアライザーのサンプルです。

シミュレーターから取得したデータを表示しているのはコントローラーと同様ですが、コントローラーが送信している操作情報もintdashから受け取って可視化している点が、ビジュアライザーのコントローラと異なるポイントです。

intdashには、データの伝送だけでなく、伝送したデータがクラウドに自動的に保存されるという機能にも対応しています。このサンプルでは、intdashに保存された過去のデータを取得してプレイバックする機能も含まれています。

データストアされたデータのプレイバック

プレイバックでの可視化では、リアルタイムの可視化とは異なり、右下の俯瞰マップに走行ルートが表示されます。プレイバック機能は、アプリケーションを開始する際に再生日時を指定することで利用できます

intdash SDK for Unity について

ここからは、SDK自体を使用して、サンプルで解説したようなアプリケーションを作ってみたい方向けの内容になります。実際のコードも踏まえつつ、モジュールの使い方を解説します。

モジュールの導入と準備

UnityEditorのHierarchyに含まれるintdashとの認証情報入力する場所

上記はSimulatorSampleに含まれるSampleScene.unityをUnityEditorで開きHierarchyとInspectorを表示した状態です。 サンプルでは intdash/ApiManager というGameObjectにIntdashApiManagerスクリプトがアタッチされています。こちらにintdashサーバーとのアクセス情報を入力するだけでサーバーとの接続準備は完了です。

コネクションの設定

intdashサーバーへデータを送信する際はエッジのUUIDの設定が必要です。サンプルではintdash/Connections 配下のGameObjectにIscpConnectionスクリプトがアタッチされ、そちらでエッジUUIDの設定が可能です。

IntdashApiManagerに含まれる Type の項目が Client Secret(Edge UUID) である場合は、認証情報を発行したエッジのUUIDがIscpConnectionのエッジUUIDとして自動で設定されるため、入力は不要です。他の認証方法を利用する場合や、複数のコネクションを設定し、複数のエッジを利用してデータを送信したいケースではエッジUUIDの設定を行ってください。

※ 複数のコネクションを利用したい場合は Is Shared にチェックをいれない、もしくは1つのコンポーネントのみにチェックする様にしてください。

データを生成する仮想デバイスの作成

シミュレーターなどにおいて、データを生成する仮想デバイスを作成する方法は、以下の通りになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SampleDevice: MonoBehaviour
{
    public float SamplingRate = 10f;
    private float? _SamplingRate;

    public struct OutputData
    {
        // ToDo: 出力したいデータ
    }
    public delegate void OnOutputDataDelegate(OutputData outputData);
    public OnOutputDataDelegate OnOutputData;

    private float elapsedTime = 0;
    private float targetTime = 0;

    // Start is called before the first frame update
    void Start() { }

    // Update is called once per frame
    void Update()
    {
        if (SamplingRate != _SamplingRate)
        {
            _SamplingRate = SamplingRate;
            this.targetTime = 1f / SamplingRate;
            this.elapsedTime = 0f;
        }

        if (SamplingRate <= 0) return;

        elapsedTime += Time.deltaTime;

        if (this.elapsedTime > this.targetTime)
        {
            this.elapsedTime -= this.targetTime;
            // ToDo: 指定した出力時間が来たので値取得 or 計算を行い利用先にデータを流す
            var data = new OutputData(出力したいデータ);
            OnOutputData?.Invoke(data);
        }
    }
}

Unityでは、Update() という関数が各フレームごとに呼び出されるので、SamplingRateで指定した分の時間間隔が経過するごとにデータの取得処理や生成処理を行うことで、必要な周期ごとにデータの生成が可能です。

※ データが大きすぎたり、PCのスペックが低すぎたりする場合には、ほかの処理に影響が出る場合もあります。その場合には、別スレッドで処理させたり、GPUを使用するなどのチューニングが必要になる場合もあります。

取得したデータのintdashによる送信

取得したデータを、intdashサーバーに送信する方法は、以下の通りになります。

using UnityEngine;
using iSCP.Model;

public class Iscp_SampleDataPublisher : MonoBehaviour, IIscpUpstreamCallbacks
{
    [SerializeField]
    private string dataType = "string/json";
    [SerializeField]
    private string dataName = "sampleData";

    [SerializeField]
    private bool persist;

    public DeviceSample InputDevice;

    // MEMO: Basically, IscpConnection attachment from Inspector is not required, but can be specified.
    [SerializeField] private IscpConnection iscp;

    private IscpUpstream upstream;

    // Called when the script is first activated.
    private void Awake()
    {
        // Setup iSCP.
        if (iscp == null)
        {
            this.iscp = IscpConnection.GetOrCreateSharedInstance();
        }
        // Register upstream.
        upstream = iscp.RegisterUpstream(persist);
        upstream.Callbacks = this;
    }

    private void OnEnable()
    {
        if (InputDevice != null)
            InputDevice.OnOutputData += OnOutputData;
    }

    private void OnDisable()
    {
        if (InputDevice != null)
            InputDevice.OnOutputData -= OnOutputData;
    }

    void OnOutputData(DeviceSample.OutputData data)
    {
        // Generation in accordance with data format.
        var json = "";
        json += "{";
        json += ""; // ToDo: 送信したいデータ
        json += " }";
        var payload = System.Text.Encoding.UTF8.GetBytes(json);
        // Send data points to upstream.
        upstream.SendDataPoint(dataName, dataType, payload);
    }
}

「仮想デバイスの作成」で作成したデバイスが定期的にコールバックで値を出力するので、事前に開いておいたintdashのアップストリームへデータ を書き込むだけでデータを伝送できます。

書き込むデータに対しては、事前にデータ名とデータタイプ、ペイロードのフォーマットを決めておく必要があります。今回、データの中身を理解しやすくするためにペイロードフォーマットにはJSONを使用しています。これはあくまで一例で、場合によってはロボット開発で使用されるROSデータや、よりデータサイズを小さくするためにバイナリフォーマットを使用することもできます。

また、ストリームを開く際に、送信したデータをクラウドへ保存するかどうかの設定もでき、データ伝送だけを行う設定とすることも可能です。

intdashを流れるデータの受信

コントローラーやシミュレーターから送信されたデータを、intdashサーバーから受信する方法は、以下の通りになります。

using System;
using UnityEngine;
using Newtonsoft.Json.Linq;

public class Iscp_SampleDataSubscriber : MonoBehaviour
{
    [SerializeField]
    private string dataType = "string/json";
    [SerializeField]
    private string dataName = "sampleData";

    [SerializeField]
    [IntdashLabel("Node ID(Edge UUID)")]
    private string nodeId = "";

    public SampleComponent TargetComponent;

    [SerializeField]
    private string receivedTime;
    public string ReceivedTime => receivedTime;

    [SerializeField]
    private string receivedData;
    public string ReceivedData => receivedData;

    // MEMO: Basically, IscpConnection attachment from Inspector is not required, but can be specified.
    [SerializeField] private IscpConnection iscp;

    private IscpDownstream downstream;

    // Called when the script is first activated.
    private void Awake()
    {
        // Setup iSCP.
        if (this.iscp == null)
        {
            this.iscp = IscpConnection.GetOrCreateSharedInstance();
        }
        // Register downstream.
        downstream = this.iscp.RegisterDownstream(nodeId, dataName, dataType, OnReceiveDataPoints);
    }

    // Received data points events.
    private void OnReceiveDataPoints(DateTime baseTime, iSCP.Model.DataPointGroup group)
    {
        Dispatcher.RunOnMainThread(() =>
        {
            if (this == null) return;
            if (!this.enabled) return;
            try
            {
                foreach (var d in group.DataPoints)
                {
                    receivedTime = DateTime.UtcNow.ToLocalTime().ToString("HH:mm:ss.ffffff");
                    // Extract the necessary data from the data format.
                    receivedData  = System.Text.Encoding.UTF8.GetString(d.Payload);
                    抽出する型 抽出したデータ;
                    // Json Parse
                    {
                        JObject json = JObject.Parse(receivedData);
                        // ToDo: 送られてくるデータフォーマットに沿って必要なデータを抽出する。
                        抽出したデータ = json["抽出したいデータ"]ToObject<抽出する型>(); 
                    }
                    if (TargetComponent != null)
                    {
                        if (TargetComponent.enabled)
                        {
                            // ToDo: 動かしたり、可視化したいコンポーネントへデータを伝える。
                            Debug.Log("Received data: " + 抽出したデータ);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError("Failed to deserialize control message. " + e.Message);
            }
        });
    }
}

受信したいデータに合わせて、dataTypeやdataName、nodeId を設定することで、intdashサーバーからダウンストリームを開くことができます。サンプルでは、シミュレーターやコントローラーで使用しているエッジのUUIDをnodeIdとして指定しています。

データが受信されるとコールバックが呼び出されるので、ペイロードのフォーマットに合わせてデータをパースし、可視化などの必要な処理を行います。

SDKで実現できること

今回のサンプルでは、あくまでSDKの使い方を示す目的にフォーカスして、最小限の構成を使用しています。最小限の構成のため、できることは限られていますが、intdashを使えば簡単にUnityからデータを伝送できることをご理解いただけたと思います。

サンプルと同様に、intdashを活用してデジタルツインシステムを実現した例として、以下のような事例もございます。

openhub.ntt.com

上記記事の中では、 建設現場の遠隔化/リアルタイムデジタルツイン というテーマで、今回のサンプルをさらにグレードアップしたようなアプリケーションが紹介されています。

今回のサンプルでは映像のみを用いた遠隔操縦を題材としていますが、3D LiDARを使用して点群データを取得するなどすれば、より詳細な情報を利用して安全かつ正確な操作が可能になります。

また、たとえば高額なセンサーの購入が必要となる実証実験の際にも、現実世界でのシステム構築の前にUnityでシミュレーションを構築すれば、実際に近いデータの流れを低コストに再現することができます。

弊社ビジネスのご紹介

アプトポッドでは、IoTミドルウェア intdash の開発と、intdsahを活用したIoTシステムの構築を事業としています。

intdashは、あらゆるIoTデータを収集、伝送、管理、活用することができ、IoTデータを活用するさまざまなサービスのバックエンドとしてご活用頂いております。

www.aptpod.co.jp

今回ご紹介したSDKは、デジタルツインやAR/VRで活用されているUnityとintdashの連携性を更に強め、intdashで集めたデータの活用の幅を広げていくための強力なツールです。

IoTデータを利用したプラットフォーム、IoTサービスの開発や、リアルタイムデジタルツイン、製造現場のDX化など、IoTシステムの開発でお困りのことがあれば、ぜひ弊社までお声がけください。

弊社の問い合わせフォームはこちらです。

www.aptpod.co.jp