Intel RealSense SDK音声認識アプリケーションでドローンを管理





ニュースは無人航空機-無人航空機-について文字通り毎日話しています。 偵察や軍事作戦、写真やビデオの撮影、娯楽だけなど、幅広い用途があります。 ドローンテクノロジーはまったく新しいものであり、関心があります。



開発者は、ドローン制御アプリケーションを作成できます。 ドローンは最終的には通常のプログラム可能なデバイスであるため、PCやスマートフォン用の通常のアプリケーションを使用して必要なアクションを実行するためのコマンドを与えることができます。 この記事では、最も強力なプログラミング機能を備えたドローンの1つ、 ParrotのAR.Drone 2.0を選択しました



C#で記述されたライブラリを使用して、このようなドローンと対話し、制御する方法を学習します。 この基盤に基づいて、 Intel RealSense SDKを使用してドローンを制御する音声コマンドを追加します



ParrotのAR.Drone 2.0は、愛好家向けの市場で最も興味深いドローンの1つです。 このドローンには多くの機能があり、安定化およびキャリブレーションインターフェイスを備えた統合ヘルプシステムが含まれています。 ドローンには、落下や固定障害物との衝突時にプロペラブレードと可動部品を保護する耐久性のある発泡スチロール製の保護フレームが装備されています。





Parrot AR.Drone * 2.0



ドローンの機器は、独自のWi-Fi *ネットワークを介して外部デバイス(スマートフォン、タブレット、PC)への接続を提供します。 通信プロトコルは、ATに似たメッセージに基づいています(数年前、電話ネットワークを介した通信用にモデムをプログラムするために同様のコマンドが使用されていました)。



このシンプルなプロトコルを使用すると、離陸、上昇または下降、およびさまざまな方向への飛行に必要なすべてのコマンドをドローンに送信できます。 また、ドローンに搭載されたカメラ(高解像度)でキャプチャされた画像のストリームを読み取り(1台のカメラが前方、もう1台が下向き)、飛行中に撮影した写真を保存したり、ビデオを録画したりできます。

製造会社は、ドローンを手動で操縦するためのアプリケーションをいくつか提供していますが、自律飛行制御を実現する方法を学ぶ方がはるかに興味深いです。 これを行うために、私は(同僚のMarco Minervaの支援を得て)さまざまなデバイスからドローンを制御できるインターフェースを作成することにしました。



ドローン制御ソフトウェア



ドローンには独自のWi-Fiネットワークがあるため、制御コマンドを送信するためにドローンに接続します。 AR.Drone 2.0開発者ガイドに必要な情報がすべて見つかりました。 たとえば、マニュアルでは、UDPを介してIPアドレス192.168.1.1、ポート5556にコマンドを送信する必要があると書かれています。これらはAT形式の単純な行です。





ドローンに接続したら、アプリケーションの入力データに基づいてドローンにコマンドを送信する一種の「ゲーム」を作成します。 クラスライブラリを作成してみましょう。



まず、デバイスに接続する必要があります。



