13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

我は神龍……どんな平面でも一つだけタッチスクリーン化してやろう

Posted at

こんにちは。あつし(@Anaakikutsushit)です。

株式会社モフさんから「どんな壁でもタッチスクリーンにできるシステムが欲しいんだけど、お願いできない?」とお声がけ頂きまして、その開発にあたっての備忘録として本記事を書きました。技術情報の公開自体は許可を頂いております。

壁面への映像の投影、およびタッチ処理を実現するためのOSはWindowsの想定です。

すなわち、プロジェクターで映し出したWindows PCの画面を直接タッチして操作可能にすることを想定しています。

開発は Windows10、C++、およびC# で行いました。やってた感じではMacでも出来そうです(未検証)。

任意の壁をタッチ操作可能にするシステムを作ろう

タッチ方式についての前提知識

そもそもタッチスクリーンを実現するには

平面をタッチスクリーン化するためには、少なくともタッチした点の座標を特定することが必要となります。
タッチ座標を特定するために、古今東西さまざまな動作原理が利用されてきました。

タッチパネル - 動作原理別(Wikipedia)

身近なところではニンテンドーDSやWiiUゲームパッドでは抵抗膜方式(感圧式)を、スマホやタブレットでは静電容量方式を採用しています。

今回採用する方式

しかし、今回目指すシステムは表面の素材に左右されずタッチスクリーン化することが要件となってきますので、上記の2つの方式はどちらも採用できません。

今回の開発では赤外線方式によるタッチスクリーン化を採用しました。

ちなみに:こんなプロダクトも

専用のペン型デバイスをPCにBluetooth接続することでタッチスクリーン化を実現するプロダクトもあります。

画面がデジタルボードに変身!書き込み、保存、共有、遠隔会議も『GoTouch』

これはかなりいい感じのプロダクトなのですが、対応可能なサイズは80インチまでとのこと。今回のプロジェクトではタッチスクリーン化したい壁面が100インチ級になる可能性があったため、見送りとなりました。

先駆者の方々

赤外線方式を利用したタッチスクリーンシステムの開発については幾人かの知見があり、参考にさせて頂きました。

使用機材はいずれも本記事とは異なりますが、システム構築の概念は共通したものです。似たようなシステムを開発する場合に参考になるかと思います。

赤外線カメラを使用した壁タッチセンサー

ウォールタッチパネルを5千円ぐらいで作りたい-その1

システムの概要

今回はLiDARと呼ばれる距離測定センサーを使ってタッチ座標を検出します。

1.jpg

(下記Amazon商品ページより引用)

製品としてはRPLiDAR社のA1M8を使用しました。
Amazon等で購入することができます

こちらのLiDARは、上部の丸い部分の側面の窓からレーザーを照射し、距離を測定する仕組みとなっています。

丸い部分が回転することによって360°全方向の距離をリアルタイムに測定可能にしているというわけですね。

測定結果のイメージは上記公式サイトで確認できます。

その他、LiDARの詳細については公式のサポートベージで確認可能です。

今回のシステムではその機能を利用して、次の図のようにシステムを組み上げていきます。

2.png

  • LiDARを横倒しにして、壁と平行な平面を検出するようにする
    • このとき、検出平面をなるべく壁に近づけることで精度がよくなります(壁に触れていないのにタッチ判定されることが少なくなる)
    • 別に壁じゃなくても大丈夫です。床でも天井でも、デスクの上でも。平面に平行な面を検出するようにLiDARを設置するとこだけがポイント。
  • 検出平面内に指が入るとLiDARでその位置を特定できるので、特定した指の位置に対してクリック処理を起こす
  • 図では「検出平面の横幅に対して中心」かつ「検出平面の上方」にLiDARを設置していますが、この設置場所もどこでも大丈夫です。
    • 私が開発したときは、この位置に置くと座標の計算がやりやすかったというだけです(計算式は後述)。
    • ただ上記型番のLiDARは、~10cmの近距離検出がニガテっぽいです。検出平面内に置くのは避けたほうがいいかも?

