はじめに (対象読者・この記事でわかること)

この記事は、Raspberry Piなどのシングルボードコンピュータでセンサーやモジュールとシリアル通信を行いたい方、組み込みLinux環境でUSBシリアル変換機を利用する開発者、あるいは一般的なLinuxユーザーでUSBシリアル変換機のデバイス名特定に困っている方を対象としています。

この記事を読むことで、USBシリアル変換機がLinuxシステムに正しく認識されているかを確認し、そのデバイスファイル名(例:/dev/ttyUSB0/dev/ttyACM0 など)を確実に特定できるようになります。特に複数のUSBデバイスが接続されている環境や、デバイス名が起動ごとに変わる問題に対処するための具体的な方法を習得し、安定したシリアル通信環境を構築するための基盤を築くことができます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Linuxの基本的なコマンド操作(ls, cd, grepなど) - テキストエディタでのファイル編集(vi, nanoなど)

USBシリアル変換機とLinuxデバイス名の基本

USBシリアル変換機は、USBポートを通じてRS-232CやTTLレベルのシリアル通信を可能にするデバイスです。PCやシングルボードコンピュータがUSBポートしか持たない場合でも、この変換機を介して、古くからあるシリアル通信デバイス(GPSモジュール、センサー、マイコンなど)とデータのやり取りができるようになります。

Linuxでは、ハードウェアデバイスは通常、/dev ディレクトリ以下に「デバイスファイル」として表現されます。USBシリアル変換機の場合、一般的なデバイスファイル名は以下のパターンに従います。

  • /dev/ttyUSBx: FTDI、CP210x(Silicon Labs)、CH34x(WCH)などのチップを使用するUSB-UART変換機に多く見られます。(xは0, 1, 2...)
  • /dev/ttyACMx: Arduinoなど、CDC-ACM(USB Communication Device Class Abstract Control Model)を実装しているデバイスに多く見られます。(xは0, 1, 2...)

なぜデバイス名を確認する必要があるのでしょうか?プログラムからシリアルポートにアクセスする場合、正確なデバイスファイル名を指定しなければ通信を開始できません。また、複数のUSBシリアル変換機が接続されている場合、どのデバイスが目的のシリアルポートなのかを見分けることが重要になります。さらに、Linuxの起動順序によっては、/dev/ttyUSB0 のようなデバイス名が接続するたびに変わってしまうことがあり、これは自動化されたシステムにとって大きな問題となります。

この記事では、これらの課題を解決し、確実に目的のUSBシリアル変換機を特定し、場合によってはデバイス名を永続化する方法を解説します。

USBシリアル変換機のデバイス名を特定する具体的な手順

ここでは、Linuxに接続されたUSBシリアル変換機のデバイス名を特定するための具体的な手順を複数紹介します。簡単な方法から、より確実で安定した特定方法まで段階的に見ていきましょう。

1. ls /dev/tty* でデバイスの増減を確認する

最もシンプルかつ手軽な方法は、USBシリアル変換機を接続する前後で/dev/tty*のリストを比較することです。

ステップ1: 変換機を接続する前に現在のデバイスリストを確認

まず、USBシリアル変換機をまだ接続していない状態で、/devディレクトリ内のttyデバイスの一覧を確認します。

Bash
ls /dev/tty*

このコマンドの出力は、システムによって様々ですが、通常は/dev/tty/dev/ttyS0などのシリアルポートや、仮想コンソール(/dev/tty1など)が表示されます。

ステップ2: USBシリアル変換機を接続し、再度デバイスリストを確認

次に、対象のUSBシリアル変換機をLinuxマシンに接続します。その後、再度ls /dev/tty*コマンドを実行します。

Bash
ls /dev/tty*

接続前にはなかった新しいデバイスファイル(例:/dev/ttyUSB0/dev/ttyACM0)が表示されていれば、それが目的のUSBシリアル変換機である可能性が高いです。

出力例(接続前後):

# 接続前
/dev/tty   /dev/tty1  /dev/tty2  /dev/ttyS0  /dev/ttyS1 ...

# 接続後
/dev/tty   /dev/tty1  /dev/tty2  /dev/ttyS0  /dev/ttyS1 ... /dev/ttyUSB0
                                                               ^^^^^^^^^^ 新しく追加されたデバイス

この方法は直感的ですが、複数のUSBシリアル変換機が接続されている場合や、すでに多くのデバイスが存在する場合は、どれが目的のデバイスなのか判別しにくいことがあります。

2. dmesg コマンドでカーネルログから接続情報を確認する

dmesgコマンドは、Linuxカーネルのメッセージバッファを表示します。USBデバイスが接続された際、カーネルはデバイスの認識に関するログを出力するため、これを利用してデバイス名を特定できます。

ステップ1: dmesgのログからUSBシリアル変換機を特定

USBシリアル変換機を接続した直後にdmesgコマンドを実行し、新しいログを探します。特に、シリアル変換機のチップ名(FTDI、CP210x、CH340など)や「tty」を含むログをgrepで絞り込むと効率的です。

