post-cover

2024-09-04 技術ブログ

LAN経由でマウスを操作する|Raspberry Pi Zero 2 W を USB マウスに変える(記事第1弾)

はじめに

弊社では映像伝送装置といった HDMI や HD-SDI の映像を遠隔に送る装置などを販売しております。

本製品はインターネットに接続が禁止されている PC のモニタ映像を遠隔に送るなどの用途に使われることもあります。


その際に映像だけでなく、遠隔からマウス操作ができたらいいが何かそういった製品はないかというお声をたまに頂戴致します。

これに関してエクステンダと呼ばれる製品があり、それを使えば 100m から 10km と光ケーブルで通信可能な距離までマウスの操作信号を送る事が出来るようです。

KVM エクステンダ


ただエクステンダの場合、インターネット経由で遠隔地から操作などをする事はできずあくまで光ケーブルを敷設し信号が届く範囲からしか操作出来ません。

弊社にお問い合わせ頂くお客様の場合ほとんどがインターネット経由での操作を希望されておりエクステンダでは解決に至りませんでした。


またインターネット経由で遠隔地からマウスを操作するといった製品はあまりにニッチすぎ需要がないのか?探す限り既製品を見つける事ができませんでした。

そこで Raspberry Pi を使って遠隔からマウスを操作できる機器を自作で開発してみる事としました。

raspberry-pi-usb-hid-1-001

開発してみると結構なコード量となった為、記事を3分割してます。

関連記事

本記事では、第1弾としてRaspberry PiをUSBマウスとしてPCに認識させ、別のPCからRaspberry Piにログインし、キーボード操作の信号をRaspberry Piでマウス信号に変換してPCを操作する方法をご紹介します。

必要なもの

  • Raspberry Pi Zero 2 W
  • microUSB ケーブル
  • USB充電器
  • SD カード
  • SD カードリーダー

Raspberry Pi OSのインストール

内容が長くなったので 別の記事 にわけました。

モジュールとドライバーの有効化

Raspberry Pi Zero 2 WにmicroUSBケーブルを接続して電源を供給します。OSが起動したら、RLoginなどのソフトを使用してSSHでリモートログインします。

リモートログインするにはOSのインストールで設定したホスト名、ユーザー名、パスワードを入力します。

以下のコマンドを実行して、必要なモジュールとドライバーを有効にします。

echo "dtoverlay=dwc2" | sudo tee -a /boot/firmware/config.txt
echo "dwc2" | sudo tee -a /etc/modules
sudo echo "libcomposite" | sudo tee -a /etc/modules

これにより、USB 機能を利用するための設定が行われます。/boot/firmware/config.txtdwc2 のオーバーレイを追加し、/etc/modulesdwc2 および libcomposite を追加することで、再起動後に必要なドライバーが自動的にロードされるようになります。

設定スクリプトの作成

この設定は保存されないため、スタートアップ時に自動的に実行されるように設定が必要です。

まず、/usr/bin/init_usb という名前の新しいスクリプトファイルを作成し、それを実行可能にします。

sudo touch /usr/bin/init_usb
sudo chmod +x /usr/bin/init_usb

このスクリプトを起動時に自動実行させるために、/etc/rc.local ファイルを編集します。以下のコマンドで rc.local ファイルを開きます。

sudo nano /etc/rc.local

ファイルの末尾近くにある exit 0 の行の前に、次の行を追加します。

/usr/bin/init_usb # libcomposite configuration

ファイルを保存するには、Ctrl+X を押し、その後 Y を押して Enter を押します。

ガジェットの作成

まず、次のコマンドで設定ファイルを開きます。

sudo nano /usr/bin/init_usb

以下はデフォルト設定ですが、シリアル番号、製造元、および製品名をニーズに合わせて変更することも可能です。

#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p usb_hid
cd usb_hid
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 "0123456789abcdef" > strings/0x409/serialnumber
echo "Sample manufacturer" > strings/0x409/manufacturer
echo "USB Device" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

# Mouse function
mkdir -p functions/hid.usb0
echo 2 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 3 > functions/hid.usb0/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\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/

# Add another function

# End functions

ls /sys/class/udc > UDC

もしキーボードも追加したい場合は# Add another function# End functionsの間に以下のコードを挿入してください。

# Keyboard function
mkdir -p functions/hid.usb1
echo 1 > functions/hid.usb1/protocol
echo 1 > functions/hid.usb1/subclass
echo 8 > functions/hid.usb1/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb1/report_desc
ln -s functions/hid.usb1 configs/c.1/

すべての設定が完了したら、次のコマンドで Raspberry Pi を再起動します。

