Raspberry Pi GPIO エミュレーター

Raspberry Pi の GPIO プログラムは、電子回路までソフトウェアで再現できると思い込まなければ、その大部分を普通のコンピューターでテストできます。2026 年現在の実用的な方法は、オープンソースの GPIO Zero にあるモック・ピン・ファクトリーです。同じアプリケーションで、自動テスト時には仮想ピンを、Raspberry Pi 上では実ピンを使えます。

このメンテナンス版ガイドは、2019 年の記事にあった古いシミュレーターのダウンロードを中心とする案内を置き換えます。出典を失わないよう、元の記事は末尾のアーカイブにそのまま残しています。

エミュレーターで何を証明するか決める

GPIO のモック層は、次のテストに役立ちます。

  • アプリケーションの判断、状態遷移、エラー処理
  • 仮想入力が変化した後、どの仮想出力がオンになるか
  • クリーンアップとテストの反復実行
  • ノート PC、CI ランナー、開発コンテナ上のコード

一方、次の項目は検証できません。

  • 実際のピン番号や配線
  • 電圧、電流、ノイズ、プル抵抗、スイッチのチャタリング
  • 電気的なタイミングやハードウェア固有バックエンドの動作
  • LED、リレー、モータードライバー、センサーが安全かつ正しく接続されているか

デスクトップ上のテストは素早い第 1 ゲートとして使い、実機での短いテストの代わりにはしないでください。

現行のツールチェーンをインストールする

GPIO Zero は通常 Raspberry Pi OS で利用できます。Pi 上ではディストリビューションのパッケージを優先します。

sudo apt update
sudo apt install python3-gpiozero

開発用コンピューターでは、依存関係を仮想環境に分離します。

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install gpiozero pytest

以下の例は GPIO Zero の BCM GPIO 番号を使います。17 は GPIO17 であり、ヘッダーの物理ピン 17 ではありません。配線前に Raspberry Pi 上で pinout を実行してください。

GPIO アクセスを小さな境界にまとめる

できる限り判断ロジックをハードウェアから独立させ、GPIO デバイスを所有するオブジェクトには明示的なクリーンアップ方法を用意します。次を indicator.py として保存します。

from gpiozero import Button, LED


def output_for_button(button_pressed):
    return bool(button_pressed)


class Indicator:
    def __init__(self, led_pin=17, button_pin=23):
        self.led = LED(led_pin)
        self.button = Button(button_pin, pull_up=True)

    def update(self):
        if output_for_button(self.button.is_pressed):
            self.led.on()
        else:
            self.led.off()

    def close(self):
        self.button.close()
        self.led.close()

純粋関数 output_for_button() が単純なのは意図的です。実際のプロジェクトでは、フィルタリング、インターロック、ステートマシン、アラームなども同じようにテスト可能な関数へ移せます。

Raspberry Pi なしでテストする

次を test_indicator.py として保存します。

from gpiozero import Device
from gpiozero.pins.mock import MockFactory

from indicator import Indicator, output_for_button


def test_output_decision():
    assert output_for_button(False) is False
    assert output_for_button(True) is True


def test_button_drives_led():
    factory = MockFactory()
    Device.pin_factory = factory
    indicator = Indicator()

    try:
        indicator.button.pin.drive_high()  # pull-up button released
        indicator.update()
        assert indicator.led.value == 0

        indicator.button.pin.drive_low()  # button pressed to ground
        indicator.update()
        assert indicator.led.value == 1
    finally:
        indicator.close()
        factory.close()

テストを実行します。

pytest -q

MockPin.drive_high()drive_low() は、入力が見る電気レベルを模擬します。プルアップ式ボタンでは、High が解放、Low がグラウンドへ接続された押下状態です。

環境変数でモック・ピンを選ぶ

スクリプト自身がファクトリーを注入しない場合は、Python がデバイスをインポートする前にモック・バックエンドを選び、簡単なスモークテストを行えます。

GPIOZERO_PIN_FACTORY=mock python your_program.py

開発環境や CI で明示的に有効にしてください。本番環境で黙ってモックへフォールバックしてはいけません。プログラムが動いているように見えて実際のハードウェアを何も制御しない状態は、明確なエラーで停止するより危険になり得ます。

PWM と接続された仮想デバイスをテストする

基本の MockPin は PWM に対応しません。テストで PWMLEDServo、その他の PWM デバイスを作る場合は、PWM 対応のモック・ピン・クラスを選びます。

GPIOZERO_PIN_FACTORY=mock 
GPIOZERO_MOCK_PIN_CLASS=mockpwmpin 
pytest -q

GPIO Zero ではモック・ピン同士を接続し、一方の仮想出力でもう一方の仮想入力を駆動することもできます。バックグラウンドの source スレッドを使うコードでは、結果を検証する前に、設定した source_delay より少し長く待ちます。これらはソフトウェア間の相互作用をテストする機能であり、実機の負荷、周波数精度、波形をモデル化するものではありません。

古い RPi.GPIO プログラムをどう扱うか

