公開日:2022/07/02
title.png

21st Season


#21-6 ペンタブレットを作る

 マウス🐭の代わりに、筆圧検知可能なペンとタブレットを使う入力デバイスがあります。ペンタブレットと呼ばれることが多いみたいです。

 今回は、Arduino DUEと、TFTシールドを使って(下図)、ペンタブレットを作って見ようと思います。

a119_due.jpga109_shield.jpg

 上図(右側)のTFTシールドは、Arduino DUE(上図左側)にシールドとして装着が可能で、4線抵抗方式タッチパネルの機能が付帯しています。

ペンタブレット(基本設計)

 大抵のArduinoは、USBでPCと接続してプログラムの書き込みができますが、そのUSBポートはプログラム書き込みにしか使えなくて、その他の用途に使えないことが多いです。ところが、Arduino DUEやSTM32、Arduino Micro等の機体では、Mouseライブラリなどを導入することで、HID(Human Interface Devices)として使用できるものがあります。

 今回は、その中からArduino DUEを使います。
 ペンタブレットを制作するに当たって、もう一つ重要なアイテムがタッチパネルなのですが、DUEならTFTシールドを使うことで手軽にタッチパネルを使用できます。下図は、DUEにTFTシールドを装着したところです。

a121_due_tft.jpg

2つのモード

 ペンタブレットを使ってPCのマウスカーソルを操作する方式として、2つのモード(相対座標モードと、絶対座標モード)をコンパイルオプションで選択可能とします。

 どちらのモードにしても、HIDマウスを使っているだけなので、基本的にはマウスの機能範囲を超越できません。

 実は、TFTシールドが採用している4線抵抗方式タッチパネルでは、筆圧を検知することができます。しかし、HIDマウスを使う以上、検知した筆圧をPC側へ伝える機構がありません。これは残念……。
 ですので、ペンタブレットと言ってもマウスと同じです。アイテムをポイントできて、2個のボタンによって操作ができる。……PCでお絵かきツールを使っても、筆圧対応のグラフィック描画とかはできません。

マウスボタンの実装

 そうか、マウスボタンも必要なのでした。
 左右2個分のマウスボタンをタクトスイッチで作り込むこととします。
 「#13-6 赤外線リモコンを作ろう」で実装したのと同じ工夫で、DUEのI/Oポート2本をINPUT_PULLUPとLOW出力にしておき、間を2端子のタクトスイッチ(下図)で接続します。

a137_tactsw.jpg

 DUEの41ピンと45ピン間、および49ピンと53ピン間に上図の様な2端子タクトスイッチを接続します。41,45,49,53ピンは、UNOと比べてDUEで追加になった2列ピンソケットに引き出されています。ピン配置表は、「#11-9 一の次は二」から、Arduino HPを参照して見てください。
 上図の様な2端子タクトスイッチを接続し易い様に、物理的に1ピン飛ばした端子を選んであります。実装してみた様子を以下図に示します。

a216_switch.jpg

 ブレッドボードなど、外部に回路を構築することなく、マウスボタン×2個も実装することができました。

TFT画面表示の処置

 ペンタブレットの中には、普通の液晶ディスプレイみたいにPCの画面が表示されて、そこに直接ペンでタッチすることでお絵描きできたりするものもありますよね?
 今回使うTFTシールドも、TFT液晶にグラフィックを表示できるので、PCから表示すべき画像データを受信できれば、TFTシールドに表示することもできます。ただ、その様なインターフェイス(HDMI等)がDUEには無いので、TFTシールドはただのタッチパネルとして使います。

 TFTシールドの画面表示は使わないので、黒とか白い画面に初期化して使えば良いのだけど、雰囲気が出るように下図のような十字線と枠線を描画しておこうと思います。

a216_pentab.png

 絶対座標モードでは、上図内側灰色の枠線辺りがPCスクリーンの四辺に相当し、その外側をタッチすると、PCの四辺に張り付くようにポイントされます。

マウスライブラリ

 Arduinoをマウスとして使うことができるようになるライブラリとして、まず、Arduinoが提供しているMouseライブラリがあります。他にも、マウスポインタの位置を絶対座標で指定可能なAbsMouseライブラリがあります。
 今回は、この2つのライブラリをコンパイル時に選択して使用可能なプログラムに仕上げます。

#defineマクロ 使用ライブラリ モード
USE_ABSMOUSE無効 Mouseライブラリ 相対座標モード
USE_ABSMOUSE有効 AbsMouseライブラリ 絶対座標モード

 コンパイル時に選択しておく必要があるので、動作中の切り替えは不可です。後ほどリンクするプログラム(tft_pentab.ino)の先頭付近に「#define USE_ABSMOUSE」の定義があるので、有効/無効を切り替えてコンパイルしてください。

Mouseライブラリ

 クラスライブラリになっていて、以下の様なメソッドがあります。

 とても簡単なインターフェイスですね。