sudo reboot

Raspberry Pi が USB HID として認識されているか確認する方法

Raspberry Pi 側での確認

Raspberry Pi が USB HID(Human Interface Device)として正しく認識されているかを確認するには、次のコマンドを使用します。

ls -all /dev/hidg0

このコマンドは、/dev/hidg0 デバイスファイルの詳細を表示します。出力が以下のようになっていれば、Raspberry Pi は USB HID として認識されています。

crw------- 1 root root 236, 0 Aug 29 18:06 /dev/hidg0

PC 側での確認

次に、PC 側で Raspberry Pi が正しく認識されているかを確認します。

  1. Windows PC のスタートメニューを右クリックし、「デバイスマネージャー」を選択します。
  2. デバイスマネージャーのリストから「マウスとそのほかのポインティングデバイス」を展開し、「HID 準拠マウス」が表示されているか確認します。
  3. HID 準拠マウスのプロパティを確認:
    • 「HID 準拠マウス」をダブルクリックして、プロパティウィンドウを開きます。
    • I2C HID デバイスと表示されているものが、Raspberry Pi です。

Python スクリプトでマウスを操作

まず、Raspberry Pi に SSH 接続を確立し、次のコマンドを使用して新しい Python スクリプトを作成します。

nano movement.py

次に、以下の Python スクリプトを Raspberry Pi にコピーして貼り付けます。

import os
import sys
import termios
import tty

# HIDファイルのパス
MOUSE_DEV = "/dev/hidg0"

# 初期設定
movement_amount = 10
min_movement = 1
max_movement = 127

# キーボード入力を非同期で取得するための設定
def get_key():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

# マウスの移動やクリックを送信する関数
def move_mouse(dx, dy, buttons=0):
    report = bytearray([buttons, dx & 0xFF, dy & 0xFF])
    with open(MOUSE_DEV, "wb") as f:
        f.write(report)

try:
    while True:
        key = get_key()

        if key == '\x1b':  # エスケープキー
            key += get_key() + get_key()

        if key == '\x1b[A':  # 上方向キー
            move_mouse(0, -movement_amount)
            print(f"Moved up by {movement_amount} units.")
        elif key == '\x1b[B':  # 下方向キー
            move_mouse(0, movement_amount)
            print(f"Moved down by {movement_amount} units.")
        elif key == '\x1b[C':  # 右方向キー
            move_mouse(movement_amount, 0)
            print(f"Moved right by {movement_amount} units.")
        elif key == '\x1b[D':  # 左方向キー
            move_mouse(-movement_amount, 0)
            print(f"Moved left by {movement_amount} units.")
        elif key == 'z':  # Zキーで移動量を減少
            movement_amount = max(min_movement, movement_amount - 4)
            print(f"Movement amount decreased to {movement_amount}.")
        elif key == 'x':  # Xキーで移動量を増加
            movement_amount = min(max_movement, movement_amount + 4)
            print(f"Movement amount increased to {movement_amount}.")
        elif key == 'a':  # Aキーで左クリック
            move_mouse(0, 0, buttons=1)
            print("Left click performed.")
            move_mouse(0, 0, buttons=0)  # クリック状態解除
        elif key == 's':  # Sキーで右クリック
            move_mouse(0, 0, buttons=2)
            print("Right click performed.")
            move_mouse(0, 0, buttons=0)  # クリック状態解除
        elif key == 'q':  # Qキーで終了
            print("Q key pressed. Exiting...")
            break

except KeyboardInterrupt:
    pass

print("終了しました。")

スクリプトを保存したら、次のコマンドを使って実行します。

sudo python3 movement.py

このスクリプトを実行すると、キーボードのキーを押してマウスカーソルが動くか、左クリックや右クリックが有効かを確認できます。

各キーの役割

矢印キー(↑ ↓ → ←): マウスカーソルを移動します。

  • ↑ (上方向キー): マウスカーソルを上方向に移動します。
  • ↓ (下方向キー): マウスカーソルを下方向に移動します。
  • → (右方向キー): マウスカーソルを右方向に移動します。
  • ← (左方向キー): マウスカーソルを左方向に移動します。
  • Z キー: マウスの移動量を減少させます。初期値から 4 単位ずつ減少しますが、最小値は 1 です。
  • X キー: マウスの移動量を増加させます。初期値から 4 単位ずつ増加しますが、最大値は 127 です。
  • A キー: 左クリックを行います。左クリック後にクリック状態が解除されます。
  • S キー: 右クリックを行います。右クリック後にクリック状態が解除されます。
  • Q キー: スクリプトの実行を終了します。このキーが押されるとプログラムが終了します。