ドローン操作の難しさ

ドローン操作って、すごく難しいと思いませんか?

  • 自分と同じ向きに向いているときはいいけど、逆向きの時は右に動かすつもりが左に動き、左に動かすつもりが右に動く…
  • ていうかそもそもドローンが今どっちを向いているのかもよくわからない
  • あれ?ドローンって左右だけじゃなくて前後移動も上下移動もあるじゃん!!
  • え?斜め移動もありなの??
  • 回転しながら移動とかムリムリー

てな感じで。操作しながらパニックに陥ること間違いなしです。

ちなみに私、手先が不器用で字も下手くそで車の運転も苦手で、車体の側面ゴリゴリ削った前科も2犯ぐらいあるので、ドローン操作もどんなに練習してもうまくはならないだろうなーと思ってました。

バーチャル3Dコントローラ

そんな超不器用な自分でも簡単にドローン操作できる方法はないか。 例えば、小さな子供が「ぶーん」とか言いながらおもちゃの飛行機を動かす感じで操作できれば…ということで思いついたのがバーチャル3Dコントローラです。

具体的な操作イメージはこんな感じです:

  1. バーチャル空間にドローンのモデルを浮かべておく
  2. バーチャル空間にあるドローンを動かしたら動かした方向(左右上限前後どこでも)に現実のドローンも移動する

「仮想空間上にあるおもちゃのドローンを動かせば現実のドローンが動く」そんなイメージです。

昔の言葉でたとえて言うならば WYSIWYG なドローン操作 ですね。

ユーザーインターフェースの実装

実際に Unity でこれを 素直に作ってみたら、こんなユーザーインターフェースになりました。

バーチャル3Dコントローラ

実際の操作対象となるドローンは Tello なのですが、そのものずばりの Tello のモデルが Sketchfab にあったので、ありがたく使わせていただきました (Dji Tello by Temoor on Sketchfab)。

このモデルに対して MRTKObjectManipulator を追加することで、手でつかんで移動することが可能になります。スクリプトを一切書かずにこれができるようになるので MRTK はこの手のアプリケーションを作る際には必須です。

3DUXに対する配慮

基本的な設定は以上で終わりなのですが、不自然な動きでユーザーにストレスを与えないようにするためにいくつかの設定を追加しています。

  • ObjectManipulator の OnManipulationEnded イベントにイベントハンドラスクリプトを追加して、オブジェクトから手が離れたときに自動的に中央位置に戻る動作を追加
  • RotationAxisConstraint を追加して、どの軸に対しても回転しないようにする
  • ElasticsManagerを追加して、中央位置に戻る際にばねで引っ張られるような動きにみえるようにする。

このあたり、どれも細かい話なんですが、実際に設定を外して動かしてみるとかなりいまいちな感じになるのでどの設定も必須かなと思います。 こういう細かい配慮に関しては、ちょっとやそっとの経験では気づかない部分だと思うのですが、それをあらかじめすぐ使える部品の形で提供してくれている MRTK は本当に素晴らしいです。

回転操作の方法

RotationAxisConstraint の設定により、つかんだ手の動きでモデル自体を回転させることはできなくしているので、回転操作に関しては別のユーザーインターフェースを用意しています。 「右または左にあるボールに手を触れている間だけ回転する」という動きです。

回転動作

両手を使えば(例:「右手で Tello モデルを動かしつつ左手でボールに触れる」)、移動と回転を同時に行うこともできるようになっています。

Tello モデルの位置や回転をコマンドに変換する

Tello モデルの位置や回転をドローンに送信するコマンドに変換するには、スクリプトを書く必要があります。

ドローンとの通信制御の細かい部分は前回の記事で紹介した Tello Low-Level Protocol Wrapper のコマンドを使用します。ここで利用できる「stick コマンドとして渡す文字列を組み立てて、それを送信する」というスクリプトを書きます。

位置情報(移動方向)と回転情報は同一の stick コマンドで同時に送信できるためこの2つの情報を組み合わせてひとつのコマンド文字列にします。

  • 回転: stick コマンドの lx 引数 (3番目) として以下の3種類の値を渡す
    • 右側のボールに触れているとき → 0.5 : 右回転 (時計回り)
    • 右側のボールに触れているとき → -0.5 : 左回転 (反時計回り)
    • どちらにも触れていないとき → 0 : 回転なし
  • 移動: stick コマンドの rx 引数 (1番目)、ry 引数 (2番目)、 ly 引数 (4番目) として渡す
    • rx: 左右 (x軸) の位置情報
    • ry: 前後 (z軸) の位置情報
    • ly: 上下 (y軸) の位置情報

移動の引数として渡すのは「現在 Tello モデルが中央位置 (x=0, y=0, z=0) からどれぐらい離れているか」を表す位置情報です。 これは Unity のスクリプトでは transform.localPosition.x, transform.localPosition.y, transform.localPosition.z で取得できます。