必要な機材

  • LiDAR
    • 上記機種でなくてもイケると思います。"360 lidar sensor"などのキーワードで検索すると、類似商品がたくさん見つかります。
  • ケーブル類
    • 上記A1M8の場合、インターフェースがmicro USB-Bになるので、必要に応じてUSB-Aに変換するケーブルも用意してください。
    • USBケーブルは伝送距離の上限が5mと規格で定められていますが、リピーターケーブルと呼ばれる長距離用の延長ケーブルを利用することで規格以上の距離を接続することが出来ます。壁とPCの間が離れているときに使ってください。
    • 参考:USBアクティブリピーターケーブル特集

センサーを使ってみる

センサーを接続する

本項は公式の開発マニュアルに準じます。

まずはUSB接続したLiDARをPC側で検出可能にするドライバをインストールしてください。

ドライバへのリンクはマニュアル上に記載されていますが、本記事執筆時点ではリンク切れ。こちらのリンクからドライバを入手しましょう。

PCに接続するとセンサー部分がグルグルと回り始めます。しかしLiDARが回っていてもPCで認識できていない場合もあります。しっかりとデバイス一覧にLiDARが載っていることを確認しましょう。

SDKをダウンロードしてビルドする

公式のGitHubからSDKを入手できます。

SDKはVisual Studio 2010でしかビルドできない仕様になっているのですが、有志の方がVisual Studio 2017や2019でもビルド出来るように修正してくれました。

現在だと2010は入手しづらいので、当該バージョンのVisual Studioを持っていない方はこちらの修正を適用してください。

[apps][fix] Make examples compilable in Visual Studios 2017 and 2019

あとはVisual Studioでソリューションを開き、ビルドできればOKです。

デモンストレーション用のアプリを使う

本項はタッチスクリーン開発とは無関係です。しかし、LiDARがどのように動作しているかのイメージを掴むために有用です。

outputディレクトリ以下に生成されたアプリframe_grabberを起動して、実際にLiDARを使ってみましょう。

各種初期設定を済ませてアプリを実行してみると、下記のような測定データがリアルタイムに表示されると思います。

また、output以下にある別のアプリultra_simpleを使ってみると、どのような形式でLiDARがデータを取得しているのかをより良くイメージできるでしょう。

ultra_simpleでは次のデータを取得できていることがわかります。

  • 角度
  • 距離
  • 測定品質

LiDARの動作イメージが掴めたら、早速開発に取り掛かっていきましょう。

センサーの値を利用するプログラムを書く

C++側のコードを書く

先ほど利用したultra_simpleなどは元々C++で開発されています。

しかし、筆者はC++に不慣れなため、新規のコードはC#で書いて、既存のC++のコードと連携させることにしました。

C++のコードをC#から利用するには、C++上でC#から呼び出すためのコードを書き、DLL形式で出力し、出力したDLLをC#で読み込むという手順が必要になります。

詳しくは下記の参考資料を読んでみてください。

上記ではUnityの話をしていますが、UnityもC#で動くらしいんで同じことです(たぶん)

そういうわけでまずはC++側……つまりultra_simpleのコードから必要な部分だけを切り出して、C#側で使えるように準備していきます。

具体的には、下記の処理をする関数をDLLとしてエクスポートし、C#から利用しました。

  • 使用するLiDARの個数を定義する
  • LiDARを初期化する
  • LiDARの回転をスタートさせる
  • LiDARから測定データを読み出す
  • LiDARの回転をストップして終了させる

DLLの中身がちゃんと出来ているかな?と確認するには、Dependenciesというアプリを利用すると便利です。

なんだか上手く利用できないな?ということがあったら、上記ツイートのように原因を特定するのに役立ててください。

C#側のコードを書く