Bash
dmesg | tail -n 20 # 最新の20行を表示 dmesg | grep ttyUSB # ttyUSBを含むログを検索 dmesg | grep cdc_acm # CDC-ACMデバイスを検索 (例: Arduino) dmesg | grep FTDI # FTDIチップのデバイスを検索 dmesg | grep CP210x # Silicon Labs CP210xチップのデバイスを検索 dmesg | grep CH341 # WCH CH340/341チップのデバイスを検索

出力例(CP210xの場合):

[12345.678901] usb 1-1.2: new full-speed USB device number 5 using xhci_hcd
[12345.890123] usb 1-1.2: New USB device found, idVendor=10c4, idProduct=ea60, bcdDevice= 1.00
[12345.901234] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[12345.912345] usb 1-1.2: Product: CP2102 USB to UART Bridge Controller
[12345.923456] usb 1-1.2: Manufacturer: Silicon Labs
[12345.934567] usb 1-1.2: SerialNumber: 0001
[12346.045678] cp210x 1-1.2:1.0: cp210x converter detected
[12346.056789] usb 1-1.2: cp210x converter now attached to ttyUSB0

このログから、idVendor=10c4, idProduct=ea60 のCP2102デバイスが/dev/ttyUSB0としてアタッチされたことが明確に分かります。

3. lsusbdmesg を組み合わせて詳細を確認する

lsusbコマンドは、現在接続されているUSBデバイスの概要を表示します。これとdmesgを組み合わせることで、より確実に目的のデバイスを特定できます。

ステップ1: lsusb でVID/PIDを確認

まず、lsusbコマンドを実行し、接続されているUSBデバイスの一覧を表示します。lsusb -vとすることで、より詳細な情報を得ることもできますが、通常はlsusbで十分です。

Bash
lsusb

出力例:

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 0424:2514 Microchip Technology, Inc. USB 2.0 Hub
Bus 001 Device 003: ID 0424:2514 Microchip Technology, Inc. USB 2.0 Hub
Bus 001 Device 004: ID 0424:7800 Microchip Technology, Inc.
Bus 001 Device 005: ID 10c4:ea60 Silicon Labs CP210x UART Bridge

ここで、ID 10c4:ea60 が先ほどのdmesgのログに出てきたCP210xのVendor ID (VID) と Product ID (PID) であることが確認できます。多くのUSBシリアル変換機は、製品名と共にそのチップベンダーのVID/PIDが表示されます。

ステップ2: VID/PIDを使ってdmesgのログを再度確認

lsusbで特定したVID/PID(例:10c4:ea60)を元に、再度dmesgのログをgrepで検索することで、そのデバイスがどの/dev/tty*として認識されたかを確定できます。

Bash
dmesg | grep "10c4:ea60"

これにより、該当するデバイスのカーネルログのみを抽出し、確実にデバイス名を特定できます。

4. udevadm を使ったより確実な特定と永続化(udevルール)

udevadmは、Linuxのデバイスマネージャーであるudevを操作するためのコマンドです。udevは、デバイスがシステムに接続されたときにカーネルからのイベントを受け取り、それに基づいてデバイスファイルを生成したり、スクリプトを実行したりします。

この機能を利用して、USBシリアル変換機がどのUSBポートに接続されても、あるいはシステムが再起動しても、常に同じデバイス名(正確にはシンボリックリンク)でアクセスできるように設定できます。

ステップ1: 対象デバイスの詳細情報を取得する

まず、目的のUSBシリアル変換機を接続し、特定されたデバイスファイル(例:/dev/ttyUSB0)に対してudevadm infoコマンドを実行して、デバイスの詳細な属性情報を取得します。

Bash
udevadm info -a /dev/ttyUSB0

このコマンドの出力は非常に長いですが、注目すべきは以下の情報です。

  • idVendor: ベンダーID
  • idProduct: プロダクトID
  • ATTRS{serial}: シリアル番号(デバイスによっては存在しない場合もある)
  • ATTRS{manufacturer}: 製造元
  • ATTRS{product}: 製品名

これらの情報は、udevルールを作成する際にデバイスを一意に識別するために使用します。特に、ATTRS{serial}は、同じ種類のUSBシリアル変換機が複数ある場合に個々を識別するのに非常に有効です。

ステップ2: udevルールを作成する

取得した情報に基づいて、udevルールファイルを作成します。ルールファイルは通常/etc/udev/rules.d/ディレクトリに配置し、ファイル名の数字が若い順に処理されます(例: 99-my-usb-serial.rules)。

たとえば、先ほどのCP2102変換機(VID=10c4, PID=ea60, SerialNumber=0001)を /dev/my_sensor_uart という名前で固定したい場合、以下の内容でファイルを作成します。

Bash
sudo nano /etc/udev/rules.d/99-my-usb-serial.rules

ファイルの内容:

Text
# CP2102 USB to UART Bridge Controller (Serial: 0001) SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0001", SYMLINK+="my_sensor_uart" # 別のFTDI変換機 (Serial: A105W0R9) # SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A105W0R9", SYMLINK+="ftdi_dev"
  • SUBSYSTEM=="tty": ttyデバイスに適用するルールであることを示します。
  • ATTRS{idVendor}=="10c4": ベンダーIDが10c4であること。
  • ATTRS{idProduct}=="ea60": プロダクトIDがea60であること。
  • ATTRS{serial}=="0001": シリアル番号が0001であること。この項目は、同じVID/PIDのデバイスが複数ある場合に特に重要です。もしシリアル番号がない、または考慮したくない場合は、この行を削除できますが、その場合、同じVID/PIDのデバイスはどれも同じシンボリックリンクを作成しようとするので注意が必要です。
  • SYMLINK+="my_sensor_uart": /dev/my_sensor_uartというシンボリックリンクを作成するよう指示します。

ステップ3: udevルールを適用する

ルールファイルを作成・編集したら、udevに新しいルールを読み込ませる必要があります。

Bash
sudo udevadm control --reload-rules sudo udevadm trigger

sudo udevadm triggerコマンドは、現在接続されているデバイスに対してudevイベントを再トリガーし、新しいルールを適用させます。

ステップ4: シンボリックリンクを確認する

設定が正しく行われたかを確認するために、/devディレクトリを見てみましょう。

Bash
ls -l /dev/my_sensor_uart

出力例:

lrwxrwxrwx 1 root root 7 Jul 28 10:30 /dev/my_sensor_uart -> ttyUSB0

このように、/dev/my_sensor_uartが実際のデバイスファイル(例:/dev/ttyUSB0)を指すシンボリックリンクとして作成されていれば成功です。これで、アプリケーションからは常に/dev/my_sensor_uartを指定することで、対象のUSBシリアル変換機にアクセスできるようになります。

ハマった点やエラー解決

複数のUSBシリアル変換機でデバイス名が起動ごとに変わる問題

問題: 同じ種類のUSBシリアル変換機を複数接続している場合(例: 2つのCP2102変換機)、/dev/ttyUSB0/dev/ttyUSB1のどちらがどちらのデバイスに対応するかが、システム起動時や再接続時にランダムに入れ替わってしまうことがあります。これは、特定のデバイスからデータを読み取りたい場合に非常に厄介です。

解決策: udevルールでシリアル番号や物理ポートを基に永続的なデバイス名を付与する

この問題の最も確実な解決策は、前述のudevルールを活用することです。udevadm info -aで取得できる情報の中から、デバイスを一意に識別できる属性(特にATTRS{serial}や、物理的なUSBポートを示すKERNELS属性など)をudevルールに含めることで、常に固定のシンボリックリンク名を割り当てることができます。

ATTRS{serial} を使用した例(再掲):

Text
# センサー用CP2102 (シリアル番号: 0001) SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0001", SYMLINK+="my_sensor_uart" # GPS用CP2102 (シリアル番号: 0002) SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0002", SYMLINK+="my_gps_uart"

このように設定することで、シリアル番号が0001のCP2102は常に/dev/my_sensor_uartとして、シリアル番号が0002のCP2102は常に/dev/my_gps_uartとしてアクセス可能になります。デバイスの接続順や再起動に左右されず、安定したデバイスアクセスが実現できます。

まとめ

本記事では、Linuxに接続されたUSBシリアル変換機のデバイス名を確実に特定するための様々な方法を解説しました。

  • ls /dev/tty*での増減確認: 最も手軽な方法で、接続前後のデバイスリスト比較で新しいデバイスを特定できます。
  • dmesgコマンドによるカーネルログの確認: USB接続時のカーネルメッセージから、チップ情報や割り当てられたデバイス名(/dev/ttyUSBxなど)を詳細に把握できます。
  • lsusbdmesgの組み合わせ: lsusbでデバイスのVID/PIDを特定し、その情報でdmesgのログを絞り込むことで、より確実に目的のデバイスを識別できます。
  • udevルールによるデバイス名の永続化: udevadm info -aで取得したデバイスのユニークな属性(シリアル番号など)を基にルールを作成することで、接続順や再起動に依存しない固定のシンボリックリンク名を割り当て、安定したデバイスアクセスを実現できます。

この記事を通して、USBシリアル変換機のデバイス名特定に関する基礎から応用までを習得し、複数のデバイスが存在する複雑な環境や、起動ごとにデバイス名が変動する問題にも自信を持って対処できるようになります。これにより、組み込みシステム開発やセンサーデータ取得などのプロジェクトにおいて、より堅牢で信頼性の高いシリアル通信環境を構築するための大きな一歩を踏み出せるでしょう。

今後は、udevルールを使ったより高度なデバイス管理や、Pythonなどのプログラミング言語を用いたシリアル通信の実装についても記事にする予定です。

参考資料