PSPっぽいジョイスティックモジュールをTrackPointのようなUSBマウスにする

秋月でも買えるPSPのJoyStickのようなアナログジョイスティックモジュールを使って、TrackPoint のようなマウスを作ってみました。

TrackPointとは

TrackPoint とは、主に Lenovo ThinkPad に搭載されている赤ポチのポインティングデバイスです。 TrackPoint に力をかけると、TrackPoint 自体は動きませんが、力の向きと力加減によってマウスポインタを操作できます。

私自身、学生の頃は ThinkPad を使っていて、TrackPointに非常に馴染みがあります。 キーボードのホームポジションを崩さずに利用できるポインティングデバイスとして、非常に人気があります。

ただ、私の場合は、打鍵が強いのもあって、TrackPoint で突き指をしてしまうことがあり、TrackPoint から離れて MagicTrackPad ユーザになっていました。

TrackPoint はモジュール単体では安価な販売先を見つけることができず、自作キーボードに埋め込む場合には主に ThinkPad から取り外して埋め込まれることが多いようです。

単体モジュールとしては、以下のような商品は見つけましたが、若干高めです。

https://www.aliexpress.com/item/1005004122366828.htmlwww.aliexpress.com

動機はAZ1UBALL

パレットシステムさんのAZ1UBALL を購入して試したところ、1U(キーボードの1キー、19mm四方サイズ)のポインティングデバイスが楽しいと感じました。 特に AZ1UBALL が PIM447というトラックボールマウスと同じインターフェイスを持っていて、QMK Firmware で組み込み可能なことが素晴らしいです。

palette-system.booth.pm

これでモジュールを作ったことについては、記事にしています。

74th.hateblo.jp

こんな感じで、キーボードの1UサイズでI2Cで組み込めるポインティングデバイスモジュールを、ジョイスティックで作って、さらにPIM447互換にしたいと思いました。

アナログジョイスティック

アナログジョイスティックは秋月でも複数の種類が販売されています。

今回は、PS2 などのゲームパッドに内蔵されているようなジョイスティックと、PSP に内蔵されているようなジョイスティックの2つを試しました。

最終的に使ったPSP用っぽいジョイスティックモジュールは秋月で150円で売られているとても安価なものです。

akizukidenshi.com

モジュール自体は、移動量をカウントできるロータリーエンコーダーとは異なり、スライドボリュームのような可変抵抗です。 スティックのX、Yそれぞれの可変抵抗となっています(以下は秋月のデータシートより引用)。

これをすぐに試すことができるDIP化キットも販売されています。

今回はこちらを使って、このジョイスティックをマウスを作れないかと考えました。

USBマウスのソフトウェアの実装

USBマウス自体は、Raspberry Pi Pico(ただし自作基板)で、CircuitPythonを使って試しました。 CircuitPython には、Adafruit 本家から USB HID ライブラリが提供されていて、対応したマイコンでは簡単にマウスを作ることができます。

github.com

実際に使ったコードも以下のようなものです。

import time
import board
from analogio import AnalogIn
import usb_hid
from adafruit_hid.mouse import Mouse
from analogio import AnalogIn

mouse = Mouse(usb_hid.devices)

# ADC
x_stick = AnalogIn(board.A0)
y_stick = AnalogIn(board.A1)

while True:
    real_x = x_stick.value
    real_y = y_stick.value

    # アナログ値をマウスに与えると良い値にいい感じに変換する関数
    x = calc(real_x)
    y = calc(real_y)

    # マウスの命令
    mouse.move(x=x, y=y)

    time.sleep(0.02)

たったこれだけでジョイスティックをUSBマウスとして使うことができます。

ここで使っているいい感じの値にする関数 calc() は、ADC から取れる 0~212 の値を、-100~+100 の値に変換する関数です。 この中には、ジョイスティックが中央付近の時には 0 にするような調整が入っています。

PS2 型のジョイスティックを試す

まず、PS2などのゲームパッドタイプのジョイスティックを試しました。

実際に使った商品は以下のものです。

https://aliexpress.com/item/1005002116584640.html

使用感は、結構残念な感じでした。

ツイートの通り、かなり硬いモジュールで傾けるのに力がいります。 加えて、中央のデッドゾーンが広く、繊細に操作するのが難しいものになりました。

ブレッドボード上でテストした感じで、これで実現は難しいなという結論になりました。

PSP 型のジョイスティックを試す

次に PSP 型のジョイスティックを試します。

akizukidenshi.com

しかし、このモジュールには、パッドの部分が付属していません。 Amazonで買える PSP 用のパッドを購入してみましたが、サイズが異なるようではまりませんでした。

Amazon.co.jp: SONY PSP 1000 対応 パーツ アナログスティック ボタン 黒 ブラック オリジナルウエス付き : ゲーム

3D プリントでパッドを作成することも考えましたが、もとの動機が TrackPoint のような操作性を得られないか、だったので、TrackPoint のキャップのアダプターを作ればいいのではないかと考えました。

そこで以下のようなアダプターを作りました。

自宅にある光造形プリンタ(ELEGOO MARS PRO)はわりと細かく造形してくれます。 強度には不安が残りますが、割と期待通り作ることができます。

これでゴムでできているTrackPointキャップをはめて使うことができます。

これでポインティングデバイスを作りました。

PIM447 と互換にする

AZ1UBALLではATTiny404を使われて、I2Cスレーブインターフェイスを実現するマイコンとして使われていました。 私の手元にはATTiny202があったため、こちらを使って実現しました。

akizukidenshi.com

安価なマイコンとして CH552 を使おうかと思いましたが、I2Cインターフェイスを持っていませんでした(ch55xduinoにはソフトウェアI2Cがありますが、マスタのみでした)。

ATTiny202 はとてもメモリの少ないマイコンで、UARTに ptintf してADCの値を観察しようとしましたが、printf すら使えませんでした。 しかし、I2Cスレーブ自体はハードウェアで機能するため、問題になりませんでした。

I2C インターフェイスを経由して Raspberry Pi Pico(オリジナル基板)で USB HID マウスとして実装しました。

使用感

ユニバーサルボードに移植し、2キーを追加して、左クリック、右クリック、右クリックを押しながら操作でスクロールを実現しました。 いくつか ADC の値をいい感じになるようにチューニングをして、わりと問題なく使えるようになりました。

TrackPoint と同様の使い勝手買っというとそんなことはなく、前のPS2ジョイスティックに比べて小さな力で操作できますが、TrackPointよりも力が必要になり、さらに力加減だけでなく移動量で制御する必要があるため、なかなか訓練が必要なデバイスになりました。

ただ、キーボードの横につける小型デバイスとして作成したため、若干土台の安定さに欠くところがあり、力の加え方に気を使う必要があり、使いやすいとは言えませんでした。 組み込むならば、やはりキーボードの上に組み込み、人差し指で操作できるべきであると感じました。

課題

ロータリーエンコーダと異なり、ボリューム抵抗であるためADCでの読み取りになり、その精度は電源や周りの回路に左右されることが予測されます。 私の手元でチューニングして使えるようになりましたが、同じファームウェアがその他の環境でも実現できるのかは検証が必要なように思います。

まとめ

TrackPoint のようなデバイスPSP に似たジョイスティックを使って実現することができました。 そして、TrackPointと同様な使い心地までは行かなくとも、ポインティングデバイスとして使うことができるのを確認できました。

次には、1Uモジュール化してみたいと思います。 さらに、キーボード内部にこれを組み、人差し指で操作してみたいと思います。

このようなI2C制御のポインティングデバイスがもっと広まるといいですね。