Raspberry Pi(Raspbian)で写真を撮るプログラムを作る


はじめに

Raspberry Pi(Raspbian)で写真を撮るプログラムの紹介です。

カメラモジュールの準備方法は下記を参照して下さい。
- Raspberry Pi(Raspbian)で写真を撮る方法 - Qiita

必要なもの

  • RaspbianがインストールされているRaspberry Pi
  • Raspberry Pi用のカメラモジュール
  • ブレッドボード
  • タクトスイッチ
  • ジャンパー線(オス/メス)x2

配線

GPIOとGNDならどこでも可ですが、今後の拡張性などを考えるとGPIOのみのピン(3, 5, 8, 10, 19, 21, 23, 24, 25以外)を使う方が無難だと思います。
この投稿では37(GPIO26), 39(GND)ピンを使用しています。

プログラム

camera.py
#Import Files
import RPi.GPIO as GPIO
import picamera
import time

#GPIO Settings
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#Camera Settings
CAM_DIR  = "/home/pi/python/_photo/"

camera = picamera.PiCamera()

#Main
try:
    while True:
        if GPIO.input(26) == 0:
            filename = time.strftime("%Y%m%d%H%M%S") + ".jpeg"
            save_dir_filename = CAM_DIR + filename
            camera.capture(save_dir_filename)

except KeyboardInterrupt:
    GPIO.cleanup()

解説

  1. スイッチの制御に使用するRPi.GPIOライブラリをインポートする
  2. Raspberry Piのカメラモジュールの制御に使用するpicameraライブラリをインポートする
  3. 時間を取得するために使用するtimeライブラリをインポートする
  4. GPIOのモードをBCMに設定する(物理的なピン番号ではなく、GPIO**を使用する)
  5. GPIO26を入力端子に設定し、状態をプルアップ(Hi)にする(Hi=OFF, Low=ON)
  6. CAM_DIRに保存先のディレクトリを設定する
  7. PiCameraクラスのインスタンスを生成する
  8. スイッチが入力されるのを待つ必要があるのでwhile True:で無限ループさせる
  9. スイッチが押されたら(GPIO26がLowになったら)写真を撮る処理を行う
  10. time.strftimeでスイッチが押された時の日時を取得する
  11. time.strftimeで取得した日時+拡張子(.jpeg)をファイル名にする
  12. CAM_DIRで指定したディレクトリとファイル名を連結させる
  13. camera.captureで写真を撮る
  14. CAM_DIRで指定したディレクトリに写真を保存する
  15. 解説9に遷移 or プログラムが終了するのを待つ
  16. Control+Cが押されたらGPIOを解放してプログラムを終了する

プログラムを実行してみる

  1. プログラムを実行する
  2. スイッチを押す
  3. CAM_DIRで指定したディレクトリに写真が保存される
  4. スイッチを押したら写真を撮るプログラム完成
  5. ファイル名が固定ではないので何回写真を撮ってもデータが上書きされない

写真が何枚も撮れてしまう問題の対処法(1)

camera.py
#Main
try:
    while True:
        time.sleep(0.1)
        if GPIO.input(26) == 0:
            filename = time.strftime("%Y%m%d%H%M%S") + ".jpeg"
            save_dir_filename = CAM_DIR + filename
            cam.capture(save_dir_filename)

except KeyboardInterrupt:
    GPIO.cleanup()

チャタリング対策のため、time.sleep(待ち時間)の処理を追加する。
time.sleep(0.01)で10ms、time.sleep(0.1)で100ms、time.sleep(1)で1s待つ。
待ち時間を長くするとスイッチを押しているのに反応しないように感じるため、100〜200ms程度が無難。

この方法だとスイッチを長押しした場合に何枚も写真が撮れてしまう問題が発生する。
短押しで1枚、長押しで連写とするのであれば問題ないが、長押しでも1枚としたい場合は別の対策が必要になる。

写真が何枚も撮れてしまう問題の対処法(2)

camera.py
#Main
try:
    while True:
        if GPIO.input(26) == 0:
            filename = time.strftime("%Y%m%d%H%M%S") + ".jpeg"
            save_dir_filename = CAM_DIR + filename
            cam.capture(save_dir_filename)
            time.sleep(1)

except KeyboardInterrupt:
    GPIO.cleanup()

time.sleep(待ち時間)の処理を追加し、写真を撮る処理を行ってから一定時間は写真を撮る処理を行わないようにする。

この方法でも写真が何枚も撮れてしまう問題の対処法(1)同様、スイッチを長押しした場合に何枚も写真が撮れてしまう問題が発生する。

写真が何枚も撮れてしまう問題の対処法(3)

camera.py
#Import Files
import RPi.GPIO as GPIO
import picamera
import time

#GPIO Settings
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#Camera Settings
CAM_DIR  = "/home/pi/python/_photo/"

camera = picamera.PiCamera()

#Camera Function
def camera_func(x):
    if GPIO.input(26) == 0:
        filename = time.strftime("%Y%m%d%H%M%S") + ".jpeg"
        save_dir_filename = CAM_DIR + filename
        camera.capture(save_dir_filename)

#Interrupt
GPIO.add_event_detect(26, GPIO.FALLING, callback=camera_func)

#Main
try:
    while True:
        pass

except KeyboardInterrupt:
    GPIO.cleanup()
  1. #Main内にあった写真を撮る処理camera_func(x)に分離
  2. スイッチを押したらcamera_func(x)を実行するようGPIO.add_event_detectを追加
  3. while True:内の処理が無くなったのでpassを追加

上記の対策を行うことでスイッチ押下時のみ写真を撮るようになる。

参考

  • GPIO.FALLINGはスイッチ押下時に処理を行う
  • GPIO.RISINGはスイッチを離した時に処理を行う