AbsMouseライブラリ

 同じくクラスライブラリになっていて、以下の様なメソッドがあります。

 Mouseライブラリにあった、click()メソッドとisPressed()メソッドは、ありません。まあ、無くても特に問題は無いと思います。

AbsMouseライブラリのインストール

 まず、Mouseライブラリですが、こちらはArduino標準ライブラリなので、Arduino IDEと共にインストールされています。そのまま使えば良いです(「Arduino IDE ⇒ スケッチメニュー ⇒ ライブラリをインクルード ⇒ Mouse」)。

 AbsMouseライブラリはオプションなので、ライブラリマネージャからインストールしてください。「Arduino IDE ⇒ スケッチメニュー ⇒ ライブラリをインクルード ⇒ ライブラリを管理」で、以下図の様なウインドウが開きます。

a216_absmouse.png

 上部右側のフィールドに「absmouse」等と打ち込んで検索すると、AbsMouseライブラリが見つかりますので、「インストール」してください。

ペンタブレット(プログラム)

 TFTシールドを使った、4線抵抗方式タッチパネルの制御方法はこちら(↓)をご覧ください。

  「#10-10 タッチパネル(座標・筆圧)

 4線抵抗方式タッチパネルをセンスした座標値から、マウスカーソルを操作します。

 絶対座標モード(AbsMouseライブラリ)では、TFTシールドの240×320[ドット]画面がPCスクリーンと対応しています。PCスクリーンと言えば、フルHD(1,920×1,080[ドット])とか、WQHD(2,560×1,440[ドット])とか、とてもドット数が多いですよね?
 4線抵抗方式タッチパネルの制御(読み取り)に使うのはanalogRead()関数で、AD変換結果を使っています。DUEのanalogRead()関数は、デフォルトでは10ビット変換値を返すようになっていて、値の範囲は0〜1,023[LSB]にしかなりません。
 1,920ドットとか、2,560ドットとか言うPCスクリーンのサイズに比べて、1,024LSBでは不足なのです。

 Arduino DUEのSAM3X8Eマイコンには12ビットAD変換器が搭載されているので、analogReadResolution()関数をコールして、analogRead()関数で12ビットの変換結果を取得できるようにして使いましょう。

  int anlg10bit=analogRead (ana_XM);  // デフォルトでは10ビット変換結果

  analogReadResolution (12);  // 12ビット解像度に設定

  int anlg12bit=analogRead (ana_XM);  // 上関数実行後は12ビット変換結果


 12ビットAD変換器の変換結果は0〜4,095[LSB]ですので、WQHD(2,560×1,440[ドット])ならば、まあ、ギリギリセーフですね。

キャリブレーション

 4線抵抗方式タッチパネルは、TFTシールドの表面に形成された透明導電膜の抵抗値を読み取ることで、タッチした座標や筆圧を検知しています。
 抵抗値は、タッチパネルと接続する経路でも変動するし、透明導電膜自体の経時変化、周囲の気温・湿度、等々、様々な測定環境によって変動します。よって、4線抵抗方式タッチパネルの場合は、タッチした位置と、読み取った抵抗値の間を校正(キャリブレーション)して使うことが基本となります。

 ちょっとした変動に目を瞑ることができるなら、キャリブレーションなしでもある程度使えます。特に、相対座標モードでは、あまり気にならないはずなので、一度キャリブレーションして校正値を読み取ったら、プログラム(tft_pentab.ino)中に定数として埋め込んで使えば良いと思います。

 いずれにしても、タッチパネルを校正する手段は必要なので、作り込んでおきました。
 1つは、シリアルモニタの【cali】コマンドを実行することでキャリブレーションモードに侵入できます。
 2つ目の方法として、シリアルモニタを接続せずに自立させる場合にもキャリブレーション可能な様に、DUEのリセットボタンを押して最初に起動した時、左ボタンに割り当てたタクトスイッチを押しておくと、キャリブレーションモードに入る様になっています。

 キャリブレーション中の様子は昔動画にしてあったので、こちらをご確認ください。

 なお、DUEのanalogRead()関数で取得するAD変換結果を12ビットに変更したため、キャリブレーション値も10ビットの時の値とは全く違う値になります。