C++から値を受け取る

C#側ではGUIを作って、各種パラメータを入力し、測定開始・終了が出来るようなデザインにしました。
その辺はいい感じに作ってください(丸投げ)

ところで、C#とC++の間でデータをやり取りするにあたって型の変換が発生しますよね。

その辺りはちゃんと対応した型を双方指定する必要があります。「C++ C# マーシャリング」などのキーワードで検索してみると詳しい情報を得られるかと思います。

受け取った値をモニター上の座標に変換する

本項はコーディングというよりも数学の話になります。

LiDARが取得するデータは二次元極座標で表される角度と距離のデータ。

しかし、PC上でクリックイベントを発生させるためには、モニター左上を原点とした二次元直交座標で指定しなければなりません。

その変換については、タッチスクリーン化したいスクリーンの縦横の幅と、LiDARからスクリーンまでの距離を既知のものとして、下図の計算で求めることが出来ます。

3.png

LiDARをスクリーンの上に置くか下に置くかで式が変わってきますが、その条件はGUIから入力します。

ちなみに:この図はGeoGebraで作成しました。「条件内であれば各点がどの場所にあっても計算結果が破綻しないな」ということを実際に点QやLiDARの位置をグリグリ動かしながら確かめられます。大変助かりました。

また、数式の検証にあたってトゥーンさん(@Toon_Scarlet)にご協力頂きました。ありがとうございました。

特定の座標にクリックイベントを発生させる

下記記事を参考にしました。

C#で指定した位置をクリックする

「指定座標にマウスカーソルを移動させる関数」と、「任意のマウスイベントを発生させる関数」の2つを組み合わせることで、壁のタッチ位置にクリックイベントを発生させるロジックを組んでいます。

今回のプロジェクトでは、「ポイントはしているけどクリックはしていない」という状態はありません。

LiDARが検出したら常にクリックする⇔LiDARが検出していなければクリックしない、という2状態のみです。

ただしそれだと指が壁に触れている限りクリックを連打してしまうことになるので、2回以上クリックしたい場合は壁から指を離したあとでもう一度触れる必要があるという仕様にしました。

完成

開発にあたってつまずいた部分など

あとは作ったものをテストしつついい感じに調整していけば完成となります。

ソースコードの類はテストと修正が容易なのですが、物理的な機器に関しては問題点の洗い出しが少々面倒でした。

ちゃんとPCに接続しているのにデバイスが認識されなかったり、ケーブルの角度や向きをいじってみたら何とか認識される……みたいなことも結構あってツラかったです。

LiDARを複数接続する場合はやっぱりUSBハブがあると安心かなと思って、ちゃんとAC電源からセルフパワーで供給するものを購入して使ってみたりしたんですが、それでも動作は不安定になってしまいましたね。

可能な限りUSBハブは使わずに直接PCに接続するのが安定させるためのコツみたいです。

公式サポートへの問い合わせでもその回答でしたし、本番でもハブを使わないことで安定して動作してくれました。

本システムの採用実績

かなり汎用性の高いシステムですので、モフさんの方で今後さまざまなプロジェクトに使っていって頂けることでしょう😊これからの展開に注目です。

もちろん、私個人としても何かしらのプロジェクトに使っていきたいですね💪

富士通「CLIP-LIVE」

富士通さんの「CLIP-LIVE」において本システムを採用して頂きました。

実際に動いてるところはこんな感じ↓

マウスクリックでインタラクションする、プロジェクター投影用のコンテンツを別で作っておいて、私のタッチスクリーンシステムと組み合わせて頂いた形ですね。

謝辞

最後に、本システムの開発にあたって株式会社 猫とロボット社代表の飯田尚宏さんに技術的なアドバイスを頂きました。大変助かりました。この場を借りてお礼申し上げます。

その他、参考にさせて頂いた各記事にもお世話になりました。ありがとうございました。

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?