記事の目次

    今回からは、レーザー式測域センサを利用したコンテンツを考えていきます。ひとまずUnityで使えるようセットアップをし、簡単なインタラクティブコンテンツをつくってみましょう。

    TEXT_高田稔則 / Toshinori Takata(Codelight
    EDIT_小村仁美 / Hitomi Komura(CGWORLD)

    <1>測域センサのしくみと種類

    本年もよろしくお願いいたします、高田です。今回は、前回紹介した北陽電機の測域センサを利用したコンテンツを考えてみます。測域センサには何種類かありますが、今回使用したのはレーザー式測域センサUST-10LX-H01です(以下UST)。このセンサはもともと工場の立ち入り禁止の領域に人が立ち入ると警告を出すシステムの構築などに使われていました。最近はロボットやドローンに搭載して環境の認識に多く使われています。


    動作イメージ(北陽電機Webサイトより)

    弊社が初めてこのセンサを利用したのが2010年でした。常設展示のコンテンツに組み込んでからすでに8年以上経過し、センサの商品としての耐用年数は超えているのですが、大きな問題もなく現在も稼働しているので安定性は高いと感じています。

    UST-10LX-H01の取扱説明書を読むと、「USTは赤外レーザー(波長905nm)光により、水平面上の空間を0.125度ピッチで270度スキャンし、対象物の距離計測とそのステップ角度により座標を計算し、通信により角度ごとの距離データを出力するセンサです」とあります。

    赤外線で距離を計測するセンサとしてはMicrosoft Kinectがコンテンツ制作で多く使われていましたが、2017年10月に生産が終了しました。これは正確には色の代わりに奥行き情報を得ることのできる深度カメラで、人物のポーズを認識できる非常に便利なセンサでした。現在販売中の深度カメラとしてはIntel RealSenseZEDOrbbec AstraXtion 2などがありますが、Kinectと同じくらい手軽にポーズ認識ができるセンサはありません。Kinectは、現在後継機がKinect for Azureとして開発が進んでいます。デモを見ると精度が高く発売されるのが楽しみです。

    Tech Showcase: Project Kinect for Azure depth sensor technology

    <2>USTセンサを採用するメリットとは?

    これらの深度カメラはいずれも数万円で購入可能ですが、USTは15万円以上します。高額なUSTをコンテンツ制作で使う利点はどこにあるのでしょうか?

    例を考えてみましょう。「長さ15m、高さ3mの壁に3台のプロジェクタで映像を投影し、壁をタッチすると花が咲くコンテンツをつくりたい」という相談があったとします。チームラボさんの作品などで良くみられる演出です。下のように壁の前にセンサの幕を作り(緑色の部分)、それに触れた場所を特定できれば実現できそうです。


    ●Kinect for Windows v2の場合

    このようなシステムを、Kinect for Windows v2(以下、Kinect v2)を用いて組むと以下のような構成になると思います。


    センサの幕を作るため壁の上部に下向きに複数設置します。Kinect v2はPCに1台しか接続できないので同じ台数のPCが必要になります(v1は4台まで接続できました)。さらにKinect v2はPCとUSB 3.0で接続されますが、その伝送距離は3mしかありません。USBリピータでケーブルを延長しても動作が不安定になる可能性があるためPCとKinect v2の距離を取ることが難しく、設置条件が制限されます。さらにKinect v2の水平画角は70度程度なので壁のかなり上に設置しないとセンシングの死角が多くなります、取得できる距離も4,500mm程度なので実際にはかなり制限が出てくると思います。また、壁全てに共通の演出を出すためには、それぞれのPC間でデータを同期する必要があり開発の工数が増えてきます。

    ●Intel RealSenseの場合

    Kinectの代替としてMicrosoftが推奨しているIntel RealSenseを使えば以下のような構成が考えられます。


    RealSenseはPCへの複数台接続が可能なので制御用PCが1台で済み、コンテンツ制作がかなり楽になります。画角は85.2度、深度も10mまでセンシング範囲が広がりますがUSB3.0での接続に関する設置場所と死角の問題は完全にはクリアできません。

    ●USTの場合

    USTを使った場合は以下のようになるでしょう。


    PC1台で済み、センサがカバーできない部分がありません。PCとはEthernetで接続されるため設置に関してもかなり自由になります(Ethernetの伝送距離は100m)。制御用PCが減りコンテンツ制作が簡単になること、センサがカバーできる範囲が広いことがUSTを使う大きな理由です。全体の工数を考えれば多少高額なUSTを選択しても十分なメリットがあるというわけです。

    では、実際に使ってみましょう。北陽電機のWebサイトにアクセスし、会員登録後ログインするとファームウェアやデータ確認ツールをダウンロードすることができます。



    データ確認ツール「URG Benri Plus」

    今回使用するセンサは計測範囲10m、角度分解能0.125度のモデルです。以下の範囲でデータを取得することができます。

    PCと接続して、URG Benri PlusのEthernetタブの接続ボタンを押すとセンサの様子が表示されます。


    次ページ:
    <3>測域センサのデータをプログラムで取得する

    [[SplitPage]]

    <3>測域センサのデータをプログラムで取得する

    センサのデータを取得するプログラムを準備します。北陽電機製センサのプログラム情報は下記のサイトにまとめられています。

    ●URG Network
    https://sourceforge.net/p/urgnetwork/wiki/top_jp/


    C/C++、C#、Java用のライブラリが公開されていますが、今回はUnityで直接使用したいのでC#用のサンプルを利用します。[ダウンロード]以下のリンクからUrg_cs_sample.zipをダウンロードして展開します。


    Urg_cs_sampleを展開すると以下のようなファイル構成になっています。


    Urg_cs_sample.slnをVisual Stuidio 2017で開き、get_distance_ethernetプロジェクトを実行します。IPアドレスとポート番号を聞いてきますので、[Enter]キーを押して進めると深度情報が取得されます。


    これをUnityで直接使えるようにしていきます。Urg_cs_sample\get_distance_ethernetフォルダのget_distance_ethernet.csをベースにします。get_distance_ethernet.csはTCPで測域センサと接続し、流れてくる情報を解析して100番目の距離データを10回表示するように実装されています。しかしコンテンツで使うためには270度全ての距離データを取得する必要があります。

    プログラムを見ていくと、距離データの取得を行なっているのは以下の2行です(39、40行目)。

    string receive_data = read_line(stream);
    if (!SCIP_Reader.MD(receive_date, ref time_stamp, ref distances)) {
    

    long型のListとして宣言されているdistancesにミリの単位の距離が返ってきます。ここを毎フレーム呼び出すことができれば各ステップの距離を取得することができます。ただ、距離データ取得のタイミングには注意が必要です。開発情報に書いてある通り物体の位置を検出するためには各ステップの距離の差を基にクラスタリングを行います。


    URG Network より

    このセンサは1回の距離データを取得するのに25msかかるため、60fpsのコンテンツでデータ取得処理をUpdate関数内で行うと何度も同じ距離データを取得することになります。

    これを図式化してみました。上段がUnityのUpdate、下段がセンサのデータ取得の時間のながれです。Updateごとにデータを取得し、緑の時間で物体検出を行うと何度も同じデータを処理することになるため無駄が増えます。


    Update関数から距離データ取得と物体検出する場合(緑が物体検出処理)

    そこでUpdate内では位置検出の処理を行わず、距離データ更新と位置検出処理をまとめて別スレッドで行うようにしてみます。


    距離データの取得と位置検出を並列化した場合

    こうすることで同じデータを処理することがなくなり、処理を並列化できるためfpsを稼ぐことができます。get_distance_ethernet.cs はMain()、get_connect_infomation()、read_line()、write()の4つのメソッドが定義されていますが、使いたいのはread_line()とwrite()だけです。

    これを残して、URGSensor.csとして書き直したプログラムをGitHubに置きました。あわせて距離データ取得と物体検出処理を別スレッド化し、検出時の演出も少し入れてあります。Unityはバージョン2018.1から.NET4.xを正式にサポートするようになりました。今後並列処理を新しく書く場合はできるだけTaskを使うべきと思います。しかし.NET4.xランタイムを指定するとデータが遅延する現象が確認されたため、.NET3.xを使い従来のスレッドを使い実装しています。

    ●今回のプログラム
    https://github.com/toshinoritakata/URG

    <4>測域センサで物体を検出する


    もう一度この図を見てみましょう。基本的にはステップごとの距離の差が大きくなった部分をまとめることで物体があることを検出します。


    黄の線:1つ前のステップとの距離の差が指定した値より大きい
    緑の線:1つ前のステップとの距離の差が指定した値より小さい

    距離の数が8個の場合で単純なクラスタリングのアルゴリズムを考えてみます。s0から順にs7まで順に距離の差を見ていきます。物体を検出させるための距離の差を「閾値」として適当な値を指定します。s1とs2の距離の差が閾値よりも大きいので、物体があるとみなしてp2の位置をPとして代入します(P = p2)。

    次にs3とs2の距離の差を調べます、閾値よりも小さいのでPに加算(P = P + p3)、同様にs4とs3の距離の差を調べ、閾値よりも小さいのでPに加算(P = P + p4)。s5とs4の距離の差を調べ、閾値よりも大きいので物体がなくなったとみなし、Pを加算した回数3で割ります。s6,s7は距離に差がないので何もしません。これで1つの物体の中心が求まりました。この手法で検出された様子を見てみましょう。

    黄色の線の先に球が見えると思います。そこが認識された位置です。これを基に、検出した位置にパーティクルを表示させるサンプルをつくりました。以下のようにセンサを設置し、壁にUnityの画面を投影します。


    壁に対してお手玉を投げるとそれを認識してパーティクルが発生します。 タイムラグが結構ありますが、調整できると思います。ソースは前述のGitHubに置いてあります。次回ももう少しこれを基に進めていきたいと思います。

    ●今回のプログラム
    https://github.com/toshinoritakata/URG

    Profile.

    高田稔則/Toshinori Takata(Codelight)
    Codelight株式会社 代表取締役・インタラクションエンジニア
    フリーランス、株式会社TBSテレビ等で映画CG制作、株式会社ソニー・コンピュータエンタテインメント(現 ソニー・インタラクティブエンタテインメント)でPS4のOSD開発などを経て2006年にCodelight株式会社を設立。インタラクティブコンテンツの制作を中核として、製造業向けのプロトタイプ開発なども行う
    www.codelight.co.jp