Written in Japanese(UTF-8)
2021. 5. 7
INASOFT

/トップ/目次/管理人のひとこと/Raspberry Pi Zero WをPCに繋ぎ、マウスのフリをさせてハードウェア版マウスふるふるを作ってみる

3129316 (+0248)[+0447]

管理人のふたこと

Raspberry Pi Zero WをPCに繋ぎ、マウスのフリをさせてハードウェア版マウスふるふるを作ってみる



公開日:2021/05/07

【目次】

■ラズパイZeroのUSBデバイス化の話を聞いて

Raspberry Pi Zero(および4)シリーズは、PCとUSB接続するとUSB機器(特にHID……例えばマウスなど)として認識させることができるという話を耳にしました(※1)。となると、これまで対応できなかった、「シンクライアント-VDI環境向けのマウスふるふる」が作れるんじゃね?という発想に至るのは時間の問題。

そこから、別にRaspberry Piでなくてもググればメルカリでも手に入りそうとか、現物のマウス+プラレールを使った代替手段があるとか、諸々の思考とか購入までの話は5月6日付の管理人のひとことを見ていただくとして、ここでは技術的に「Raspberry Pi Zero WをPCに繋ぎ、マウスのフリをさせてハードウェア版『マウスふるふる』を作ってみる」ことについて書いてみたいと思います。

というわけで、Raspberry Pi Zero W(すでにGPIOピンは設置済みだが使用予定はない)と、micro SDカード(KIOXIA製, 16GB)を準備しました。

Raspberry Pi Zero Wとmicro SDカード

■基本的なRaspberry Pi OSの導入手順

 最近は、Raspberry Pi OS(昔はRaspbeanと呼ばれていた)をゼロからインストールしていなかったのですが、今はSDカードにOSイメージを書き込むためのプログラムをダウンロードできるんですね。

Raspberry Pi OSのダウンロード

(1) Windowsであれば、赤枠で囲ったリンクからダウンロードします。
 ダウンロードしたプログラムを実行します。これはイメージライター(Raspberry Pi Imager)のプログラムですので、[Install]ボタンを押してインストールします。

Raspberry Pi OSのImagerのインストール

(2) Raspberry Pi Imagerをインストールしたら、スタートメニューから実行します。
 USBデバイスとして動作させたいだけで、デスクトップ環境は不要なので、Lite版を利用します。Lite版をSDカードに書き込みますので、「CHOOSE OS」→「Raspberry Pi OS(other)」→「Raspberry Pi OS Lite(32-bit)」を選びます。

Raspberry Pi OSのmicroSDカード書き込み1
 ↓
Raspberry Pi OSのmicroSDカード書き込み2
 ↓
Raspberry Pi OSのmicroSDカード書き込み3

(3) 「WRITE」を押す前に、Ctrl+Shift+Xを同時押ししてAdvanced options画面を表示します。

Advanced options画面

(4) ここで、hostnameの設定や、SSHの有効化、Wi-Fiの設定などを行います。Raspberry Pi Zeroは5GHz帯のWi-Fiには対応していないことに注意。

Advanced options画面

(5) 「WRITE」を押し、書き込み完了まで待ちます。

最後に「WRITE」を押し、書き込み完了まで待つ
 ↓
書き込み完了。CONTINUEを押すと、microSDカードは自動的に「安全な取り外し」をした状態になります

(6) Raspberry PiにmicroSDカードを挿入し、micro USBに電源を供給してやると、Raspberry Piが起動します。micro USBの差込口は2つありますが、とりあえず今回はPCに接続したいわけではないので、PWRの側が望ましいと思いますが、まぁどちらでもOKです。

(7) ACTの緑色のLEDの点滅が落ち着いたら、PCからSSH接続します。TeraTermで、先ほどの書き込み時に指定したホスト名で繋いでやります。

PCからSSH接続

ちなみに私はここでトラブルが発生し、うまくつなぐことができませんでした。Raspberry Pi Zeroが5GHz帯のWi-Fiに対応できないことを知らず、SSIDの指定を間違っていたためです。

こういうトラブル発生時には、本来であれば、mini HDMI経由でモニタに繋ぎ、開いているmicro USB端子にUSBキーボードを挿し、トラブルシュートをするべきなのですが、私はmini HDMIケーブルも持っていませんでしたし、micro USBに変換するケーブルも持っていませんでしたので、Raspberry Pi Zero単独としては詰んでしまいました。


