インストール - RPi.GPIO
概要
RPi.GPIOモジュールは、Raspberry PiのGPIOピンを制御するための基本的なPythonモジュールである。
このモジュールを使用することにより、LEDの点灯、スイッチの入力検知、センサからのデータ読み取り等、GPIO (汎用入出力) ピンを通じて外部の電子部品と通信できる。
このモジュールのメリットは、簡便な構文でありながら、デジタル入出力、PWM出力、割り込み処理等、多岐にわたる機能を提供していることである。
ビギナーでも扱いやすく、高度な制御も可能なバランスの取れたモジュールとなっている。
同時に、高度な制御も可能で、複雑なプロジェクトにも対応できる柔軟性を備えている。
また、豊富なドキュメントやサンプルコードが提供されており、ビギナーでも学習しやすい環境が整っている。
まず、重要な概念として、ピン番号の指定方法がある。
BCMモードとBOARDモードという2つの方式が存在しており、多くの開発者は理解のしやすさからBCMモードを採用している。
- BCMモード
- GPIO番号を使用
- BOARDモード
- 物理的なピン番号を使用する。
GPIOピンの設定には、入力と出力の2つの基本モードがある。
- 入力モード
- スイッチの状態読み取りやセンサからのデータ取得などが可能である。
- 入力ピンには、プルアップやプルダウン抵抗の設定もできる。
- 出力モード
- LEDの点灯や電子部品の制御等ができる。
実際の制御においては、出力ピンではHIGH (オン) と LOW (オフ) の2つの状態を制御できる。
入力ピンでは、接続された部品の状態 (ON / OFF) を読み取ることができる。
より高度な機能として、イベント検出機能 (割り込み検出) がある。
これは、ピンの状態変化を監視して、変化が発生した時に特定の処理を実行する機能である。
例えば、特定の物理スイッチが押下された時、特定の関数を呼び出すことが可能である。
また、PWM (パルス幅変調) 出力にも対応しており、LEDの明るさを段階的に制御したり、モータの速度を制御したりすることも可能である。
プログラム終了時には、使用したGPIOピンを適切に解放することが重要である。
これにより、次回使用時に問題が発生することを防ぐことができる。
RPi.GPIOモジュールのインストール
まず、Raspberry Pi OSのアップデートを行う。
sudo apt update sudo apt upgrade
次に、pipのインストールを行う。
sudo apt install python3-pip
Python3のRPi.GPIOモジュールをインストールする。
sudo apt install python3-rpi.gpio # または sudo pip3 install RPi.GPIO
確認
Python 3を使用して、モジュールをインポートできることを確認する。
このとき、import RPi.GPIOコマンドは出力を返さなければ成功である。(モジュールが正常にインポートされたことを意味する)
python3
import RPi.GPIO
GPIOのピン番号の指定
まず、プログラムの冒頭で以下に示すようにモジュールをインポートする。
import RPi.GPIO as GPIO
GPIOにはピン番号の指定方法として2つのモードがある。
多くの開発者はBCMモードを使用することが多い。
- BCMモード
- GPIO番号 (例: GPIO18) を使用する。
- BOARDモード
- 物理的なピン番号を使用する。
GPIO.setmode(GPIO.BCM) # BCMモードを使用
# または
GPIO.setmode(GPIO.BOARD) # BOARDモードを使用
入出力ピンの設定
GPIOピンの入力 / 出力を明確に指定する必要がある。
# 出力ピンの設定例 (LED接続等)
GPIO.setup(18, GPIO.OUT)
# 入力ピンの設定例 (スイッチ接続等)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
// 使用例 (LEDのON / OFF 制御)
# LEDを点灯
GPIO.output(18, GPIO.HIGH)
# LEDを消灯
GPIO.output(18, GPIO.LOW)
// 使用例 (入力の読み取り)
# スイッチの状態を読み取る
switch_state = GPIO.input(23)
イベント検出 (割り込み制御)
イベント検出 (割り込み制御) を使用することにより、特定の物理スイッチが押下された場合等の状態変化を検知して、特定の関数を実行できる。
def button_pressed(channel):
print(f"ボタンが押されました!ピン:{channel}")
GPIO.add_event_detect(23, GPIO.FALLING, callback=button_pressed, bouncetime=200)
GPIOのクリーンアップ
以下に示す理由から、プログラム終了時には、必ずGPIOのクリーンアップを行うことが推奨されている。
特に、電子工作やハードウェア制御を行う場合は、安全性の観点からも非常に重要な処理である。
- 安全性の確保
- クリーンアップを行わない場合、GPIOピンが前回の状態を保持したままになる可能性がある。
- これは接続されている電子部品に予期せぬ電流が流れ続けることを意味しており、部品の損傷やショートの原因となりかねない。
- 特に、LEDやモータ等のアクティブな部品が接続されている場合、この問題は重要である。
- メモリ・リソースの解放
- GPIOの設定はシステムメモリ内に保持される。
- クリーンアップを行わない場合、これらの設定が不要になった後もメモリを占有し続けることになる。
- 長時間稼働するシステムや複数のプログラムを実行する環境では、このメモリの効率的な利用が重要である。
- <br.
- 次回起動時の問題回避
- クリーンアップを行わずにプログラムを終了した場合、次回のプログラムを実行した時に「このピンは既に使用されている」というようなエラーが発生する可能性がある。
- これは、特に開発時のデバッグを困難にする要因となる。
- 割り込み処理の適切な終了
- イベント検出等の割り込み処理を使用している場合、クリーンアップによってこれらの処理が適切に終了される。
- これにより、システムリソースの無駄な消費を防ぎ、次回の実行時に問題が発生することを防ぐことができる。
- システムの安定性維持
- Raspberry Piは組み込みシステムとして使用されることが多く、長期的な安定性が求められる。
- 適切なクリーンアップを行うことにより、システム全体の安定性が向上して、予期せぬ動作を防ぐことができる。
GPIO.cleanup()
LEDの点滅
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# GPIO18にLEDを接続
# 1秒間隔で点滅
def basic_led_control():
LED_PIN = 18
GPIO.setup(LED_PIN, GPIO.OUT)
try:
while True:
GPIO.output(LED_PIN, GPIO.HIGH)
time.sleep(1)
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(1)
finally:
GPIO.cleanup()
PWMによるLEDの調光制御
以下の例では、LEDの明るさを段階的に変化させている。
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# GPIO18にLEDを接続
# 徐々に明るく、徐々に暗くなる
def pwm_led_control():
LED_PIN = 18
GPIO.setup(LED_PIN, GPIO.OUT)
pwm = GPIO.PWM(LED_PIN, 100) # 100Hz
pwm.start(0)
try:
while True:
# 明るくする
for duty in range(0, 101, 5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.1)
# 暗くする
for duty in range(100, -1, -5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.1)
finally:
pwm.stop()
GPIO.cleanup()
デジタル入出力
以下の例では、プッシュボタンを使用してデジタル入出力を行っている。
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# GPIO18にLED、GPIO23にボタンを接続
# プッシュボタンを押下している間だけLEDが点灯
def button_led_control():
LED_PIN = 18
BUTTON_PIN = 23
GPIO.setup(LED_PIN, GPIO.OUT)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
try:
while True:
button_state = GPIO.input(BUTTON_PIN)
GPIO.output(LED_PIN, not button_state) # プルアップなので論理を反転
time.sleep(0.1)
finally:
GPIO.cleanup()
割り込みカウンタ
以下の例では、プッシュボタンを押下して、リアルタイムでイベント検出している。
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# GPIO23にボタンを接続
# ボタンが押されたときにカウントアップ
def interrupt_counter():
BUTTON_PIN = 23
counter = 0
def button_callback(channel):
nonlocal counter
counter += 1
print(f"ボタンが押されました!カウント: {counter}")
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=button_callback, bouncetime=200)
try:
while True:
time.sleep(0.1)
finally:
GPIO.cleanup()
超音波センサ (HC-SR04) での距離測定
以下の例では、タイミング制御と距離計算を行い、測距している。
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# TRIG_PIN: GPIO18
# ECHO_PIN: GPIO24
def ultrasonic_distance():
TRIG_PIN = 18
ECHO_PIN = 24
GPIO.setup(TRIG_PIN, GPIO.OUT)
GPIO.setup(ECHO_PIN, GPIO.IN)
def measure_distance():
GPIO.output(TRIG_PIN, GPIO.HIGH)
time.sleep(0.00001)
GPIO.output(TRIG_PIN, GPIO.LOW)
while GPIO.input(ECHO_PIN) == 0:
pulse_start = time.time()
while GPIO.input(ECHO_PIN) == 1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * 17150 # 音速から距離を計算
return round(distance, 2)
try:
while True:
dist = measure_distance()
print(f"距離: {dist}cm")
time.sleep(1)
finally:
GPIO.cleanup()
サーボモータ制御
以下の例では、PWMを使用したサーボモータを角度制御している。
import RPi.GPIO as GPIO
import time
# 共通のセットアップ
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# GPIO18にサーボモータを接続
# 0度から180度まで往復
def servo_control():
SERVO_PIN = 18
GPIO.setup(SERVO_PIN, GPIO.OUT)
pwm = GPIO.PWM(SERVO_PIN, 50) # 50Hz
pwm.start(0)
def set_angle(angle):
duty = angle / 18 + 2 # 角度をデューティ比に変換
pwm.ChangeDutyCycle(duty)
time.sleep(0.3)
try:
while True:
# 0度から180度まで
for angle in range(0, 181, 10):
set_angle(angle)
# 180度から0度まで
for angle in range(180, -1, -10):
set_angle(angle)
finally:
pwm.stop()
GPIO.cleanup()
その他の使用例
以下の例では、設定された回数だけ暖房サイクルを繰り返している。
動作の流れを以下に示す。
- 暖房を45分間運転
- 20分間の休止期間
- 次のサイクルに移行
# 必要なモジュールのインポート
import RPi.GPIO as GPIO
import time
# GPIOの基本設定
GPIO.setmode(GPIO.BCM) # Broadcomのピン番号方式を使用
GPIO.setwarnings(False) # ピンの使用に関する警告を無効化
# 制御に使用するGPIOピンの定義(17番: メイン暖房制御, 18番: 予備用)
pins = [17,18]
# すべてのピンを出力モードに設定し、安全のためHIGH(オフ)に初期化
for pin in pins:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, 1) # 1 = オフの状態で初期化(安全のため)
# システムの動作パラメータ設定
runcycles = 2 # 暖房サイクルの実行回数
ontime = 45 # 暖房のON時間(分)
offtime = 20 # サイクル間の休止時間(分)
# 時間の単位を分から秒に変換(sleep関数用)
ontime *= 60 # ON時間を秒に変換
offtime *= 60 # OFF時間を秒に変換
# メインの制御ループ
cycle = 0 # サイクルカウンターの初期化
try:
# 指定された回数のサイクルを実行
while cycle < runcycles:
cycle += 1 # サイクルカウンターを増加
# 暖房をONにする(GPIO17をLOW/0に設定)
GPIO.output(17, 0)
print("暖房運転開始:%d秒間 (サイクル %d / %d)"
%(ontime, cycle, runcycles))
time.sleep(ontime) # 指定されたON時間だけ待機
# 暖房をOFFにする(GPIO17をHIGH/1に設定)
GPIO.output(17, 1)
# 最終サイクルの場合はループを抜ける
if cycle == runcycles:
break
# 次のサイクルまでの待機時間
print("暖房休止中:%s秒間 (残りサイクル数:%s)"
%(offtime, runcycles - cycle))
time.sleep(offtime)
# キーボード割り込み (Ctrl + C) の処理
except KeyboardInterrupt:
GPIO.output(17, 1) # 安全のため暖房を確実にOFF
print("プログラムが停止され、暖房をオフにしました") # 終了メッセージを表示
# 完了メッセージ
print("全てての暖房サイクルが完了しました")