| (同じ利用者による、間の1版が非表示) | |||
| 58行目: | 58行目: | ||
<br><br> | <br><br> | ||
== RPi. | == GPIOのピン番号の指定 == | ||
まず、プログラムの冒頭で以下に示すようにモジュールをインポートする。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
import RPi.GPIO as GPIO | |||
</syntaxhighlight> | |||
<br> | |||
GPIOにはピン番号の指定方法として2つのモードがある。<br> | |||
多くの開発者はBCMモードを使用することが多い。<br> | |||
* BCMモード | |||
*: GPIO番号 (例: GPIO18) を使用する。 | |||
* BOARDモード | |||
*: 物理的なピン番号を使用する。 | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
GPIO.setmode(GPIO.BCM) # BCMモードを使用 | |||
# または | |||
GPIO.setmode(GPIO.BOARD) # BOARDモードを使用 | |||
</syntaxhighlight> | |||
<br><br> | |||
== 入出力ピンの設定 == | |||
GPIOピンの入力 / 出力を明確に指定する必要がある。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
# 出力ピンの設定例 (LED接続等) | |||
GPIO.setup(18, GPIO.OUT) | |||
# 入力ピンの設定例 (スイッチ接続等) | |||
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
// 使用例 (LEDのON / OFF 制御) | |||
# LEDを点灯 | |||
GPIO.output(18, GPIO.HIGH) | |||
# LEDを消灯 | |||
GPIO.output(18, GPIO.LOW) | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
// 使用例 (入力の読み取り) | |||
# スイッチの状態を読み取る | |||
switch_state = GPIO.input(23) | |||
</syntaxhighlight> | |||
<br><br> | |||
== イベント検出 (割り込み制御) == | |||
イベント検出 (割り込み制御) を使用することにより、特定の物理スイッチが押下された場合等の状態変化を検知して、特定の関数を実行できる。<br> | |||
<syntaxhighlight lang="python"> | |||
def button_pressed(channel): | |||
print(f"ボタンが押されました!ピン:{channel}") | |||
GPIO.add_event_detect(23, GPIO.FALLING, callback=button_pressed, bouncetime=200) | |||
</syntaxhighlight> | |||
<br><br> | |||
== GPIOのクリーンアップ == | |||
以下に示す理由から、プログラム終了時には、必ずGPIOのクリーンアップを行うことが推奨されている。<br> | |||
特に、電子工作やハードウェア制御を行う場合は、安全性の観点からも非常に重要な処理である。<br> | |||
<br> | |||
* 安全性の確保 | |||
*: クリーンアップを行わない場合、GPIOピンが前回の状態を保持したままになる可能性がある。 | |||
*: これは接続されている電子部品に予期せぬ電流が流れ続けることを意味しており、部品の損傷やショートの原因となりかねない。 | |||
*: 特に、LEDやモータ等のアクティブな部品が接続されている場合、この問題は重要である。 | |||
*: <br> | |||
* メモリ・リソースの解放 | |||
*: GPIOの設定はシステムメモリ内に保持される。 | |||
*: クリーンアップを行わない場合、これらの設定が不要になった後もメモリを占有し続けることになる。 | |||
*: 長時間稼働するシステムや複数のプログラムを実行する環境では、このメモリの効率的な利用が重要である。 | |||
*: <br. | |||
* 次回起動時の問題回避 | |||
*: クリーンアップを行わずにプログラムを終了した場合、次回のプログラムを実行した時に「このピンは既に使用されている」というようなエラーが発生する可能性がある。 | |||
*: これは、特に開発時のデバッグを困難にする要因となる。 | |||
*: <br> | |||
* 割り込み処理の適切な終了 | |||
*: イベント検出等の割り込み処理を使用している場合、クリーンアップによってこれらの処理が適切に終了される。 | |||
*: これにより、システムリソースの無駄な消費を防ぎ、次回の実行時に問題が発生することを防ぐことができる。 | |||
*: <br> | |||
* システムの安定性維持 | |||
*: Raspberry Piは組み込みシステムとして使用されることが多く、長期的な安定性が求められる。 | |||
*: 適切なクリーンアップを行うことにより、システム全体の安定性が向上して、予期せぬ動作を防ぐことができる。 | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
GPIO.cleanup() | |||
</syntaxhighlight> | |||
<br><br> | |||
== LEDの点滅 == | |||
<syntaxhighlight lang="python"> | |||
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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== PWMによるLEDの調光制御 == | |||
以下の例では、LEDの明るさを段階的に変化させている。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== デジタル入出力 == | |||
以下の例では、プッシュボタンを使用してデジタル入出力を行っている。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
import RPi.GPIO as GPIO | import RPi.GPIO as GPIO | ||
import time | import time | ||
# | # 共通のセットアップ | ||
GPIO.setmode(GPIO.BCM) | GPIO.setmode(GPIO.BCM) | ||
GPIO.setwarnings(False) | 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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== 割り込みカウンタ == | |||
以下の例では、プッシュボタンを押下して、リアルタイムでイベント検出している。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== 超音波センサ (HC-SR04) での距離測定 == | |||
以下の例では、タイミング制御と距離計算を行い、測距している。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== サーボモータ制御 == | |||
以下の例では、PWMを使用したサーボモータを角度制御している。<br> | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
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() | |||
</syntaxhighlight> | |||
<br><br> | |||
== その他の使用例 == | |||
以下の例では、設定された回数だけ暖房サイクルを繰り返している。<br> | |||
<br> | |||
動作の流れを以下に示す。<br> | |||
* 暖房を45分間運転 | |||
* 20分間の休止期間 | |||
* 次のサイクルに移行 | |||
<br> | |||
<syntaxhighlight lang="python"> | |||
# 必要なモジュールのインポート | |||
import RPi.GPIO as GPIO | |||
import time | |||
# GPIOの基本設定 | |||
GPIO.setmode(GPIO.BCM) # Broadcomのピン番号方式を使用 | |||
GPIO.setwarnings(False) # ピンの使用に関する警告を無効化 | |||
# 制御に使用するGPIOピンの定義(17番: メイン暖房制御, 18番: 予備用) | |||
pins = [17,18] | pins = [17,18] | ||
# すべてのピンを出力モードに設定し、安全のためHIGH(オフ)に初期化 | |||
for pin in pins: | for pin in pins: | ||
GPIO.setup(pin, GPIO.OUT) | |||
GPIO.output(pin, 1) # 1 = オフの状態で初期化(安全のため) | |||
# | # システムの動作パラメータ設定 | ||
runcycles = 2 | runcycles = 2 # 暖房サイクルの実行回数 | ||
ontime = 45 # | ontime = 45 # 暖房のON時間(分) | ||
offtime = 20 # | offtime = 20 # サイクル間の休止時間(分) | ||
# | # 時間の単位を分から秒に変換(sleep関数用) | ||
ontime *= 60 | ontime *= 60 # ON時間を秒に変換 | ||
offtime *= 60 | offtime *= 60 # OFF時間を秒に変換 | ||
# | # メインの制御ループ | ||
cycle = 0 | cycle = 0 # サイクルカウンターの初期化 | ||
try: | 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時間だけ待機 | |||
except KeyboardInterrupt: | # 暖房を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(" | # 完了メッセージ | ||
print("全てての暖房サイクルが完了しました") | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||