ただ、予備で準備してあったRaspberry Pi 3 model Bがありましたので、そこにmicro SDカードを差し込み、HDMI経由でモニタに繋ぎ、USB端子にUSBキーボードを挿し、トラブルシュートができました。

ついでも含めて、下記の作業を行いました。



■ラズパイZeroのHID化

 PCに対してHID (Human Interface Device) なUSBデバイスだと認識させるための設定を行います。以下の内容は、TomoSoftさんの内容を参考に構成していますが、一部、rootユーザーからcronで実行したいための改変を入れています。


(8) 次の内容で hid.sh を作成します。接続したPCに対し、マウスデバイスとして認識させるシェルスクリプトです。

pi@raspberrypi5:~ $ vi hid.sh

#!/bin/bash /usr/sbin/modprobe libcomposite cd /sys/kernel/config/usb_gadget/ mkdir -p g1 cd g1 echo 0x1d6b > idVendor # Linux Foundation echo 0x0104 > idProduct # Multifunction Composite Gadget echo 0x0100 > bcdDevice # v1.0.0 echo 0x0200 > bcdUSB # USB2 mkdir -p strings/0x409 echo "S/N DUMMY 000-00" > strings/0x409/serialnumber echo "inasoft.org" > strings/0x409/manufacturer echo "Generic USB Mouse" > strings/0x409/product N="usb0" mkdir -p functions/hid.$N echo 1 > functions/hid.$N/protocol echo 1 > functions/hid.$N/subclass echo 8 > functions/hid.$N/report_length echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x01\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0 > functions/hid.usb0/report_desc C=1 mkdir -p configs/c.$C/strings/0x409 echo "Config $C: ECM network" > configs/c.$C/strings/0x409/configuration echo 250 > configs/c.$C/MaxPower ln -s functions/hid.$N configs/c.$C/ # End functions ls /sys/class/udc > UDC
pi@raspberrypi5:~ $ chmod 744 hid.sh

(9) マウスふるふる的にマウスを動かすために、OS起動時にrootのcronから実行されるシェルスクリプトを作成します。

pi@raspberrypi5:~ $ vi rspi_mousefr.sh

#!/bin/sh # rootで動作していなければ終了 if [ `whoami` != "root" ]; then echo rootユーザーで実行してください。 exit 1 fi # 接続したPCに対し、マウスデバイスとして認識させる if [ ! -e /dev/hidg0 ]; then bash /home/pi/hid.sh fi # mousefrの動作(動作テスト用:6秒に1回マウスを大きく左右に動かす) # 動作させるタイミングで基板上のLEDを点滅させる while true do # マウスカーソルを右へ echo -ne "\0\x0F\0" > /dev/hidg0 echo heartbeat > /sys/class/leds/led0/trigger /usr/bin/sleep 1 # マウスカーソルを左へ echo -ne "\0\xF0\0" > /dev/hidg0 echo actpwr > /sys/class/leds/led0/trigger /usr/bin/sleep 5 # 計画停止ファイル /tmp/stop が見つかればループを抜け終了 if [ -e /tmp/stop ]; then rm /tmp/stop exit 0 fi done
pi@raspberrypi5:~ $ chmod 744 rspi_mousefr.sh

実行しているのがrootユーザーかどうかを確認する部分は、本当はUID=0を判定するのが正当っぽいのですが、そもそも運用が始まってしまうと、このシェルスクリプトを手動で実行することが無くなってしまうので、後回しで。
計画停止のファイルチェックについても、実運用が始まってしまうと使用しない(というか、試運用でも再設定後の反映はsudo rebootでOSごと再起動することになる)ので、実質的には役立たないかも。


(10) さきほど準備したrspi_mousefr.shを、rootのcronでOS起動時に実行するようにします。末尾に下記の内容を追加します。

pi@raspberrypi5:~ $ sudo crontab -e

MAILTO="" @reboot bash /home/pi/rspi_mousefr.sh > /tmp/errlog.txt 2>&1

(11) USB OTGドライバ「dwc2」が動作可能になるように設定します。参考先のサイトでは、シェルを作ってそれを実行することにより登録をするような手順になっていたのですが、

USB OGTドライバ「dwc2」を動作可能にするように設定

要は各ファイルの末尾に特定のテキストが追加されればよいのだと思うので、次の手順でもよいはず。たぶん。

pi@raspberrypi5:~ $ sudo vi /boot/config.txt

 :  : dtoverlay=dwc2