コードとして書き起こすと以下のようになります。

// コマンド文字列の組み立て
var rx = transform.localPosition.x;
var ry = transform.localPosition.z;
var ly = transform.localPosition.y;
var lx = (...回転の値取得)
var command = $"stick {rx:F2} {ry:F2} {lx:F2} {ly:F2} 0";

// コマンドの送信
tyDrone.EntryCommand(command);

stick コマンドの引数として与える値はいずれも -1.0 から 1.0 の範囲をとります。 1 もしくは -1 に近づけば近づくほど移動スピードが増し、0 で移動を停止します。

従って、「Tello モデルを中心から離せば離すほどスピードが増す」という動作になります。

なお、Tello モデルから手が離れているときは、モデルの位置に関係なく常に 0 を送信しています (手を離れた後のモデルの位置は操作者の意図を反映していないためです) 。

スピードアップ操作に関するUXデザイン

ドローンはスピードを上げれば上げるほど制御が難しくなり、衝突などの危険度が増すことになるはずです。 そこで、過度なスピードアップを防止するために、スピードアップ操作 (中心からTelloモデルを離す操作) に関してはUXデザイン上の工夫を行いました。具体的には以下2つです。

  • 中央から一定以上離れたら Tello モデルの色を変える
  • 中央から一定以上離れるとだんだん引っ張るのが難しくなる
スピードアップ時の動作

前者の「色を変える」は具体的に言うと「距離に応じて徐々に赤みを強くしていき、赤みがマックスに到達したら次に黒みを増していく」という色変化を実装しています。 「スピードを上げすぎるとヤバいよ」ということを色で視覚化したかったのですが、実機を使って体験してみると効果薄でした。 というのも操作中はTelloモデルよりも実機のほうを見ちゃうので色があまり気にならないんですよね。また、これに関して少し調べてみたところ、そもそも人間は周辺視野では色の認識がきちんとできないという学術的な実験結果があるようです。ということで、せっかく実装したので機能自体は残してはいますが、あまり意味のないデザインといえるでしょう。

後者の「引っ張るのが難しくなる」動きについては、Telloモデルが中心部分とゴムで結ばれている状態をイメージしてもらうとわかりやすいかもしれません。 これもMRTKのElasticsManagerの設定で実現しています。こちらは手元を注視していなくても、期待通りの動きになるのでかなり効果的でした。

スピードアップ防止のためのUXデザインに関しては、実機でテストしてみるともうひとつ最も効果の大きいデザイン要素があることに気付きました。 それは「中心から Tello モデルを離せば離すほどスピードが上がる」というデザインそのものです。 なぜこれがスピードアップ防止につながるかというと、身体(手や腕)可動域の限界が制約になるからです。 身体の中心付近に手を置いてモデルを動かすのは簡単ですが、手が体から離れれば操作は難しくなります。これはなかなか面白い発見でした。

周辺視野の色認識の件もそうなのですが、3DUXのデザインにおいては、こういった人間工学的な知識や工夫が最も重要になりそうです。

実機からのフィードバック

ここまで「バーチャル空間上の Tello モデルを使って現実世界の実機を動かす」に関して説明してきましたが、今回実装した仕組みでは「実機からバーチャル空間へのフィードバック」も重要な役割を果たしています。

バーチャル空間と現実世界のフィードバック

フィードバックの内容は機体の水平方向の角度 (yaw) です。この情報に従ってバーチャル空間上のTelloモデルも角度を変更するようにしています。

機体からのフィードバック

これにより実機とモデルの向きが一致するため、「見たまま動かしたい方向に動かせばよいだけ」という操作感が実現できます。

実際の動作

これを実際に動かしてみるとこんな感じになります。

デモ飛行

当初の目標「超不器用な自分でも簡単にドローン操作できるようになる」についてはかなり満足度の高いレベルで実現できている気がします。 ただし少し動作にはタイムラグがあったりもするので、「小さな子供がおもちゃの飛行機を動かす感じ」という「完全一致」レベルの操作感ではありません。 どちらかというと、Tello モデルのばねのような動きと相まって凧あげのような操作感に近いです。 もちろん凧あげに比べるとかなり自由度は高いのでめっちゃ楽しいんですが。

ちなみに私、Telloを入手してからもう半年以上になりますが、普通のコントローラでの操作はいまだにできません 😇

ソースコードの公開について

こちらのソースコードに関しては Lynx R-1 が無事入手できて、実装対応が完了したら公開する予定です。

デモ動画のように Oculus Quest のパススルーは白黒画像で実機ドローンの視認性がいまいちなので、カラーパススルーの Lynx R-1 には超期待しています(出荷は当初の予定よりかなり遅れていますが…)。

Tello 関連記事