ラズパイでGPIO制御をする
今までソフトウェア中心の勉強でしたが、ハードウェアのスキルの幅を
広げるためにもラズベリーパイを使って電子回路を制御し、
いろんなものを作っていきたいと思っています。
そのためにラズパイでハードウェアを制御する方法を勉強していきます。
初回はGPIO制御です。LEDの点灯、消灯を実際にやってみたいと思います。
ラズパイのピンレイアウト
私が持っているラズパイはRaspberry Pi 3B+ですが、
ピンレイアウトはこのようになっています。
いくつかのピンはGPIOだけでなく、I2C, SPI, UARTとしても使用できます。
コマンドでも$gpio readallで確認できます。
GPIOポートの使い方
ラズパイのポートをGPIOとして使用する方法はいくつかあるようですが、
ディープラーニングでPythonを使い慣れていることもあり、RPi.GPIOという
ライブラリを使ってみます。
まず、ライブラリのインストールです。
$ sudo apt-get install python-rpi.gpio
Pythonスクリプト上でRPi.GPIOを使用するためにライブラリをインポートします。
import RPi.GPIO as GPIO
RPi.GPIOではポートの指定方法に2種類あります。
1つはピン番号1-40(上図のNo.の列の番号)で指定する方法 GPIO.BOARD
もう一つはGPIOの番号(上図のGPIO列の番号)で指定する方法 GPIO.BCM
どちらの表記で記載するかを以下のようにGPIO.setmode()で指定します。
GPIO.setmode(GPIO.BOARD) # ボードのピン番号で指定 GPIO.setmode(GPIO.BCM) # GPIO番号で指定
GPIOポートの入出力設定はGPIO.setup()で行います。
例えば、GPIO2を出力、GPIO3を入力ポートで使用する場合は以下のようになります。
GPIO.setmode(GPIO.BCM) # GPIO番号で指定 GPIO.setup(2, GPIO.OUT) # GPIO2:出力ポート GPIO.setup(3, GPIO.IN) # GPIO3:入力ポート
出力設定したポートのH/L出力を指定するにはGPIO.output()を使います。
GPIO2のポートをH/L制御する場合は以下のようになります。
GPIO.output(2, GPIO.HIGH) # 出力H GPIO.output(2, GPIO.LOW) # 出力L
入力設定したポートの値を読み出すにはGPIO.input()を使います。
この関数の戻り値がポートの値となっています。
print GPIO.input(3) # GPIO3の値を読み出し # 結果:1 or 0
GPIO入力をトリガに割り込み処理を実行
プッシュスイッチなどポートの値の変化をトリガにして処理を行いたいケースが
あったので割り込み処理の作り方を調べてみました。
callback関数を定義し、ポートの値が変化したらcallback関数を呼び出す
add_event_detect()というメソッドを使用します。
def callback(gpio_pin): #関数内処理 GPIO.add_event_detect("ピン名", "トリガエッジ", callback=callback, bouncetime=300)
ピン名:ピン番号かGPIO名を指定 入力ポートに設定しておく必要あり
トリガエッジ:立ち上がりエッジ GPIO.RISING, 立下りエッジ GPIO.FALLING
両方 GPIO.BOTH
callback:コールバック関数の指定
bouncetime:チャタリング防止のため、指定時間の間次のイベントを呼び出さない
単位msec
サンプル
最後に上記内容を使って作成したコードを上げておきます。
「スイッチを押すとLEDが点灯し、ラズパイに接続したUSBカメラで写真を撮る」
というものです。
回路図は以下の通り
38pinがトリガでL->Hとなったときに36pinがHとなり、LEDが点灯
同時にUSBカメラのシャッターを切る制御が動作するという仕組みです。
38pinはスイッチにつなぎたかったのですが、スイッチがなかったため、
40pinの出力結果を入力するようにしました。
# coding: utf-8 import RPi.GPIO as GPIO import time import subprocess SHUTTER_PIN = 21 # 40pin SHUTTER_TRIGGER = 20 # 38pin LED_PIN = 26 # 36pin def main(): # cameraの設定 cmd = 'fswebcam capture.jpg' GPIO.setmode(GPIO.BCM) GPIO.setup(SHUTTER_PIN,GPIO.OUT) GPIO.setup(SHUTTER_TRIGGER ,GPIO.IN) GPIO.setup(LED_PIN ,GPIO.OUT) # callback登録(GIO.RISING:立ち上がりエッジ検出、bouncetime:300ms) GPIO.add_event_detect(SHUTTER_PIN, GPIO.RISING, callback=callback, bouncetime=300) try: while(True): time.sleep(0.1) # Ctrl + Cで抜ける except KeyboardInterrupt: print("break") GPIO.output(TRIGGER_PIN, GPIO.LOW) # LEDを消して終了 GPIO.cleanup() def callback(gpio_pin): print(gpio_pin) GPIO.output(LED_PIN , GPIO.HIGH) ret = subprocess.check_output(cmd, shell=True) # カメラ撮影 if __name__ == "__main__": main()
カメラの撮影はfswebcamというパッケージを使用しています。
もしインストールされていない場合は
$ sudo apt-get install fswebcam
でインストールできます。
40pinのトリガーはこちらのスクリプトで発生させています。
import RPi.GPIO as GPIO SHUTTER_PIN= 21 # 40pin def main(): GPIO.setmode(GPIO.BCM) GPIO.setup(SHUTTER_PIN,GPIO.OUT) GPIO.output(SHUTTER_PIN, GPIO.HIGH) if __name__ == "__main__": main()
このスクリプトで写真撮影はできていましたが、fswebcamを使うと
トリガー発生時から約1sec後にシャッターを切るようです。
リモートからのシャッター制御には使えないですね。
トリガーが発生したら即撮影するいい方法があったら教えてください。