元の記事では、手書きの testRPiGPIO.py モジュールと 2 種類のサードパーティー製シミュレーターを紹介していました。小さなローカルスタブでも少数の呼び出しを確認できますが、実 API とのずれが生じやすく、実用的な入力、イベント、PWM、クリーンアップの意味を持たないことが一般的です。

現在も保守するコードでは、次のいずれかの境界を選んでください。

  1. デバイス層を GPIO Zero へ移行し、MockFactory を使う。
  2. 古い RPi.GPIO 呼び出しを 1 つのアダプターに隔離し、ユニットテストではそのアダプターを偽装する。
  3. 古いプログラムは変更せず、デスクトップでは純粋な判断ロジックだけをテストし、アダプターは Pi 上で実行する。

関数名が一致するだけでは、ハードウェア互換性の証明になりません。下のアーカイブにある SourceForge と GPIOSimulator の手順は歴史的な資料であり、現在のインストール推奨ではありません。

実機テストのゲートを追加する

何かを接続する前に、ボードの公式ピン配置と部品のデータシートを確認してください。Raspberry Pi の GPIO 入出力は 3.3 V ロジックです。GPIO ピンへ 5 V を入力しないでください。LED には直列抵抗を使い、モーターを GPIO から直接駆動してはいけません。適切なドライバーまたは H ブリッジと、用途に合った電源を使います。

Pi 上では、小さく観察しやすいテストをもう一度実施します。

  • BCM 番号か物理番号かを確認する。
  • 配線を変える前に電源を切る。
  • 1 つの入力または出力から始める。
  • 非アクティブ状態とプル方向を検証する。
  • すべての安全インターロックとクリーンアップ経路を試す。
  • 最後に完全な負荷を接続する。

トラブルシューティング

症状考えられる原因確認事項
BadPinFactory、または既定のピン・ファクトリーがないPi 以外で実行しており、バックエンドも未選択テストでは GPIOZERO_PIN_FACTORY=mock を設定するか、Pi 上で対応する実バックエンドを使う
モック・ピンで PWMLED が失敗する既定のモック・ピンは PWM 非対応GPIOZERO_MOCK_PIN_CLASS=mockpwmpin を設定する
プルアップ式ボタンの読み値が逆に見える押すとピンがグラウンドへ接続される解放時は High、押下時は Low を駆動し、両方をテストする
テストは通るが回路は動かないモックは配線や電気特性を検証しないpinout、共通 GND、抵抗値、電圧、実デバイスのデータシートを確認する
テスト同士が影響するグローバルなデバイスやピン・ファクトリーを閉じていないfinally ブロックまたは pytest fixture でデバイスとファクトリーを閉じる

2019 年の元記事アーカイブ

以下は 2019 年に公開した英語の本文です。行末空白の正規化を除き、そのまま保存しています。ダウンロード先とインストールコマンドは現在では古い可能性があるため、現行作業には上のメンテナンス版ガイドを使ってください。

Method 1

Create a file named testRPiGPIO.py and import this file in your projects

import testRPiGPIO as GPIO

#!/usr/bin/python
BOARD = "board"
BCM = "bcm"
OUT = "out"
IN = "in"
HIGH = 1
LOW = 0

def setwarnings(mode):
print(mode)

def output(pin,value):
print(pin, ":", value)

def setmode(mode):
print(mode)

def setup(pin,value):
print(pin, ":", value)

def cleanup():
print("clean-up")

#End


Method 2

Download [this file](https://sourceforge.net/projects/pi-gpio-emulator/) and extract it in the folder of your project.

from EmulatorGUI import GPIO


If you want to install it using pip,

pip install GPIOSimulator


Import it to your project using

from RPiSim.GPIO import GPIO


Supported methods

- GPIO.setmode()
- GPIO.setwarnings()
- GPIO.setup()
- GPIO.input()
- GPIO.output()

An example

from EmulatorGUI import GPIO
#import RPi.GPIO as GPIO
import time
import traceback

def Main():
try:
GPIO.setmode(GPIO.BCM)

GPIO.setwarnings(False)

GPIO.setup(4, GPIO.OUT)
GPIO.setup(17, GPIO.OUT, initial = GPIO.LOW)
GPIO.setup(18, GPIO.OUT, initial = GPIO.LOW)
GPIO.setup(21, GPIO.OUT, initial = GPIO.LOW)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(15, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(26, GPIO.IN)

while(True):
if (GPIO.input(23) == False):
GPIO.output(4,GPIO.HIGH)
GPIO.output(17,GPIO.HIGH)
time.sleep(1)

if (GPIO.input(15) == True):
GPIO.output(18,GPIO.HIGH)
GPIO.output(21,GPIO.HIGH)
time.sleep(1)

if (GPIO.input(24) == True):
GPIO.output(18,GPIO.LOW)
GPIO.output(21,GPIO.LOW)
time.sleep(1)

if (GPIO.input(26) == True):
GPIO.output(4,GPIO.LOW)
GPIO.output(17,GPIO.LOW)
time.sleep(1)

except Exception as ex:
traceback.print_exc()
finally:
GPIO.cleanup() #this ensures a clean exit

Main()

公式リファレンス

Leave a Reply