2017年7月18日火曜日

[コラム]ROSで始めるロボティクス(13) ー Tango端末やDaydreamはAR/VRだけじゃない!XR元年はロボットのあり方も変える!


HTC ViveやOculus RiftなどPCベースのVR(仮想現実)以外にも、Tango端末のAR(拡張現実)やCardbordとDaydreamでのVR、それにMicrosoft HoloLensなどのMR(ミックスドリアリティ: 複合現実)などの技術を総称してXR(リアリティ)技術と呼ばれています。

2016年がVR元年ならば今年2017年は【XR元年】でしょう。しかし、ロボティクスにとってこれら技術のうち、特にTango端末は安価なのに高精度、そしてスマホサイズの小ささで、通信から処理までこなすという便利センサーとみなすことが出来るのではないでしょうか。
本稿ではTango端末をXRに使うのではなく、ロボティクスへと応用する方法について見ていくこととしましょう。



Tango端末とは

Tangoテクノロジーとは一言で言うとグーグルの3Dマッピング技術です。ロボティクス的に言えばVSLAM(Visual Simultaneous Localization and Mapping)技術を基本にした空間測位と自己測位のトータルソリューションです。

VSLAMは、動画や画像を解析して物体の特徴点をリアルタイムに追跡し、位置や姿勢などの3D情報を推定する手法で、これにより、壁や地面の検出、物体の感知を行うことができ、空間測位や現在位置の推定などを可能にするものです。

SLAMはロボティクスの重要課題

実はロボットにおける重要な問題の1つに「SLAM:自己位置推定と環境地図の作成」があります。今までは非常に高価な数多くのセンサーを使用して、大量の演算処理を行わなければなりませんでした。それがなんとTango対応のスマートフォンだけでSLAMが実行できるのです。

Tango端末を購入するだけでこれだけの高性能なセンサーとプログラムのセットが手に入るのです。このSLAM機能をロボットに応用しない手はありません。

筆者の所有するLenovo Phab 2 Proは世界初の Tango 対応スマートフォンです。現時点で販売されているTango対応端末はこのPhab 2 ProとZenfone ARだけです。

筆者のスマートフォンPhab 2 Pro

Phab 2 Proの充実したセンサー

本当にスマートフォンとは思えないセンサーの充実ぶりです。9軸IMUによる姿勢検出、魚眼レンズカメラからの視覚特徴点の相対位置(位置変化)を計算し端末の移動距離を推定、そして赤外線TOFセンサーが奥行きを測定してくれます。
もう、スマートフォンというよりは高性能なセンサーモジュールと処理ソフトウェアの塊にしか見えませんね。

Tango入門!実際にTangoを動かしてみよう

既にTangoの開発環境も充実しておりGoogleから取得してTango端末向けアプリを作ることが出来ます。それでは、実際にサンプルを動かしながら、Tango端末からのセンサー情報を取得してみましょう。AR、VRに使うわけではないので当然Unityは一切使用しません。

サンプルプロジェクトのダウンロードと実行

https://github.com/googlesamples/tango-examples-java/archive/master.zip をダウンロードします。

Android Studioを起動して「Inport project」より、java_basic_examplesディレクトリを選択してOKを押します。


プロジェクトが開いたら、ツールバーを見るといくつかのモジュールが存在していると思います。ここからhello_motion_trackingを選択してRunボタンをおして実行してみましょう。


実行するとAndroid Studioの下部に生の姿勢データが表示されます。


hello_depth_preception

では次にhello_depth_preceptionを実行してみましょう。これも同じくLogcatに生の値を吐くだけです。ただポイントクラウドはデータ量が多いからか距離の平均を出力しているようです。



Logcatを見るかぎり、おおよそ0.2秒間隔で3万6千個の点を取得出来ているようです。

heloo_area_descriptin

次に、hello_area_descriptinを実行してみましょう。このサンプルは先ほどまでのサンプルより複雑ですね。

Larning mode onにしてStartするとセンサーの値から領域を学習し、学習した領域をADFに保存します。

hello_video

お次はhello_videoです。

このhello_videoはとてもなめらかに動き、ほぼ遅延なくRGBカメラからの画像が画面上に表示されます。OpenGLで描画しているみたいですね。

それでは次です。どんどんサンプルの動作を確認していきましょう。

java_augmented_reality_example

java_augmented_reality_exampleです。これはTangoAPIでARアプリを作るための簡単なデモになっています。端末の約1メートル前に地球と、地球の周りを回る月を表示します。レンダリングにはRajawaliというレンダリングライブラリを使っています。