pi@raspberrypi5:~ $ sudo vi /etc/modules
# /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. dwc2

(12) とりあえず動作テストをしてみます。まず、Raspberry Pi Zeroを安全にシャットダウンします。

pi@raspberrypi5:~ $ sudo shutdown -h now

(13) Raspberry Pi ZeroとPCをUSB接続します。Raspberry Pi Zero側のmicro USB端子は、「PWR」ではなく「USB」の方を使用します。PCとRaspberry Pi Zeroが接続されると、Raspberry Pi Zeroが起動します。

PCと接続するときはUSB側のmicro USB端子を使う

(14) 動作テストです。待っていると、PC側でマウスとして認識されます。さらに待つと、PC側のマウスが6秒に一回、大きめに動きます。



■Raspberry Pi OSのReadOnly化

(15) Raspberry Pi Zeroにブチ切り可能な設定をします。SDカードをReadOnly化する設定です。

 Raspberry Pi OSは、なんだかんだでLinuxなので、シャットダウンするにはsudo shutdown - h nowコマンドなりなんなりを打ち込んで、正しく終了させなければなりません。ブチ切りを繰り返していると、何回かは耐えられても、そのうち起動しなくなると言われています。

 でも、今回のように、USBデバイスとして利用したい場合「ケーブルを抜いたら終了」としたいところです。そこらへん、うまくいく方法がないかなとTwitterで呟いたところ、ご紹介いただけたのがSDカードをリードオンリーでマウントする方法が書かれたサイトでした。(※2)

 なるほど、その方法でいいのか。

 参考先のサイトでは、X Window環境を立ち上げるために大変難しいことをしているようですが、こちらは最低限の動作しかさせていないので、やるべきことはかなり少なくて済むはず。(※3)

(※2)(※3) まだ十分な耐久テストを行えたわけではなく、本当にブチ切りに耐えられているのかは、今後継続的に検証していくことになるかなと考えています。というか、Raspberry Piは学習用の簡易なワンボードコンピュータなのですから、そもそも耐久テストとかの概念は合わないですね…。



(16) 今後、一時的にReadOnlyを解除したくなった時のためのコマンドを作成します。

pi@raspberrypi5:~ $ vi mountfs.sh

#!/bin/bash case "${1}" in rw) sudo mount -o remount,rw / echo "Filesystem mounted in READ-WRITE mode" ;; ro) sudo mount -o remount,ro / echo "Filesystem mounted in READ-ONLY mode" ;; *) if [ -n "$(mount | grep mmcblk0p2 | grep -o 'rw')" ] then echo "Filesystem is mounted in READ-WRITE mode" else echo "Filesystem is mounted in READ-ONLY mode" fi echo "Usage ${0} [rw|ro]" ;; esac
pi@raspberrypi5:~ $ chmod 744 mountfs.sh

microSDカード内の情報を簡単に更新したい場合に、一時的に書き込みを許可するためのシェルスクリプトです。sudo apt-get update -y;sudo apt-get upgrade -y;sudo apt-get dist-upgrade -y などでブートローダーを更新する必要が生じた場合、上記の「/」に加え「/boot」もrwでremountします。(sudo mount -o remount,rw /boot)



(17) mountfs.shを手動で簡単に打ち込めるように、エイリアス(省略化コマンドみたいな感じ)を作っておくといい感じです。

pi@raspberrypi5:~ $ vi .bashrc

  :   : alias mountfs='~/mountfs.sh'   :   :
なお、シェルスクリプト内ではエイリアスは使えません。
expand_aliasesオプションが必要だそうですが、まぁ、いらないでしょう。

今後は、次のコマンドを打ち込めば、一時的にReadOnlyが解除されます。

pi@raspberrypi5:~ $ mountfs rw
Filesystem mounted in READ-WRITE mode

Raspberry Piを安全に再起動、または、次のコマンドを打ち込むと、再びReadOnly状態になります。

pi@raspberrypi5:~ $ mountfs ro
Filesystem mounted in READ-ONLY mode


■マウスふるふるスクリプトの改修

(18) 本格的な利用にあたって

 先ほど作成した rspi_mousefr.sh はテスト用なので、マウスカーソルは頻繁に&大きく移動しますが、実用としては、1分弱で1回の頻度で、小さめに動けばよいです。例えば次のような感じにすると、最小の揺れ幅になります。シェルスクリプトの変更後は、再起動するのがラクです。