public static async Task ConnectAsync(string hostName = HOST_NAME, string port = REMOTE_PORT) { // Set up the UDP connection. var droneIP = new HostName(hostName); udpSocket = new DatagramSocket(); await udpSocket.BindServiceNameAsync(port); await udpSocket.ConnectAsync(droneIP, port); udpWriter = new DataWriter(udpSocket.OutputStream); udpWriter.WriteByte(1); await udpWriter.StoreAsync(); var loop = Task.Run(() => DroneLoop()); }
      
      





前述のように、UDPプロトコルを使用する必要があるため、DatagramSocketオブジェクトが必要です。 ConnectAsyncメソッドを使用して接続した後、コマンドを送信するDataWriterを出力ストリームに作成します。 最後に、最初のバイトをWi-Fi経由で送信します。 システムの初期化のみに使用され、ドローンによってドロップされます。



ドローンに送信されたコマンドを確認してください。



  private static async Task DroneLoop() { while (true) { var commandToSend = DroneState.GetNextCommand(sequenceNumber); await SendCommandAsync(commandToSend); sequenceNumber++; await Task.Delay(30); } }
      
      





DroneState.GetNextCommandタグは、デバイスに送信するAT文字列コマンドをフォーマットします。 これを行うには、シリアル番号が必要です。ドローンは各コマンドにシリアル番号が付いていることを想定しており、すでに受信したコマンドの番号以下のすべてのコマンドを無視します。



その後、 WriteStringを使用してStreamSocketを介してコマンドをストリームに送信し、 StoreAsyncがコマンドをバッファーに書き込んで送信します。 最後に、シーケンス番号をインクリメントし、 Task Delayパラメーターを使用して、次の反復の前に30ミリ秒の遅延を入力します。

DroneStateクラスは、送信するコマンドを決定します。



  public static class DroneState { public static double StrafeX { get; set; } public static double StrafeY { get; set; } public static double AscendY { get; set; } public static double RollX { get; set; } public static bool Flying { get; set; } public static bool isFlying { get; set; } internal static string GetNextCommand(uint sequenceNumber) { // Determine if the drone needs to take off or land if (Flying && !isFlying) { isFlying = true; return DroneMovement.GetDroneTakeoff(sequenceNumber); } else if (!Flying && isFlying) { isFlying = false; return DroneMovement.GetDroneLand(sequenceNumber); } // If the drone is flying, sends movement commands to it. if (isFlying && (StrafeX != 0 || StrafeY != 0 || AscendY != 0 || RollX != 0)) return DroneMovement.GetDroneMove(sequenceNumber, StrafeX, StrafeY, AscendY, RollX); return DroneMovement.GetHoveringCommand(sequenceNumber); } }
      
      





StrafeXStrafeYAscendYおよびRollXのプロパティは、左右への移動速度、前後への移動、航空機の高さおよび回転角度を決定します。 これらのプロパティはDoubleデータ型で、有効な値は1〜-1です。 たとえば、 StrafeXプロパティを-0.5に設定すると、ドローンは最大速度の半分で左に移動します。 1に設定すると、ドローンは最大速度で右に飛行します。



Flying変数は離陸と着陸を定義します。 GetNextCommandメソッドでは、これらのフィールドの値をチェックして、ドローンに送信するコマンドを決定します。 これらのコマンドは、 DroneMovementクラスによって管理されます。

コマンドが指定されていない場合、最後の命令はいわゆるホバリングコマンドを作成することに注意してください。 これは空のコマンドであり、航空機とデバイス間のオープンな通信チャネルをサポートします。 ドローンは、アクションを実行する必要がなく、何も変更されていない場合でも、それを管理するアプリケーションから常にメッセージを受信する必要があります。



DroneMovementクラスの最も興味深いメソッドはGetDroneMoveメソッドです。このメソッドは、実際にドローンへのコマンドのコンパイルと送信に関与します。 モーションに関連する他の方法については、この例を参照してください。



 public static string GetDroneMove(uint sequenceNumber, double velocityX, double velocityY, double velocityAscend, double velocityRoll) { var valueX = FloatConversion(velocityX); var valueY = FloatConversion(velocityY); var valueAscend = FloatConversion(velocityAscend); var valueRoll = FloatConversion(velocityRoll); var command = string.Format("{0},{1},{2},{3}", valueX, valueY, valueAscend, valueRoll); return CreateATPCMDCommand(sequenceNumber, command); } private static string CreateATPCMDCommand(uint sequenceNumber, string command, int mode = 1) { return string.Format("AT*PCMD={0},{1},{2}{3}", sequenceNumber, mode, command, Environment.NewLine); }
      
      





FloatConversionメソッドはここでは指定されませんが、-1から1の範囲のDouble値を、PCMD文字列などのATコマンドで使用して移動を制御できる符号付き整数値に変換します。



ここに示すコードは、NuGet Webサイト (AR.Drone 2.0 Interaction Library)から無料のライブラリとして入手できます。 このライブラリには、離陸から着陸まで、制御に必要なすべてが含まれています。





NuGetのAR.Drone UIユーザーインターフェイス



このサンプルアプリケーションのおかげで、実装の複雑さを忘れて、さまざまな対話方法を使用してドローンを操縦する機会を与えるアプリケーションの作成に集中できます。



Intel RealSense SDK



次に、Intel RealSense SDKの最も興味深く、使いやすい(私にとって)機能の1つである音声認識を見てみましょう。



SDKは、音声認識に対する2つのアプローチをサポートしています。





最初のアプローチは、指定された言語でアプリケーションによって指定された一種のコマンドのリストであり、「リゾルバー」によって処理されます。 リストにない単語はすべて無視されます。



2番目のアプローチは、自由形式のテキストを「理解」するボイスレコーダーのようなものです。 このアプローチは、簡単な字幕の自動作成などに最適です。



このプロジェクトでは、ドローンに送信されるコマンドの有限数をサポートする必要があるため、最初のオプションを使用します。

最初に、いくつかの変数を定義する必要があります。



  private PXCMSession Session; private PXCMSpeechRecognition SpeechRecognition; private PXCMAudioSource AudioSource; private PXCMSpeechRecognition.Handler RecognitionHandler;
      
      





セッションは、後続のすべてのアクションがこのインスタンスから継承されるため、I / OおよびSDKアルゴリズムにアクセスするために必要なタグです。

SpeechRecognition- セッション環境のCreateImpl関数によって作成された認識モジュールのインスタンス。

AudioSource-オーディオ入力デバイスのインストールと選択を可能にするデバイスインターフェイス(コード例では、簡単にするために最初の利用可能なオーディオデバイスを選択しています)。

RecognitionHandlerは、 OnRecognitionイベントのイベントハンドラーを割り当てる実際のハンドラーです。



セッション、 AudioSource、およびSpeechRecognitionインスタンスを初期化します。



  Session = PXCMSession.CreateInstance(); if (Session != null) { // session is a PXCMSession instance. AudioSource = Session.CreateAudioSource(); // Scan and Enumerate audio devices AudioSource.ScanDevices(); PXCMAudioSource.DeviceInfo dinfo = null; for (int d = AudioSource.QueryDeviceNum() - 1; d >= 0; d--) { AudioSource.QueryDeviceInfo(d, out dinfo); } AudioSource.SetDevice(dinfo); Session.CreateImpl<PXCMSpeechRecognition>(out SpeechRecognition);
      
      





前述のように、簡単にするために、使用可能な最初のオーディオデバイスを選択します。



 PXCMSpeechRecognition.ProfileInfo pinfo; SpeechRecognition.QueryProfile(0, out pinfo); SpeechRecognition.SetProfile(pinfo);
      
      





次に、システムに問い合わせ、実際の構成パラメーターを見つけて変数に割り当てます( pinfo )。



認識言語を変更するには、プロファイルに多数のパラメーターを構成する必要もあります。 認識信頼レベル(より高い値で、より信頼できる認識が必要です)、認識終了の間隔などを設定します。



この場合、デフォルトのパラメーターは、プロファイル0( Queryprofileから取得 )のように設定されます。



  String[] cmds = new String[] { "Takeoff", "Land", "Rotate Left", "Rotate Right", "Advance", "Back", "Up", "Down", "Left", "Right", "Stop" , "Dance"}; int[] labels = new int[] { 1, 2, 4, 5, 8, 16, 32, 64, 128, 256, 512, 1024 }; // Build the grammar. SpeechRecognition.BuildGrammarFromStringList(1, cmds, labels); // Set the active grammar. SpeechRecognition.SetGrammar(1);
      
      





次に、認識システムを学習するための文法辞書を設定します。 BuildGrammarFromStringListを使用して、動詞と対応する戻り値の簡単なリストを作成し、文法番号1を定義します。



アプリケーションで使用するいくつかの文法を指定し、必要に応じてそれらの1つを含めることができます。そのため、サポートされるすべての言語に対して異なるコマンド辞書を作成し、SDKで認識される言語を切り替える機能をユーザーに提供できます。 この場合、適切な言語サポートDLLをインストールする必要があります。SDKをインストールすると、デフォルトで英語(US)言語のみのサポートがインストールされるためです。 この例では、デフォルトの文法と英語(米国)言語のみを使用します。



次に、 SpeechRecognitionインスタンスでアクティブに設定する文法を選択します。



  RecognitionHandler = new PXCMSpeechRecognition.Handler(); RecognitionHandler.onRecognition = OnRecognition;
      
      





これらの手順では、 OnRecognitionイベントの新しいイベントハンドラーを定義し、それを以下で説明するメソッドに割り当てます。



  public void OnRecognition(PXCMSpeechRecognition.RecognitionData data) { var RecognizedValue = data.scores[0].label; double movement = 0.3; TimeSpan duration = new TimeSpan(0, 0, 0, 500); switch (RecognizedValue) { case 1: DroneState.TakeOff(); WriteInList("Takeoff"); break; case 2: DroneState.Land(); WriteInList("Land"); break; case 4: DroneState.RotateLeftForAsync(movement, duration); WriteInList("Rotate Left"); break; case 5: DroneState.RotateRightForAsync(movement, duration); WriteInList("Rotate Right"); break; case 8: DroneState.GoForward(movement); Thread.Sleep(500); DroneState.Stop(); WriteInList("Advance"); break; case 16: DroneState.GoBackward(movement); Thread.Sleep(500); DroneState.Stop(); WriteInList("Back"); break; case 32: DroneState.GoUp(movement); Thread.Sleep(500); DroneState.Stop(); WriteInList("Up"); break; case 64: DroneState.GoDown(movement); Thread.Sleep(500); DroneState.Stop(); WriteInList("Down"); break; case 128: DroneState.StrafeX = .5; Thread.Sleep(500); DroneState.StrafeX = 0; WriteInList("Left"); break; case 256: DroneState.StrafeX = -.5; Thread.Sleep(500); DroneState.StrafeX = 0; WriteInList("Right"); break; case 512: DroneState.Stop(); WriteInList("Stop"); break; case 1024: WriteInList("Dance"); DroneState.RotateLeft(movement); Thread.Sleep(500); DroneState.RotateRight(movement); Thread.Sleep(500); DroneState.RotateRight(movement); Thread.Sleep(500); DroneState.RotateLeft(movement); Thread.Sleep(500); DroneState.GoForward(movement); Thread.Sleep(500); DroneState.GoBackward(movement); Thread.Sleep(500); DroneState.Stop(); break; default: break; } Debug.WriteLine(data.grammar.ToString()); Debug.WriteLine(data.scores[0].label.ToString()); Debug.WriteLine(data.scores[0].sentence); // Process Recognition Data }
      
      





これは、認識データから返された値を取得し、対応するコマンド(この場合、対応するドローン飛行制御コマンド)を実行する方法です。



各ドローンコマンドは、特定のメソッド( TakeOff、GoUp、DoDownなど)と、特定の移動量または継続時間のパラメーターを使用したDroneState呼び出しを参照します。



一部のコマンドでは、現在のアクションを停止するためにStopメソッドを明示的に呼び出す必要があります。そうでない場合、ドローンは受信したコマンドに従って移動し続けます(前のコードフラグメントのコマンドを参照)。



場合によっては、前のアクションが完了するのを待ってから新しいコマンドを送信するために、2つの異なるコマンドの間にThread.Sleepを挿入する必要があります。



認識を確認するために、使用可能なドローンがない場合でも、ドローンスタブ機能モードをオンにする変数(メインウィンドウのフラグによって制御されます)を挿入しました(このモードでは、コマンドは作成されますが送信されません)。



アプリケーションを閉じるには、 OnClosingメソッドを呼び出して、すべてのインスタンスとハンドラーを閉じて破棄し、一般的なシステムクリーニングを行います。



コードには、システムのテスト時にVisual Studio *のデバッグウィンドウに有用な情報を表示するデバッグコマンドが含まれています。



おわりに



この記事では、自然言語のインタラクションインターフェイスを使用してデバイス(ドローンのように複雑な)と対話する方法を説明しました。 コマンドの簡単な辞書を作成し、システムにそれを理解させ、それに応じて複雑なデバイス(飛行中のドローン)を管理する方法を説明しました。 この記事では、利用可能なドローン制御機能のほんの一部を示しています。 可能性は本当に無限です。



オリジナル記事



All Articles