では、import projectをクリックし、java_augmented_reality_exampleを選択してOKを押します。


RajawaliはAndroid OpenGL フレームワークです。

実行すると次のように地球と月が表示され、位置がほぼ固定されます。ただ追従はあまりよくない感じですね。ちなみに奥にある地球儀と天球儀は実物です。


PointCloud

続いてPointCloudのJavaサンプルを見てみましょう。次のようにPointCloudを画面上に表示するサンプルになっています。

Android StudioのでInport projectを選択し、java_point_cloud_exampleを選択してOKボタンをクリックします。


ファイル構成は以下のようになっています。


各ファイルの役割は次のようになっています。

PointCloudActivity.javaJavaによる点群表示サンプル。メインアクティビティです。
PointCloudRajawaliRenderer.java点群データのレンダラーです。
 TouchViewHandler.java 標準的なパン操作とズームタッチ操作の処理を含む、VR設定のトップダウンビューと3人称ビューを追加するヘルパークラスです。
 rajawali/FrustumAxes.javapublic class FrustumAxes extends Line3D
FrustumとAxesの組み合わせを表すプリミティブ(基本的なもの)。錐台(すいだい、英: Frustum)は、錐体から、頂点を共有し相似に縮小した錐体を取り除いた立体図形の事。
Axesとは軸の事。
 rajawali/Grid.javapublic class Grid extends Line3D
現在のシーンの「床」を表すRajawaliオブジェクト。
これはシーンに配置された静的グリッドで、さまざまなビューにパースペクティブを提供します。
 rajawali/PointCloud.javapublic class PointCloud extends Points
色を使用して深度センサまでの距離を示すポイントクラウドをレンダリングします。
着色は光のスペクトルに基づいています。最も近い点は赤色で、最も遠くは紫色です。
rajawali/Points.javapublic class Points extends Object3D
Rajawaliの点のプリミティブ(基本型)です。
それでは詳しくみていきましょう。rajawaliフォルダ内のソースは見ていただくとして、メインとなるjavaファイルを詳細に説明していきましょう。


PointCloudActivity

onCreateでは、TangoPointCloudManagerを生成しています。また、PointCloudRajawaliRendererクラス(点群データのレンダラー)のインスタンス生成を行なっています。また、DisplayManagerを取得し、画面の回転方向をmDisplayRotationメンバ変数へ保持しています。

onStartでは、bindTangoServiceメソッド内で、Tangoサービスを通常のAndroidサービスとして初期化します。

onStopでは、OpenGLスレッドまたはUIスレッドで使用されているサービスが切断するまで同期します。Tangoコールバックスレッドでこの同じオブジェクトに対してロックしないでください。すべてのTangoコールバックコールが終了するまで、Tango.disconnectはここでブロックされます。Tangoのコールバックスレッドでこのオブジェクトをロックすると、デッドロックが発生します。

bindTangoServiceではTangoサービスを通常のAndroidサービスとして初期化します。 onPauseでmTango.disconnect()を呼び出すので、これはTango Serviceのバインドを解除するので、onResumeが呼び出されるたびに新しいTangoオブジェクトを作成する必要があります。サービスがOpenGLスレッドまたはUIスレッドで使用されているときに切断に対して同期させます。

setupTangoConfigはbindTangoService内で呼ばれるメソッドで、Tango設定オブジェクトを設定します。 この呼び出しを行う前に、mTangoオブジェクトが初期化されていることを確認してください。これはデフォルトの設定を使用して、さらに深度センサーを追加します。

startupTangoもbindTangoServiceメソッド内で呼ばれるメソッドで、Tangoサービスのコールバックリスナーを設定し、Tango接続後に必要なその他のパラメータを取得します。ポイントクラウドとTangoのイベントとポーズの更新をリッスンします。

setupRendererはonCreate時に呼ばれるメソッドで、Rajawaliサーフェイスビューとそのレンダラーを設定します。 これは、理想的にはonCreateで1回だけ呼び出されます。

setupTangoUxAndLayoutもonCreate時に呼ばれるメソッドでTangoUXの設定とそのリスナーの設定を行います。イベントは、例外条件が観測されたときに「DETECTED」とみなされ、根本原因が解決されたときに「RESOLVED」とみなされます。

画面のFirstボタンを押すとカメラが現在位置に設定されます。いわゆる一人称視点になります。

Thirdボタンを押すとカメラを現在位置に設定し、Z軸に45度回転し、更にカメラをY軸に45度回した位置に固定します。いわゆる第三者視点です。

