RaspberryPi[1] USBポートでデバイスを固定

Raspberry Pi には4つのUSBポートが付いています。これに複数のUSBが付いたときに、どこに何を刺すかによってポート名を固定したほうがプログラムが書きやすいので調べてみました。

Raspberry Pi & Python 開発ブログ ☆彡を参考にさせていただきました。詳細はこちらの方がいいと思います。

Rasperry Pi 4の場合は以下のように割り付けてあります。ちなみに確認はUSBにさして、順番にポートを変えていくとわかります。その時のコマンドは、

udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB0) | more

を実行すると、

looking at device ‘//devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.
0/0000:01:00.0/usb1/1-1/1-1.1/1-1.1:1.0/ttyUSB0/tty/ttyUSB0′:
KERNEL==”ttyUSB0″
SUBSYSTEM==”tty”
DRIVER==””

と出てくるのでポートを変えていけばわかります。

LANコネクタ側上 ⇒ “/usb1/1-1/1-1.1/1-1.1:1.0/
LANコネクタ側下 ⇒ “/usb1/1-1/1-1.2/1-1.2:1.0/
電源コネクタ側上 ⇒ “/usb1/1-1/1-1.3/1-1.3:1.0/
電源コネクタ側下 ⇒ “/usb1/1-1/1-1.4/1-1.4:1.0/

cd /etc/udev/rules.d

 の下にデフォルトで 99-com.rules というファイルが入っています。これが、ポート名を作るルールになっているようなので、ここに新規にルールを書いていけばよさそうです。しかし、このオリジナルファイルを修正するのではなく、違うファイル名で作ることも可能になっているようなので、新規に作ります。参考のページでは 90-usb.rules としているので同じ名称にしておきます。たぶん、この前についている数値の小さいほうからルール設定されていくのだろうと思います。

今回はGPS,速度パルスと電流値を読み込むので、今回はその名称を使います。

ACTION=="add", DEVPATH=="*/usb1/1-1/1-1.1/1-1.1:1.0/*",SYMLINK+="USB_GPS"
ACTION=="add", DEVPATH=="*/usb1/1-1/1-1.2/1-1.2:1.0/*",SYMLINK+="USB_MEM"
ACTION=="add", DEVPATH=="*/usb1/1-1/1-1.3/1-1.3:1.0/*", SYMLINK+="USB_PLS"sudo reboot
ACTION=="add", DEVPATH=="*/usb1/1-1/1-1.4/1-1.4:1.0/*", SYMLINK+="USB_CUR"

確認は各ポートにUSBを刺して、/dev/ に設定したポート名が出てくれば大丈夫です。

この何がメリットかというと、ポートに名前が付けられるので、アプリーしょんでその名称でオープンするときに、そのポートに刺さっているものはその名称であると固定できるということです。間違ったものを指すと、それは異なるデバイスをオープンすることになります。そのポートに何も刺さっていないのならば、オープンでエラーがでます。どこにさしてもそのデバイスを正しく認識してほしいときは、下記の「デバイスでポートを指定する」を用いると便利です。ただこれもデバイスが固定されている場合ですので、異なるデバイスが接続させる可能性がある場合は、下記の方法は使えません。

デバイスでポートを指定する。

USBデバイスを複数さすときに、USB0になったりUSB1になったりする場合、順番に番号が振られるけど、両方を刺したまま再起動すると、どっちにUSB0が振られるかはどうも時の運のようです。しかし、プログラムでデバイスを指定するためには変わっては欲しくない。こんなことがよくありますが、デバイス名にシンボリックリンクを張ることができるようです。その識別子としてプロダクトIDとかモデルIDとかを使えるようです。USB一つにデバイスを刺して下記コマンドを打つと

udevadm info -q all -n /dev/ttyUSB0

P: /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.1/1-1.1:1.0/ttyUSB0/tty/ttyUSB0
N: ttyUSB0
L: 0
S: serial/by-id/usb-Silicon_Labs_CP2102N_USB_to_UART_Bridge_Controller_1a949dbce7e6ea11a474f17a994a5d01-if00-port0
S: serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0-port0
S: wind
E: DEVPATH=/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.1/1-1.1:1.0/ttyUSB0/tty/ttyUSB0
E: DEVNAME=/dev/ttyUSB0
E: MAJOR=188
E: MINOR=0
E: SUBSYSTEM=tty
E: USEC_INITIALIZED=195369592
E: ID_BUS=usb
E: ID_VENDOR_ID=10c4
E: ID_MODEL_ID=ea60
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_VENDOR_FROM_DATABASE=VIA Technologies, Inc.
E: ID_MODEL_FROM_DATABASE=VL805 USB 3.0 Host Controller
E: ID_PATH=platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0
E: ID_PATH_TAG=platform-fd500000_pcie-pci-0000_01_00_0-usb-0_1_1_1_0
E: ID_VENDOR=Silicon_Labs
E: ID_VENDOR_ENC=Silicon\x20Labs
E: ID_MODEL=CP2102N_USB_to_UART_Bridge_Controller
E: ID_MODEL_ENC=CP2102N\x20USB\x20to\x20UART\x20Bridge\x20Controller
E: ID_REVISION=0100
E: ID_SERIAL=Silicon_Labs_CP2102N_USB_to_UART_Bridge_Controller_1a949dbce7e6ea11a474f17a994a5d01
E: ID_SERIAL_SHORT=1a949dbce7e6ea11a474f17a994a5d01
E: ID_TYPE=generic
E: ID_USB_INTERFACES=:ff0000:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_DRIVER=cp210x
E: ID_MM_CANDIDATE=1
E: DEVLINKS=/dev/serial/by-id/usb-Silicon_Labs_CP2102N_USB_to_UART_Bridge_Controller_1a949dbce7e6ea11a474f17a994a5d01-if00-port0 /dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0-port0 /dev/wind
E: TAGS=:systemd:
E: CURRENT_TAGS=:systemd:

と表示されます。ほとんど場合は、ID_VENDOR で区別できると思うので、これをキーワードとします。もし、同じベンダーで識別したいというなら異なるものをキーワードにすればできると思います。

上記に書いた99-com.rulesの中身を以下ににします。

KERNEL=="ttyUSB*",ATTRS{idVendor}=="067b",SYMLINK+="via_gps",MODE="0666"
KERNEL=="ttyUSB*",ATTRS{idVendor}=="10c4",SYMLINK+="wind",MODE="0666"

これで再起動をかけて /dev/を見ると以下のように見えます。したがってプログラムでは、/dev/via_gps としてopen してあげれば、その実態がttyUSB0だろうがttyUSB1だろうが関係なくなります。ちなみに、上記の、idVendor をID_VENDOR_IDとすると機能しません。

$ ls -al /dev/ | grep USB
crw-rw-rw-   1 root dialout 188,   0  1月 30 09:46 ttyUSB0
crw-rw-rw-   1 root dialout 188,   1  1月 30 09:51 ttyUSB1
lrwxrwxrwx   1 root root           7  1月 30 09:46 via_gps -> ttyUSB0
lrwxrwxrwx   1 root root           7  1月 30 09:51 wind -> ttyUSB1