pi@raspberrypi5:~ $ mountfs rw
Filesystem mounted in READ-WRITE mode
pi@raspberrypi5:~ $ vi rspi_mousefr.sh

#!/bin/sh # rootで動作していなければ終了 if [ `whoami` != "root" ]; then echo rootユーザーで実行してください。 exit 1 fi # 接続したPCに対し、マウスデバイスとして認識させる if [ ! -e /dev/hidg0 ]; then bash /home/pi/hid.sh fi # mousefrの動作(50秒に1回、マウスを左右に小さく動かす) # 動作させるタイミングで基板上のLEDを点滅させる while true do # マウスカーソルを右へ echo -ne "\0\x01\0" > /dev/hidg0 echo heartbeat > /sys/class/leds/led0/trigger /usr/bin/sleep 1 # マウスカーソルを左へ echo -ne "\0\xFF\0" > /dev/hidg0 echo actpwr > /sys/class/leds/led0/trigger /usr/bin/sleep 49 # 計画停止ファイル /tmp/stop が見つかればループを抜け終了 if [ -e /tmp/stop ]; then rm /tmp/stop exit 0 fi done
pi@raspberrypi5:~ $ sudo reboot

これでも、スクリーン セーバーへ/スリープモードへの移行は防げるのですが、すでにスクリーン セーバーが動いている場合に、それを解除できなかったりします。おそらく、最小の揺れ幅だと、ちょっとした振動によるものである可能性もあって、スクリーン セーバーを解除するほどではないと判断されてしまうのかもしれません。

また、マウスふるふる的には対象とはしていませんが、VDI接続のクライアントとか、Skypeとか、Teamsとかに対しても反応をさせたければ、もう少し振れ幅が大きい方が良いのかもしれません。

pi@raspberrypi5:~ $ mountfs rw
Filesystem mounted in READ-WRITE mode
pi@raspberrypi5:~ $ vi rspi_mousefr.sh

#!/bin/sh # rootで動作していなければ終了 if [ `whoami` != "root" ]; then echo rootユーザーで実行してください。 exit 1 fi # 接続したPCに対し、マウスデバイスとして認識させる if [ ! -e /dev/hidg0 ]; then bash /home/pi/hid.sh fi # mousefrの動作(50秒に1回、マウスを左右にちょっと大きめに動かす) # 動作させるタイミングで基板上のLEDを点滅させる while true do # マウスカーソルを右へ echo -ne "\0\x08\0" > /dev/hidg0 echo heartbeat > /sys/class/leds/led0/trigger /usr/bin/sleep 1 # マウスカーソルを左へ echo -ne "\0\xF8\0" > /dev/hidg0 echo actpwr > /sys/class/leds/led0/trigger /usr/bin/sleep 49 # 計画停止ファイル /tmp/stop が見つかればループを抜け終了 if [ -e /tmp/stop ]; then rm /tmp/stop exit 0 fi done
pi@raspberrypi5:~ $ sudo reboot

(※1) 本当はRaspberry Pi Picoに魅力を感じて調べていたのですが、その過程でZeroでもPCと繋げばUSB機器として認識できるっぽいと知ったことと、Zeroなら他のラズパイで培った知識やLinuxの知識を応用して容易に実現できそうだと思い至りました。実際、構想したのは5月3日、本記事執筆は5月6日なので、実質4日間ほどで実現できました。ですが、Picoの方でも同じことはやってみたいと思っています。Picoはお急ぎ便で注文し、5月8日には自宅に到着予定です。


参考
関連(ラズピコの話、ガワの話)



本ページへは、自己責任の範囲内であれば自由にリンクしていただいて構いません。
本ページに掲載されている内容は、自由にお使いいただいて構いませんが、必ずしも筆者が内容を保証するものではありませんので、ご利用に際しては自己の責任においてお使いいただきますよう、お願いいたします。
このページのURLやアンカーは、サーバ運営・サイト運営・ページ運営・その他の都合により無告知で一時的あるいは永遠に消滅したり、変更したりする可能性がありますので、あらかじめご了承下さい。
本ページは、公開から1年半経過後の任意のタイミングで削除される予定です。本ページの内容は複製・公開していただいて構いません。


/トップ/目次/管理人のひとこと/Raspberry Pi Zero WをPCに繋ぎ、マウスのフリをさせてハードウェア版マウスふるふるを作ってみる