Digital TwinsとMixed Realityの組み合わせ
Microsoft Build 2021ではIoTカテゴリのセションの中でMixed Realityを活用する話がありました。もともとMixed Reality(複合現実)は「現実環境とデジタル環境が相互作用する概念」なので「現実環境をリアルタイムでデジタル環境に構築する」というデジタルツインはかなり親和性が高い技術だと思います。
これからもこれらの技術はかなり近い領域で活用されるのではないでしょうか。
本記事ではMicrosoft Build 2021で紹介されたDigital Twinsを実現するためのAzure関連サービスの解説を何回かにわけて紹介したいと思います。今回はAzure IoT Hubについての話です。
Microsoft Build 2021で紹介されたDigital Twinsについては以下のQiitaでも整理しているので参考にしてください。
はじめに
解説に入る前に題材にするサンプルアプリについての紹介をしたいと思います。
ラーニングパス「Azure Digital Twins と Unity を使用して Mixed Reality デジタル ツインを構築する」とは
先日のMicrosoft Build 2021の中のセション「Connect IoT data to HoloLens 2 with Azure Digital Twins and Unity」で公開された新しいラーニングパスです。ちなみに、このセションで実際にポイントになる情報もわかるのでラーニングパスと合わせて確認すると理解が深まるかと思います。
このラーニングパスでは「現実環境にあるIoTデバイスからのテレメトリー情報をデジタルツインとしてリアルタイムで収集/管理し、その結果をMixed Realityを活用して俯瞰視点で可視化する」についての手順を学ぶことができます。
このラーニングパスはDigital Twins関連のセション「Building Digital Twins, Mixed Reality and Metaverse Apps」で紹介されているテクノロジーを組合わせた1つのユースケースにもなっています。おそらくこの可視化を「Microsoft Mesh」を活用してコラボレーションするというところまでが1つの流れとしてあると思います。
ラーニングパスでは主に「現実環境をIoTでセンシングしデジタル環境でモデル化」、「情報をリアルタイムに更新」という部分を中心に構成されています。HoloLens 2についてはデジタルツインとして管理している情報を可視化する手段として活用しています。こういった形でAzure上で構成されるDigital Twinsについて必要なところから導入をしていくことが可能な構造にはなっています。おそらく最も最小限の構成というのは「Azure IoT Hub」と、「Azure Digital Twins」の組み合わせになると思います。
### 開発環境と構築について
開発環境はラーニングパスの環境をベースの構築しています。
詳細はラーニングパスのサイトを参照してください。
- HoloLens 2 デバイス(ない場合もUnityのデバック実行上で確認は可能です)
- Azure サブスクリプション
- 必要なツールが構成された Windows 10 PC
- Windows 10 SDK 10.0.18362.0 以降
- Unity 2020.3.8f1 (LTS) 以降(サンプルは左記バージョンで構築されています)
- Visual Studio 2019
- USB デバイス接続を含めた、ユニバーサル Windows プラットフォーム (UWP) ワークロードがインストールされている
- USB デバイスの接続
- Microsoft Mixed Reality Feature Tool
環境周りについては @Futo_Horio さんが整理しているのでラーニングパスで困ったら参考にしてください。
ラーニングパスのアーキテクチャについて
このラーニングパスについては以下のようなアーキテクチャ構造を取っています。このラーニングパスはサンプル風力発電プラントのデジタルツインを想定した作りになっています。
物理環境には数台の風車が稼働している想定になっており、以下の流れで処理が行われます。デモアプリでは異常系としてAlertの発生もできるようになっています。これらの情報はプログラムでエミュレートされています。
- 風車はAzure IoT Hubで管理。各風車はリアルタイムで風車の周辺温度、風速、回転数をAzure IoT Hubのテレメトリ情報として送信
- Azure IoT Hubは風車からのテレメトリー情報をEvent Gridへ転送
- Event Grid(システムトピック)ではAzure IoT Hubを監視しテレメトリー情報の受信を検知するとAzure Functionsを呼出
- Azure Functions内では受信したテレメトリー情報を、Azure Digital Twinsであらかじめモデル化された風車の情報を更新
- Azure Digital Twinsは更新されたモデル情報をEvent Gridへ転送
- Event Gridでは登録されたAzure Functionsを呼出
- Azure Functions内ではDigital Twinsから取得した情報をSignalRを通じて同報発信を実施
- HoloLensはアプリケーション内でSignalRに接続し通知された情報で風車の各情報を更新
- 風車に問題が発生した場合、Azure Digital Twinsに対してAlertを送信。Alert情報はテレメトリー情報と同じ経路で処理される
- Alertの連続送信を防止するためにAzure Digital Twinsの情報を取得
- HoloLensからAlert情報のリセットを行う。Azure Digital Twinsに対してAlert解除を実施
ラーニングパスで活用されている技術(Azure IoT Hub編)
ではラーニングパスを参考にAzure IoT Hubがラーニングパス上でどのように活用されているか確認していきます。
Azure IoT Hubについて(概要)
(後述)
環境構築
Azure IoT Hubを含めてこのラーニングポスではARM-Templateを活用しています。スクリプトを実行するといくつかサービスが展開されます。このなかで注意が必要なのが実はAzure IoT Hubです。Azure IoT Hubは「S1-標準」で構築されるため月額で費用が掛かります。他のサービスも環境次第でさらに課金されることがあるので注意してください。なお、今回のサンプルではD2C(テレメトリー)のみを使っています。他の機能は特に利用していないのでB1で構築も可能です(この場合IoT Hubの再作成が必要)。なお、サンプルが複数のIoTデバイスとつながっている想定なのでF1は無改造では利用できません。
ARM-Templateについて
ARM(Azure Resource Managerの略)テンプレートは文字通りAzureのリソースを管理するためのテンプレートになります。ラーニングパスではazuredeploy.bicepファイルがそれです。中身を見るときはVisual Studio Codeが便利です。合わせて以下のExtensionも追加しておくと自分で作るときに役立つと思います。
Azure IoT Hub関連のサービス
先ほど紹介したアーキテクチャの通りでAzure IoT Hubのサービスを構成するためには以下のサービス群が必要になります。
Azure サービス名 | ラーニングパスでの利用方法 |
---|---|
Azure IoT Hub | 風車をIoTデバイスとして管理。それぞれのデバイスからのセンサー情報をテレメトリ情報として受け取ります。 |
Azure Functions | IoT Hubに届いたテレメトリ情報を処理しAzure Digital Twinsに格納するために関数として利用します。 |
Event Grid | システムトピックとしてAzure IoT Hubに紐づけられたEvent Gridです。 |
PostDeploymentscript | これ自体はAzureのサービスではないのですが、ARM-Templateの後処理として実行します |
Azure IoT Hub
1ユニットでS1構成のものをデプロイします。nameのところは変数になっておりラーニングパスの手順に従って設定される名前が入ってます。
// create iot hub
resource iot 'microsoft.devices/iotHubs@2020-03-01' = {
name: iotHubName
location: location
sku: {
name: 'S1'
capacity: 1
}
properties: {
eventHubEndpoints: {
events: {
retentionTimeInDays: 1
partitionCount: 4
}
}
}
}
Azure Functions
Azure Functionsについては以下の2つの関数をもつ構成で定義されます。
- IoT Hubからのテレメトリ情報をAzure Digital Twinsに格納する
- Azure Digital Twinsのテレメトリ情報の変更に応じてSignalRで同報発信する
azuredeploy.bicep内ではAzure Functionsの定義のみ実施しています。アプリ設定には各種サービスへの接続が必要なためそれらに関するリソースが依存関係で定義されています。
- アプリケーションインサイトへの接続情報(APPINSIGHTS_INSTRUMENTATIONKEY, APPLICATIONINSIGHTS_CONNECTION_STRING)
- Azure Digital Twinsへの接続情報(ADT_SERVICE_URL)
- ASP.NET Core SignalRへの接続情報(SIGNALR_CONNECTION_STRING, AzureSignalRConnectionString)
- サーバファームでの運用
- AzureWebJobsStorageに使用
// create Function app for hosting the IoTHub ingress and SignalR egress
resource funcApp 'Microsoft.Web/sites@2019-08-01' = {
name: funcAppName
kind: 'functionapp'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
siteConfig: {
appSettings: [
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~3'
}
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageName};AccountKey=${listKeys(storageName, '2019-06-01').keys[0].value}'
}
{
name: 'ADT_SERVICE_URL'
value: 'https://${adt.properties.hostName}'
}
{
name: 'SIGNALR_CONNECTION_STRING'
value: 'Endpoint=https://${signalrName}.service.signalr.net;AccessKey=${listKeys(signalrName, providers('Microsoft.SignalRService', 'SignalR').apiVersions[0]).primaryKey};Version=1.0;'
}
{
name: 'AzureSignalRConnectionString'
value: 'Endpoint=https://${signalrName}.service.signalr.net;AccessKey=${listKeys(signalrName, providers('Microsoft.SignalRService', 'SignalR').apiVersions[0]).primaryKey};Version=1.0;'
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsights.properties.InstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsights.properties.ConnectionString
}
]
}
serverFarmId: appserver.id
clientAffinityEnabled: false
}
dependsOn: [
storage
identity
adt
signalr
appInsights
]
}si
関数のデプロイは以下の部分で実施されます。デプロイの「blade-functions.zip」はC#で書かれたFunctionsのプロジェクト(github)をフォルダーに対して発行しZip圧縮したものです。
// Deploy function code from zip
resource ingestfunction 'Microsoft.Web/sites/extensions@2015-08-01' = {
name: '${funcApp.name}/MSDeploy'
properties: {
packageUri: 'https://github.com/MicrosoftDocs/mslearn-mr-adt-in-unity/raw/main/ARM-Template/functions/zipfiles/blade-functions.zip'
dbType: 'None'
connectionString: ''
}
dependsOn: [
funcApp
]
}
Event Grid
Event Gridは今回は2つ使用しています。まずは、Azure IoT Hub用のシステムトピックです。システムトピックとはAzureのサービスに紐づてAzureサービス上で発生する様々な処理をイベントとして監視できるサービスです。このEvent Grid上にどういったアクションを監視するかサブスクリプションを定義し、Functions等をトリガーとして呼出すことができます。
以下のスクリプトはAzure IoT Hubに対するシステムトピックを作成しています。
resource eventGridIngestTopic 'Microsoft.EventGrid/systemTopics@2020-04-01-preview' = {
name: eventGridIngestName
location: location
properties: {
source: iot.id
topicType: 'microsoft.devices.iothubs'
}
dependsOn: [
iot
ingestfunction
funcApp
]
}
実際に処理を行うFunctionsの割り当ては以下のイベントサブスクリプションで定義します。
ラーニングパスではAzure IoT Hubで発生する処理のうちテレメトリ情報(Microsoft.Devices.DeviceTelemetry)を受け取るとこのサブスクリプションが反応し、割り当てわれているAzure Functionsが動作するようになっています。
resource eventGrid_IoTHubIngest 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2020-04-01-preview' = {
name: '${eventGridIngestTopic.name}/${ingestFuncName}'
properties: {
destination: {
endpointType: 'AzureFunction'
properties: {
resourceId: '${funcApp.id}/functions/${ingestFuncName}'
maxEventsPerBatch: 1
preferredBatchSizeInKilobytes: 64
}
}
eventDeliverySchema: 'EventGridSchema'
filter: {
includedEventTypes: [
'Microsoft.Devices.DeviceTelemetry'
]
}
}
dependsOn: [
eventGridIngestTopic
iot
ingestfunction
funcApp
signalr
PostDeploymentscript
]
}
Azureポータル上でこのサブスクリプションを開きます。リソースグループの中から「Event Grid システムトピック」を選択しその中のイベントサブスクリプションを開くと詳細がわかります。Azure IoT Hubのテレメトリ情報がイベントの種類として定義されているのがわかります。また、他のタイプとしてIoT Hubへのデバイスの追加、接続なども選択可能です。
以上が、ラーニングパスでAzure IoT Hubに関連する環境定義部分です。
次に実装部分で関連するDevice SimulatorとFunctions部分の実装を見ていきたいと思います。
実装部分
次に実装部分でどういうことをしているかを見ていきましょう。今回はAzure IoT Hubに情報を送っているDevice Simulatorの中でAzure IoT Hubに対して処理を行っているメソッドとその中でどのような処理が実装されているかを解説します。完全なコードはGithubの情報を参照してください。ここではメソッド名とその中で使われているAzure IoT Hubに関するクラスと実装について抜粋して記載しています。
また、Event Gridを通して実施されるFunctionsについても簡単に解説したいと思います。
Device Simulator
Azure IoT HubはIoTデバイスを管理しセンサー情報をテレメトリーとして情報を発信することができます。また、逆にデバイスに対してコマンドを送るための機能もあります。これらは通常Azure IoT Hubに接続するデバイス側でプログラムで実装します。プログラムはさほど難しいものではなくSDKで提供されていますIoTデバイスを相手にするだけに対応する言語も豊富です。Raspberry Piやmbedといった電子工作でもよく使うチップでも接続可能なのでIoTデバイスとデータの管理はかなり簡単です。
テレメトリ情報の送信については「公式ドキュメント:クイック スタート:デバイスから IoT ハブに利用統計情報を送信して Azure CLI で監視する」も参考にしてください。
Device Simulatorもこの仕組みを利用しています。PC上でセンサーデータを適当に生成した上で、Azure IoT HubのSDKを利用し、Azure IoT Hubにデータを送信しています。
ラーニングパスのDevice Simulatorは以下の様にAzure IoT Hubへデータを送信することと、そのテレメトリ情報を取得しています。
コードはmslearn-mr-adt-in-unity/Device-SImulator/DeviceSimulator/AzureIoTHub.csになります。
このクラスでは以下のメソッドで処理を実施しています。
IoTデバイスの管理
Device Simulatorは最初にAzure IoT Hubに接続し、デバイス情報を収集します。デバイス情報はT98~T107の風車の情報を検索する形になっています。センサー情報が見つからない場合はIoT Hubに不足したデバイスの追加を実施します。
public static async Task<List<Device>> CreateDeviceIdentitiesAsyc(List<string> deviceIds)
IoT Hubに関するデバイス管理はMicrosoft.Azure.Devices.RegistryManagerクラスを利用しています。このクラスにAzure IoT Hubの接続文字列を指定することでIoT Hubに接続しデバイス情報を取得できます。
// Azure Iot Hubとの接続
var registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
//Deviceの登録
var device = new Device("[Device Name]");
Device createdDevice = await registryManager.AddDeviceAsync(device);
// Deviceの取得
var device = await registryManager.GetDeviceAsync("[Device Name]");
実際のアプリケーションでは登録処理を利用することは少ないと思います。
シミュレータがデバイスに情報を利用しているには以降のメッセージを送信する際にIoT Hubのデバイスに接続するためです。
上記のメソッドはあくまでIoT Hubのサービスにアクセスしサービス管理するためのもので、実際のデバイスへの送信はデバイス毎の接続文字列が必要になります。
// IoT Hubへの接続文字列
"HostName=[ServiceName].azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=[key]";
// IoT Hubに登録されたデバイスへの接続文字列
"HostName=[ServiceName].azure-devices.net;DeviceId=[DeviceId];SharedAccessKey=[key]";
以降のメソッドではデバイスへの接続文字列を利用しています。
テレメトリー情報の発信(D2Cメッセージ)
Azure IoT Hubに対してデバイスからメッセージを送信する処理は以下のメソッドで実装されています。
// クラウド上で登録されているDviceにメッセージを送信
public static async Task SendDeviceToCloudMessageAsync(CancellationToken cancelToken)
// 風車の送信用データを生成
private static Microsoft.Azure.Devices.Client.Message ConstructTelemetryDataPoint(TelemetryData data, bool isAlert)
このメソッド内では先のデバイスの接続文字列を利用し、各デバイスのセンサー情報として以下の情報を送信します。
ID | 内容 |
---|---|
TurbineID | 風車のID |
TimeInterval | (・_・)……? |
Description | Alertのメッセージ |
Code | Alertのコード |
WindSpeed | 風速 |
Ambient | 周辺温度 |
Rotor | 風車の回転速度 |
Power | 発電量 |
メッセージとしてこの情報をJSONデータにして送っています。
ポイントになるかもしれないのが、あくまでもデバイスの情報(テレメトリ)を送っている点ですね。別途紹介はする予定ですが、風車に異常があるという情報はAzure Digital Twinsに直接送っていて明確に分かれている形になっています。IoTデバイスからはセンサーの情報のみを投げるというのがセオリーの様です。
// IoT Hubで管理されているデバイスへの接続し、インスタンスを生成
var client = DeviceClient.CreateFromConnectionString("[Device Connection string]");
//メッセージの設定
var message = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes("[Json Message]"))
{
ContentType = "application/json",
ContentEncoding = "utf-8"
};
// メッセージの送信
await client.SendEventAsync(message);
テレメトリー情報の確認
テレメトリ情報が問題なく届いているかを確認する処理も実装されています。Azure IoT Hubのサービスに接続し、そこで発生するイベントの発生を待機し、イベントを受け取るとその情報を可視化します。
public static async Task ReceiveMessagesFromDeviceAsync(CancellationToken cancelToken)
この処理は基本的には本番で使うようなものではなくデバック等の検査時に活用することが想定されています。
// IoT Hubのコンシューマグループへの接続を確立
var client = await using var consumerClient = new EventHubConsumerClient(
"[consumer group name]",
"[Event Hub Connection String]");
//メッセージの待機と表示
await foreach (PartitionEvent partitionEvent in consumerClient.ReadEventsAsync(cancelToken))
{
if (partitionEvent.Data == null) continue;
string data = Encoding.UTF8.GetString(partitionEvent.Data.Body.ToArray());
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Message received. Partition: {partitionEvent.Partition.PartitionId} Data: '{data}'");
}
Azure Function
Azure Functionsは2つの関数が利用されています。今回はAzure IoT HubからAzure Digital Twinsにテレメトリ情報を送る関数部分の解説を行いたいと思います。
関数の定義
Azure Funtionsの引数部分でAzure IoT Hubの情報を取得するようになっています。引数の属性として定義されるEventGridTriggerAttributeによってこの関数はEvent Gridの内で定義できるタイプになります。
引数のeventGridEventには、Event Gridが受け取った情報が含まれています。今回のサンプルではテレメトリー情報としてJsonデータが入っています。
public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
// データの取得
JObject alertMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
この関数にはこれ以外にもAzure Digital Twinsへの接続とデータ送信の実装があるのですが、その部分の説明についてはAzure Digital Twins編で紹介したいと思います。
処理の流れは?
テレメトリー情報の伝搬の仕方について各サービスのオブジェクトを模式図で紹介します。ポイントは2つあると思います。
- 物理的なIoTデバイスの対となるインスタンスをAzure IoT HubにIoTデバイスとして定義する
- Azure Iot Hubのテレメトリ情報はEvent Gridのシステムトピックにより監視され処理を実施
データの流れでわかりにくいのはこのEvent Gridだと思います。システムトピックとして定義されており、Azure IoT Hubサービス上では紐づけ関係が一見無いように見えてしまいます。実際はサービス自体を監視し条件に応じてイベントを発生させる仕組みになっています。簡単にポイントも整理しました。
- 物理環境のIoTデバイス数に合わせてAzure IoT HubのIoTデバイスのインスタンスを定義
- 物理環境のIoTデバイス上のプログラムで、Azure IoT Hub上で定義したIoTデバイスのインスタンスと接続を確立
- 物理環境のIoTデバイスからテレメトリ情報を送信
- Azure IoT Hub上のIoTデバイスは物理環境からのテレメトリ情報を受信
- Event GridはAzure IoT Hubサービスの監視を行っており、テレメトリ情報の受信を検知すると登録済みのAzure Functionsを呼出
- Azure Functionsへ引き継ぐ情報としてテレメトリ情報としてIoTデバイスから送信されたJsonデータを添付する
- Azure Functionsはテレメトリ情報を加工してAzure Digital Twinsに対して更新を実施する。
まとめ
今回は、「Microsoft Learn 「Azure Digital Twins と Unity を使用して Mixed Reality デジタルツインを構築する」解説(Azure IoT Hub編)」としてAzureで構成するDigital TwinsのベースになるAzure IoT Hubの動作についてラーニングパスのサンプルで紹介しました。実際のプロジェクトでの活用時の参考になると幸いです。
次回はAzure IoT Hubが受信した情報をデジタル環境でモデル化する「Azure Digital Twins」を中心に同じサンプルを用いて解説したいと思います。