読み込み中...

PythonでPyUSBを使ったUSBデバイス通信の基本と活用12選

PyUSB 徹底解説 Python
この記事は約31分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●PythonとPyUSBで驚異的なUSB通信を実現!

皆さん、ハードウェアとソフトウェアの橋渡しに興味はありませんか?

PythonとPyUSBを使えば、USBデバイスとの通信が驚くほど簡単になります。

今回は、この強力な組み合わせについて深く掘り下げていきましょう。

USB通信は、多くの人にとって未知の領域かもしれません。

しかし、実は私たちの日常生活に深く根付いているのです。

キーボード、マウス、プリンター、外付けハードディスク – どれもUSB接続を利用しています。

○USBデバイス通信の基礎知識

USBデバイス通信とは、コンピューターと周辺機器の間でデータをやり取りする方法です。

USB(Universal Serial Bus)は、その名の通り、汎用的なシリアル通信規格です。

高速なデータ転送と、プラグアンドプレイ機能により、多くのデバイスで採用されています。

USBデバイスには、ホストとデバイスという役割があります。

通常、コンピューターがホストとなり、接続された周辺機器がデバイスとなります。

ホストはデバイスを制御し、データの送受信を管理します。

○PythonとPyUSBの威力

PythonとPyUSBの組み合わせは、USBデバイス通信の世界に革命をもたらしました。

Pythonの簡潔で読みやすい文法と、PyUSBの豊富な機能セットにより、複雑なUSB通信を簡単に実装できるようになったのです。

PyUSBは、Pythonから直接USBデバイスにアクセスするためのライブラリです。

低レベルのUSB操作を抽象化し、開発者が簡単にUSBデバイスとやり取りできるようにします。

デバイスの検出、データの読み書き、制御転送など、様々な操作が数行のコードで実現できます。

○サンプルコード1:PyUSBのインストールと初期設定

まずは、PyUSBをインストールしましょう。

pipを使用すると簡単です。

次のコマンドを実行してください。

pip install pyusb

インストールが完了したら、簡単なテストコードを書いてみましょう。

このコードは、接続されているUSBデバイスの一覧を表示します。

import usb.core
import usb.util

# 接続されているすべてのUSBデバイスを検出
devices = usb.core.find(find_all=True)

# 検出されたデバイスの情報を表示
for device in devices:
    print(f"デバイスID: {device.idVendor:04x}:{device.idProduct:04x}")
    print(f"製造元: {usb.util.get_string(device, device.iManufacturer)}")
    print(f"製品名: {usb.util.get_string(device, device.iProduct)}")
    print("-------------------------")

このコードを実行すると、接続されているUSBデバイスの一覧が表示されます。

ベンダーID、プロダクトID、製造元、製品名などの基本情報を確認できます。

実行結果の例

デバイスID: 046d:c52b
製造元: Logitech
製品名: USB Receiver
-------------------------
デバイスID: 8087:0024
製造元: Intel Corp.
製品名: Integrated Rate Matching Hub
-------------------------

このように、PyUSBを使うことで、簡単にUSBデバイスの情報を取得できます。

●環境構築

PyUSBを使いこなすには、適切な環境構築が欠かせません。

ここでは、必要なライブラリやツールを紹介し、各主要OSでの設定手順を解説します。

○必要なライブラリとツール

PyUSBを効果的に使用するには、ライブラリとツールが必要です。

主なものは次の通りです。

  1. Python -> 最新の安定版を推奨します。Python 3.6以上であれば問題ありません。
  2. pip -> Pythonのパッケージ管理ツールです。通常、Pythonと一緒にインストールされます。
  3. PyUSB -> USBデバイスとの通信を可能にする主要ライブラリです。
  4. libusb -> USBデバイスにアクセスするためのCライブラリです。PyUSBのバックエンドとして使用されます。
  5. 開発ツール -> お好みのIDE(統合開発環境)やテキストエディタを用意しましょう。PyCharm、VSCode、Sublime Textなどが人気です。