完成したプログラム

 以下に完成したプログラムをリンクしておきます。

  完成プログラム:tft_pentab.ino

 デフォルトでは、シリアルモニタ無効、かつ、相対座標モード(Mouseライブラリ)でコンパイルされます。

  //#define USE_SERIAL
  //#define USE_ABSMOUSE


 プログラム(tft_pentab.ino)先頭付近に上の記述があるので、必要に応じて、#defineマクロを有効化して見てください。

 シリアルモニタを有効(#define USE_SERIAL)にしてコンパイルした場合、DUEのプログラムポートをPCに接続しないと動作しません。プログラムポートをPCに接続すると、シリアルモニタから以下のコマンドを受け付けています。

  シリアルモニタコマンド仕様:

 すべてデバッグ用のコマンドです。プログラム(tft_pentab.ino)はシリアルモニタ無しで自立するようになっています。自立させたい時は、「USE_SERIAL」のマクロを無効化してコンパイルしてください。

USBポート(プログラムとネイティブ)

 Arduino DUEには、2個のUSBポートが付いています。プログラムポートとネイティブポートと呼ぶことにします。
 Arduino IDEでは、DUEのボードを選ぶときに、どちらのポートから書き込むか選択できます(下図)。

a119_idebd.png

 今回のアプリケーションではマウスライブラリを使うのだけど、この時、DUEがマウスのふりをするためにはネイティブポート側がPCに接続されている必要があります。
 ネイティブポート側はHIDマウスとしてPCに接続する必要があるので、上図の様にプログラムポート側を選択して書き込みを実行しましょう。

 プログラムのデバッグ時は、2本のUSBを同時にPCと接続して使用可能です。ネイティブポート側がマウスのふりをしながら、プログラムポート側からシリアルモニタが使えます。デバッグする時、シリアルモニタが使えるのは心強いです。

 ただし、Arduino IDEからの書き込み時は注意が必要となります。
 手元の環境では、2本のUSBポートを同時に接続した状態だと、書き込みに失敗してしまいました。ネイティブポート側を切断してから書き込みを実行すると、エラー無く書き込むことができます。

※ちょっとだけ面倒ですが、実は、USBポートが1本しか無いのにマウスになれるSTM32とかArduino Microとかを使ってデバッグするのは、シリアルモニタも使えなくなってしまうし、もっと面倒だったので、DUEのデバッグ環境は大分ましな方です。

 書き込みが終わったら、またネイティブポート側をPCに接続すると、DUE+TFTシールドがペンタブレットになってデバッグを続けることができます。

ネズミの実験

 では実験です。完成したプログラム(tft_pentab.ino)を書き込んだArduino DUEにTFTシールドを装着してください。
 DUEとPCをUSBで接続します。

 DUEの41ピンと45ピン間、および49ピンと53ピン間に2端子タクトスイッチを接続してください。

※もし、PCに接続した時、マウスとして認識されないようなら、一度DUEのリセットボタンを押してみてください。DUEのネイティブUSBポートだけをPCに接続した時、リセットを掛けないとHIDマウスとして機能しない様な気がします。


 以下、実験中の様子です。

a216_expr.jpg

 デフォルトでは、上図の向きで上下/左右が一致するように調整してあります。マウスボタンも、向かって左側に映っている2端子タクトスイッチの上側が左ボタン、下側が右ボタンになっています。
 プログラム(tft_pentab.ino)先頭付近の以下の定数で、画面の上下(pen_FLIPH)/左右(pen_FLIPV)反転、マウスボタンの左右ボタン反転(pen_FLIPB)が可能ですので、左利きの方などは向きを変えてお使いください。

  const bool pen_FLIPH=false;  // 上下を反転する
  const bool pen_FLIPV=true;  // 左右を反転する
  const bool pen_FLIPB=true;  // マウスボタンの左右を反転する


※H=Horizontal、V=Verticalなので、上下と左右が逆なんじゃないか?と思われるかもしれませんが、TFTシールドは、短辺がHorizontal、長辺がVerticalなので、横長のPCスクリーンに対応させる時に、上下と左右が入れ替わっています。よって、上のコメントで合っています。

 PC画面が縦長の場合、90°回転するオプションは作っていないので、必要に応じて各自対応してください。


 以下、動作中の様子を動画にしてみました。相対座標モード(Mouseライブラリ)での操作感をご覧いただけます。



※別途キャリブレーションは実施済みです。キャリブレーション実行中の様子はこちら

 マウス代わりの入力デバイスとしては十分機能します。ただ、4線抵抗方式タッチパネルの特長である「筆圧検知」は、PC側のドライバやDUE側のライブラリにも手を入れないと対応できないので、筆者の手には余ります(断念)……。

実験にて気付いたこと

 AbsMouseライブラリを使ったDUEをPCに接続すると、PCに接続した他のマウスではマウスカーソルを動かすことができなくなってしまうみたいです。
 筆者の使い方が悪いのかな?そうでないとすると、多分、そういう仕様なんだと思う。
 マウスなのに絶対座標で指定できるなんて、相当無理して実現しているのだろうから、多分仕様なんだろうな。
 Mouseライブラリ版だと、他のマウスなどと共存できるので、実用的にはMouseライブラリ版の方が使い勝手が良いと思われます。


 その昔、机が狭くて、マウスを動かすスペースが確保できなかった時に使用していた、小さなペンタブレットがあったのだけど、その時の使用感を思い出しました。


btn_arduino.png

btn_prev.png btn_next.png

home