Topボタンを押すとカメラを現在位置の上部に固定し上からの俯瞰表示にします。これらボタンの処理はTouchViewHandler内で行われます。

画面上には、getAveragedDepthメソッドで計算した平均深度とポイントクラウドの数が表示されています。


PointCloudRajawaliRenderer

ポイントクラウドのデータはXYZC形式で提供されるため、ポイントあたり4つのfloatを示します。
レンダリングされたポイントクラウドを更新します。 このためには、クラウドデータを取得した時点でポイントクラウドデータとデバイスポーズが必要です。
注:これは、OpenGLレンダリングスレッドから呼び出す必要があります。

Rajawaliは左手系を使用するため、共役四元数が必要です。

現在のデバイスポーズに関する情報を更新します。
注:これは、OpenGLレンダリングスレッドから呼び出す必要があります。


TouchViewHandler

標準的なパン操作とズームタッチ操作の処理を含む、VR設定のトップダウンビューと3人称ビューを追加するヘルパークラスです。


それでは実行してみましょう。実行すると次の画像のような点群表示が得られます。リアルタイムでかなり高速に点群表示できている事が確認できます。ただ、点群の更新はちょっと遅れるようですね。ロボット用の高額なセンサーみたいに応答性が良い、というわけではありませんが、スマホで使うには申し分ない速度でしょう。移動速度の遅い移動型ロボットには十分な感じがします。







では、これをロボティクスで使用出来るようにします。つまりTangoから得られたデータをROSメッセージに変換するわけです。

Android端末でROS

Android端末でROSを実行するには、次の手順で環境を構築しましょう。従来はROS
環境を構築する必要があったのですが今ではAndroidStudioをつかってROSの開発環境無しでROSのAndorid開発が出来るようになっています。AndroidでROSを動かすには、JavaでROSを動かすrosjavaというパッケージを使用します。

プロジェクトのbuild.gradleを編集します。次のような感じです。

task wrapper(type: Wrapper) {
    gradleVersion = '2.14.1'
}

buildscript {
    apply from: "https://github.com/rosjava/android_core/raw/kinetic/buildscript.gradle"
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

subprojects {
    apply plugin: 'ros-android'
}

次にアプリケーションを設定します。今度はアプリ内の方のbuild.gradle を開き、次のような感じに編集します。

apply plugin: 'com.android.application'

android {
...
    packagingOptions {
        exclude "META-INF/LICENSE.txt"
        exclude "META-INF/NOTICE.txt"
    }
    productFlavors {
    }
}

dependencies {
...
    compile 'org.ros.android_core:android_15:[0.3,0.4)'
    compile 'org.ros.rosjava_messages:sensor_msgs:[1.12,1.13)'
}

android {
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
    }
}


AndroidManifest.xmlに追加します。

<!-- To set up the connection to the master -->
<activity android:name="org.ros.android.MasterChooser">

        <!-- To manage to execute nodes like the node handler -->
        <service android:name="org.ros.android.NodeMainExecutorService">
            <intent-filter>
                <action android:name="org.ros.android.NodeMainExecutorService">
            </action></intent-filter>
        </service>
</activity>


これで準備はOKです。AndroidではRosActivityというアクティビティを使います。マスターセレクタにより、ROSマスターノードを指定したり、デバイス上で新しいマスターノードを開始したりできます。

さて、これでrosjavaによるrosプログラミング環境が整いました。いつでもAndroidを利用したロボット開発が可能です。ただ、センサーの値を取得してROSで受け取るだけであれば、tango ros streamerというアプリケーションがあります。

http://wiki.ros.org/tango_ros_streamer

アプリはGoogle Playで公開されており、ソースコードもgitから取得することが可能です。
さて、長くなってきましたので、続きはまた次回としましょう。次は、実際にAndroidのTangoから取得したセンサーの値をマスター側で受け取り、RVizで表示してみましょう。


ROSで始めるロボティクス(9) ー ROSを使ったステレオカメラキャリブレーション
ROSで始めるロボティクス(10) ー オムニホイールで全方向移動可能ロボットを作る 1
ROSで始めるロボティクス(11) ー オムニホイールで全方向移動可能ロボットを作る 2
ROSで始めるロボティクス(12) ー ROSの入門機に新しくTurtleBot3が加わります
140 180 Phab 2 Pro , ProjectTango , ROS , SLAM

記載されている会社名、および商品名等は、各社の商標または登録商標です。

1 コメント:

Related Posts Plugin for WordPress, Blogger...