○Windows/Mac/Linuxでの設定手順

各OSでの環境構築手順を見ていきましょう。

Windows

  1. Pythonをダウンロードしてインストールします(https://www.python.org/downloads/windows/)。
  2. コマンドプロンプトを開き、次のコマンドでPyUSBをインストールします。
   pip install pyusb
  1. libusb-win32をダウンロードしてインストールします(https://sourceforge.net/projects/libusb-win32/)。

Mac

  1. Homebrewをインストールします(https://brew.sh/)。
  2. ターミナルを開き、次のコマンドを実行します。
   brew install python
   pip3 install pyusb
   brew install libusb

Linux (Ubuntu/Debian)

  1. ターミナルを開き、次のコマンドを実行します。
   sudo apt-get update
   sudo apt-get install python3 python3-pip libusb-1.0-0-dev
   pip3 install pyusb

○サンプルコード2:PyUSBの動作確認

環境構築が完了したら、PyUSBが正しく動作するか確認しましょう。

次のコードを実行してみてください。

import usb.core
import usb.util

# すべてのUSBデバイスを列挙
devices = usb.core.find(find_all=True)

if devices is None:
    print("USBデバイスが見つかりません。")
else:
    print("接続されているUSBデバイス:")
    for device in devices:
        print(f"  ベンダーID: {device.idVendor:04x}, プロダクトID: {device.idProduct:04x}")

print("PyUSBの動作確認が完了しました。")

このコードは、接続されているすべてのUSBデバイスのベンダーIDとプロダクトIDを表示します。

正常に動作すれば、次のような出力が得られるはずです。

接続されているUSBデバイス:
  ベンダーID: 046d, プロダクトID: c52b
  ベンダーID: 8087, プロダクトID: 0024
  ベンダーID: 1d6b, プロダクトID: 0002
PyUSBの動作確認が完了しました。

もし問題が発生した場合は、次の点を確認してください。

  1. Pythonが正しくインストールされているか
  2. PyUSBが正しくインストールされているか
  3. libusb(またはlibusb-win32)が正しくインストールされているか
  4. USBデバイスが正しく接続されているか

●USBデバイスとの対話を始めよう

さあ、いよいよPythonとPyUSBを使ってUSBデバイスと対話を始めましょう。

USBデバイスとの通信は、まるで新しい言語を学ぶようなものです。

最初は少し戸惑うかもしれませんが、基本を押さえれば驚くほど簡単です。

○デバイスの検出と情報取得

USBデバイスとの対話の第一歩は、デバイスを見つけることから始まります。

PyUSBは、接続されているUSBデバイスを簡単に検出できる機能を提供しています。

デバイスを検出するには、usb.core.findメソッドを使用します。

特定のデバイスを探す場合は、ベンダーIDとプロダクトIDを指定します。

全てのデバイスを列挙したい場合は、find_all=Trueパラメータを使用します。

デバイスが見つかったら、さまざまな情報を取得できます。

製造元、製品名、シリアル番号などの基本情報から、デバイスの設定やインターフェースの詳細まで、幅広い情報にアクセスできます。

○インターフェースとエンドポイントの理解

USBデバイスを本格的に操作するには、インターフェースとエンドポイントの概念を理解することが重要です。

インターフェースは、デバイスの機能を表します。

例えば、多機能プリンターの場合、印刷機能と
スキャン機能が別々のインターフェースとして実装されているかもしれません。

エンドポイントは、データの送受信を行う通信チャンネルです。

入力エンドポイント、出力エンドポイント、制御エンドポイントの3種類があります。

エンドポイントの種類によって、データの流れる方向や通信の性質が決まります。

○サンプルコード3:USBデバイスの検出と情報表示

では、実際にPyUSBを使ってUSBデバイスを検出し、情報を表示するコードを見てみましょう。

import usb.core
import usb.util

def find_usb_device(vendor_id=None, product_id=None):
    # デバイスを検出
    device = usb.core.find(idVendor=vendor_id, idProduct=product_id)

    if device is None:
        print("USBデバイスが見つかりません。")
        return None

    # デバイス情報の表示
    print(f"デバイス情報:")
    print(f"  ベンダーID: {device.idVendor:04x}")
    print(f"  プロダクトID: {device.idProduct:04x}")
    print(f"  製造元: {usb.util.get_string(device, device.iManufacturer)}")
    print(f"  製品名: {usb.util.get_string(device, device.iProduct)}")

    # インターフェース情報の表示
    for cfg in device:
        print(f"  設定値: {cfg.bConfigurationValue}")
        for intf in cfg:
            print(f"    インターフェース番号: {intf.bInterfaceNumber}")
            for ep in intf:
                print(f"      エンドポイントアドレス: {ep.bEndpointAddress:02x}")

    return device

# 例:ベンダーID 0x046d (Logitech)のデバイスを検索
find_usb_device(vendor_id=0x046d)

このコードを実行すると、指定したベンダーIDのUSBデバイスを検索し、見つかった場合はその詳細情報を表示します。

実行結果は次のようになります。

デバイス情報:
  ベンダーID: 046d
  プロダクトID: c52b
  製造元: Logitech
  製品名: USB Receiver
  設定値: 1
    インターフェース番号: 0
      エンドポイントアドレス: 81
    インターフェース番号: 1
      エンドポイントアドレス: 82

この結果から、Logitechのレシーバーが接続されており、2つのインターフェースと2つのエンドポイントを持っていることがわかります。

●データ転送の基本テクニック

USBデバイスとの通信で最も重要なのは、データの転送です。

PyUSBを使えば、デバクリからデータを読み取ったり、デバイスにデータを書き込んだりすることが簡単にできます。

○サンプルコード4:デバイスからのデータ読み取り

まずは、デバイスからデータを読み取る方法を見てみましょう。

import usb.core
import usb.util

def read_from_device(device, endpoint_address, length):
    try:
        # デバイスを設定
        device.set_configuration()

        # データを読み取り
        data = device.read(endpoint_address, length)

        print(f"読み取ったデータ: {data}")
        return data
    except usb.core.USBError as e:
        print(f"エラーが発生しました: {str(e)}")
        return None

# デバイスを検索(例:ベンダーID 0x046d、プロダクトID 0xc52b)
device = usb.core.find(idVendor=0x046d, idProduct=0xc52b)

if device is None:
    print("デバイスが見つかりません。")
else:
    # エンドポイントアドレス0x81から64バイト読み取り
    read_from_device(device, 0x81, 64)

この例では、指定したエンドポイントから一定量のデータを読み取ります。

実際の出力は接続されているデバイスによって異なりますが、次のような結果が得られるかもしれません。

読み取ったデータ: array('B', [0, 12, 0, 0, 0, 0, 0, 0])

○サンプルコード5:デバイスへのデータ書き込み

次に、デバイスにデータを書き込む方法を見てみましょう。

import usb.core
import usb.util

def write_to_device(device, endpoint_address, data):
    try:
        # デバイスを設定
        device.set_configuration()

        # データを書き込み
        bytes_written = device.write(endpoint_address, data)

        print(f"書き込んだバイト数: {bytes_written}")
        return bytes_written
    except usb.core.USBError as e:
        print(f"エラーが発生しました: {str(e)}")
        return None

# デバイスを検索(例:ベンダーID 0x046d、プロダクトID 0xc52b)
device = usb.core.find(idVendor=0x046d, idProduct=0xc52b)

if device is None:
    print("デバイスが見つかりません。")
else:
    # エンドポイントアドレス0x02に "Hello, USB!" と書き込み
    write_to_device(device, 0x02, "Hello, USB!".encode())

この例では、指定したエンドポイントにデータを書き込みます。

実行結果は次のようになるかもしれません。

書き込んだバイト数: 11

○サンプルコード6:制御転送の実装

最後に、より高度な通信方法である制御転送の実装を見てみましょう。

制御転送は、デバイスの設定変更やステータス取得などに使用されます。

import usb.core
import usb.util

def control_transfer(device, request_type, request, value, index, data_or_length):
    try:
        result = device.ctrl_transfer(request_type, request, value, index, data_or_length)
        print(f"制御転送の結果: {result}")
        return result
    except usb.core.USBError as e:
        print(f"エラーが発生しました: {str(e)}")
        return None

# デバイスを検索(例:ベンダーID 0x046d、プロダクトID 0xc52b)
device = usb.core.find(idVendor=0x046d, idProduct=0xc52b)

if device is None:
    print("デバイスが見つかりません。")
else:
    # デバイスの説明子を取得する制御転送の例
    control_transfer(device, 
                     usb.util.CTRL_TYPE_STANDARD | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_IN,
                     usb.util.REQ_GET_DESCRIPTOR,
                     (usb.util.DESC_TYPE_DEVICE << 8) | 0,
                     0,
                     18)

この例では、USB規格で定義されているデバイス説明子を取得する制御転送を実行しています。

実行結果は次のようになるかもしれません。

制御転送の結果: array('B', [18, 1, 0, 2, 0, 0, 0, 64, 108, 4, 43, 197, 2, 1, 1, 2, 0, 1])

●高度なUSBデバイス制御

PyUSBの基本を押さえたところで、もう一歩踏み込んだUSBデバイス制御の世界へ足を踏み入れましょう。

高度な制御技術を身につければ、USBデバイスの可能性を最大限に引き出すことができます。

○サンプルコード7:カスタムコマンドの送信

多くのUSBデバイスは、独自のコマンドセットを持っています。

製造元が定義したカスタムコマンドを送信することで、デバイスの隠れた機能を引き出せることがあります。

例えば、LEDの色を変更したり、特殊なモードに切り替えたりするといったことが可能です。

次のサンプルコードは、仮想的なUSBデバイスにカスタムコマンドを送信する方法を表しています。

import usb.core
import usb.util

def send_custom_command(device, command, value=0, index=0, data=None):
    # カスタムコマンドを送信
    result = device.ctrl_transfer(
        bmRequestType=0x40,  # ベンダー固有のリクエスト、デバイスへの書き込み
        bRequest=command,
        wValue=value,
        wIndex=index,
        data_or_wLength=data if data else 0
    )
    return result

# デバイスを検索(例:ベンダーID 0x1234、プロダクトID 0x5678)
device = usb.core.find(idVendor=0x1234, idProduct=0x5678)

if device is None:
    print("デバイスが見つかりません。")
else:
    # LEDを赤色に設定するカスタムコマンドを送信(仮想的な例)
    command = 0x12  # LEDコントロールコマンド
    value = 0xFF0000  # 赤色のRGB値
    result = send_custom_command(device, command, value)
    print(f"コマンド送信結果: {result}")

このコードを実行すると、次のような出力が得られるかもしれません。

コマンド送信結果: 0

0が返ってきた場合、コマンドが正常に処理されたことを意味します。

実際の出力は、デバイスの仕様によって異なります。

○サンプルコード8:非同期通信の実装

USBデバイスとの通信を効率化するには、非同期通信が有効です。

非同期通信を使用すると、データの送受信中にプログラムが他の処理を行えるようになります。

特に大量のデータを扱う場合や、リアルタイム性が求められる場合に威力を発揮します。

ここでは、非同期通信を実装したサンプルコードを紹介します。

import usb.core
import usb.util
import threading

def async_read(device, endpoint, length, callback):
    def read_thread():
        try:
            data = device.read(endpoint, length)
            callback(data)
        except usb.core.USBError as e:
            print(f"読み取りエラー: {str(e)}")

    thread = threading.Thread(target=read_thread)
    thread.start()

def data_received(data):
    print(f"受信データ: {data}")

# デバイスを検索(例:ベンダーID 0x1234、プロダクトID 0x5678)
device = usb.core.find(idVendor=0x1234, idProduct=0x5678)

if device is None:
    print("デバイスが見つかりません。")
else:
    # 非同期読み取りを開始
    async_read(device, 0x81, 64, data_received)
    print("非同期読み取りを開始しました。他の処理を続行できます。")

# ここで他の処理を行うことができます

このコードを実行すると、次のような出力が得られるかもしれません。

非同期読み取りを開始しました。他の処理を続行できます。
受信データ: array('B', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

非同期通信により、データ受信を待つ間も他の処理を実行できます。

これにより、プログラムの応答性が向上し、効率的な処理が可能になります。

○サンプルコード9:バルク転送の最適化

大量のデータを高速に転送したい場合、バルク転送が最適です。

しかし、単純にバルク転送を行うだけでは、最高のパフォーマンスは得られません。

転送サイズの調整やバッファリングなどの最適化が必要です。

ここでは、バルク転送を最適化したサンプルコードを紹介します。

import usb.core
import usb.util
import time

def optimized_bulk_transfer(device, endpoint, data, chunk_size=512):
    total_sent = 0
    start_time = time.time()

    while total_sent < len(data):
        chunk = data[total_sent:total_sent + chunk_size]
        bytes_sent = device.write(endpoint, chunk)
        total_sent += bytes_sent

    end_time = time.time()
    transfer_rate = len(data) / (end_time - start_time) / 1024 / 1024  # MB/s

    print(f"転送完了: {len(data)} バイト")
    print(f"転送速度: {transfer_rate:.2f} MB/s")

# デバイスを検索(例:ベンダーID 0x1234、プロダクトID 0x5678)
device = usb.core.find(idVendor=0x1234, idProduct=0x5678)

if device is None:
    print("デバイスが見つかりません。")
else:
    # 1MBのテストデータを生成
    test_data = b'0' * (1024 * 1024)

    # 最適化されたバルク転送を実行
    optimized_bulk_transfer(device, 0x02, test_data)

このコードを実行すると、次のような出力が得られるかもしれません。

転送完了: 1048576 バイト
転送速度: 32.15 MB/s

チャンクサイズを調整することで、さまざまなUSBデバイスやホストシステムに対して最適なパフォーマンスを得ることができます。

●よくあるエラーと対処法

USBデバイスとの通信は、時として予期せぬ問題に直面することがあります。

ここでは、よく遭遇するエラーとその対処法について説明します。

エラーの原因を突き止め、解決する技術を身につけましょう。

○デバイス認識エラーの解決

デバイスが認識されないのは、USBプログラミングにおいて最も頻繁に発生する問題の一つです。

原因としては、ドライバの問題、権限の不足、デバイスの不具合などが考えられます。

問題解決のためのチェックリスト

  1. デバイスが正しく接続されているか確認する
  2. 別のUSBポートを試す
  3. デバイスドライバが正しくインストールされているか確認する
  4. 管理者権限でプログラムを実行してみる
  5. 別のコンピュータで試してみる

次のコードは、デバイス認識エラーを検出し、詳細な情報出力します。

import usb.core
import usb.util

def check_device(vendor_id, product_id):
    try:
        device = usb.core.find(idVendor=vendor_id, idProduct=product_id)
        if device is None:
            print("デバイスが見つかりません。接続を確認してください。")
            return None

        print("デバイスが見つかりました。")
        print(f"ベンダーID: {device.idVendor:04x}")
        print(f"プロダクトID: {device.idProduct:04x}")

        # デバイスの詳細情報を取得
        try:
            device.set_configuration()
            print("設定の設定に成功しました。")
        except usb.core.USBError as e:
            print(f"設定の設定に失敗しました: {str(e)}")

        return device
    except usb.core.USBError as e:
        print(f"USBエラーが発生しました: {str(e)}")
        return None

# デバイスをチェック(例:ベンダーID 0x1234、プロダクトID 0x5678)
check_device(0x1234, 0x5678)

このコードを実行すると、デバイスの認識状況や詳細な情報が表示されます。

問題が発生した場合は、エラーメッセージを参考に対処方法を検討できます。

○タイムアウト問題への対応

USBデバイスとの通信中にタイムアウトが発生することがあります。

特に、大量のデータを転送する場合や、デバイスの応答が遅い場合に起こりやすい問題です。

タイムアウト問題に対処するためのテクニックは次のようになります。

  1. タイムアウト時間を適切に設定する
  2. 再試行メカニズムを実装する
  3. デバイスの状態を定期的にチェックする

次のコードは、タイムアウトを考慮したデータ読み取りの例です。

import usb.core
import usb.util
import time

def read_with_timeout(device, endpoint, length, timeout=1000, max_retries=3):
    for attempt in range(max_retries):
        try:
            return device.read(endpoint, length, timeout=timeout)
        except usb.core.USBTimeoutError:
            print(f"タイムアウトが発生しました。再試行 {attempt + 1}/{max_retries}")
            time.sleep(0.5)  # 少し待ってから再試行

    raise Exception("最大再試行回数を超えました。デバイスが応答しません。")

# デバイスを検索(例:ベンダーID 0x1234、プロダクトID 0x5678)
device = usb.core.find(idVendor=0x1234, idProduct=0x5678)

if device is None:
    print("デバイスが見つかりません。")
else:
    try:
        data = read_with_timeout(device, 0x81, 64)
        print(f"読み取りデータ: {data}")
    except Exception as e:
        print(f"エラー: {str(e)}")

このコードでは、タイムアウトが発生した場合に複数回再試行する機能を実装しています。

これで、一時的な通信の問題を克服し、より安定したデータ転送が可能になります。

○リソース管理とメモリリーク防止

長時間動作するプログラムや、多数のUSBデバイスを扱うプログラムでは、適切なリソース管理が重要です。

リソースを適切に解放しないと、メモリリークやデバイスのロックなどの問題が発生する可能性があります。

リソース管理のベストプラクティスは次のとおりです。

  1. デバイスを使用後に適切にクローズする
  2. コンテキストマネージャを使用してリソースを管理する
  3. 定期的にガベージコレクションを実行する

次のコードは、コンテキストマネージャを使用してUSBデバイスを安全に管理する例です。

import usb.core
import usb.util
from contextlib import contextmanager

@contextmanager
def usb_device_context(vendor_id, product_id):
    device = usb.core.find(idVendor=vendor_id, idProduct=product_id)
    if device is None:
        raise ValueError("デバイスが見つかりません。")

    try:
        # デバイスを設定
        device.set_configuration()
        yield device
    finally:
        # デバイスをクリーンアップ
        usb.util.dispose_resources(device)

# デバイスを安全に使用する例
try:
    with usb_device_context(0x1234, 0x5678) as device:
        # デバイスを使用したコードをここに書く
        data = device.read(0x81, 64)
        print(f"読み取りデータ: {data}")
except ValueError as e:
    print(f"エラー: {str(e)}")
except usb.core.USBError as e:
    print(f"USBエラー: {str(e)}")

print("デバイスのリソースが適切に解放されました。")

このアプローチを使用することで、プログラムの終了時やエラー発生時に確実にデバイスのリソースを解放できます。

これで、メモリリークを防ぎ、長時間安定して動作するプログラムを作成できます。

●PyUSBの応用例

PyUSBの基本を理解したところで、実践的な応用例に挑戦してみましょう。

PyUSBを使えば、様々なUSBデバイスを自在に操ることができます。

ここでは、身近なUSBデバイスを使った面白い応用例を紹介します。

○サンプルコード10:USBマウスの動き追跡

USBマウスの動きを追跡するプログラムを作成してみましょう。

マウスの動きをリアルタイムで捉え、画面上に表示することができます。

import usb.core
import usb.util
import sys

# マウスのベンダーIDとプロダクトIDを指定(例:Logitechのマウス)
VENDOR_ID = 0x046d
PRODUCT_ID = 0xc52b

# マウスを検索
mouse = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID)

if mouse is None:
    print("マウスが見つかりません。")
    sys.exit(1)

# マウスの設定
mouse.set_configuration()

# エンドポイントを取得
endpoint = mouse[0][(0,0)][0]

# マウスの動きを追跡
try:
    while True:
        try:
            data = mouse.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize)
            print(f"X: {data[1]:4} Y: {data[2]:4}")
        except usb.core.USBError as e:
            if e.args == ('Operation timed out',):
                continue
except KeyboardInterrupt:
    print("プログラムを終了します。")

このコードを実行すると、マウスの X 軸と Y 軸の動きがリアルタイムで表示されます。

出力例は次のようになります。

X:    1 Y:    0
X:    2 Y:   -1
X:   -1 Y:    1
X:    0 Y:    3

マウスを動かすと、X と Y の値が変化するのがわかります。

このデータを使えば、マウスの動きを追跡したり、独自のジェスチャー認識システムを作ったりできます。

○サンプルコード11:USBカメラからのリアルタイム画像処理

次は、USBカメラからリアルタイムで画像を取得し、簡単な画像処理を行う例を見てみましょう。

この例では、OpenCVライブラリを使用して画像を取得し、エッジ検出を行います。

import cv2
import numpy as np

# カメラを初期化(通常、0は内蔵カメラ、1は外付けUSBカメラ)
cap = cv2.VideoCapture(1)

while True:
    # フレームを取得
    ret, frame = cap.read()
    if not ret:
        print("フレームの取得に失敗しました。")
        break

    # グレースケールに変換
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # エッジ検出
    edges = cv2.Canny(gray, 100, 200)

    # 結果を表示
    cv2.imshow('Original', frame)
    cv2.imshow('Edges', edges)

    # 'q'キーで終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# リソースを解放
cap.release()
cv2.destroyAllWindows()

このコードを実行すると、USBカメラからのリアルタイム映像と、そのエッジ検出結果が表示されます。

‘q’キーを押すとプログラムが終了します。

実行結果は視覚的なものなので、テキストで表現するのは難しいですが、2つのウィンドウが開き、一方には通常のカメラ映像、もう一方にはエッジが強調された白黒の映像が表示されます。

○サンプルコード12:IoTデバイスとの連携

最後に、PyUSBを使ってIoTデバイスと連携する例を見てみましょう。

ここでは、Arduino互換のマイコンボードとシリアル通信を行い、センサーデータを読み取る例を紹介します。

まず、Arduino側のコードです。

void setup() {
  Serial.begin(9600);
}

void loop() {
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(1000);
}

このコードは、アナログピンA0に接続されたセンサーの値を1秒ごとに読み取り、シリアル通信で送信します。

次に、Python側のコードです。

import serial
import time

# シリアルポートの設定(Windowsの場合は'COM3'などに変更してください)
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)

try:
    while True:
        if ser.in_waiting > 0:
            line = ser.readline().decode('utf-8').rstrip()
            print(f"センサー値: {line}")
        time.sleep(0.1)
except KeyboardInterrupt:
    print("プログラムを終了します。")
    ser.close()

このPythonコードは、シリアルポートからデータを読み取り、表示します。

実行結果は次のようになります。

センサー値: 512
センサー値: 510
センサー値: 515
センサー値: 508

このように、PyUSBを使うことで、様々なUSBデバイスと連携し、データの取得や制御を行うことができます。

マウスの動き追跡、カメラからの画像処理、IoTデバイスとの連携など、応用範囲は無限大です。

まとめ

PyUSBを使ったUSBデバイス通信の基本から応用まで、幅広くカバーしてきました。

PyUSBの利用により、PythonプログラマーがUSBデバイスを自在に操る道が開かれます。

本記事で学んだ技術を基に、独自のUSBデバイス制御プロジェクトに挑戦してみてはいかがでしょうか。

新しいアイデアや革新的なアプリケーションが生まれるかもしれませんね。