Raspberry Pi（Raspbian）で写真を撮るプログラムを作る

#はじめに
Raspberry Pi（Raspbian）で写真を撮るプログラムの紹介です。

カメラモジュールの準備方法は下記を参照して下さい。
- [Raspberry Pi（Raspbian）で写真を撮る方法 - Qiita](https://qiita.com/Yuta_Chief/items/8497ed52d50b9f20f0ca)

#必要なもの
- RaspbianがインストールされているRaspberry Pi
- Raspberry Pi用のカメラモジュール
- ブレッドボード
- タクトスイッチ
- ジャンパー線（オス/メス）x2

#配線
GPIOとGNDならどこでも可ですが、今後の拡張性などを考えるとGPIOのみのピン（3, 5, 8, 10, 19, 21, 23, 24, 25以外）を使う方が無難だと思います。
この投稿では37（GPIO26）, 39（GND）ピンを使用しています。
![DSC_0173.JPG](https://qiita-image-store.s3.amazonaws.com/0/263360/8a3b6909-171e-ae7a-1639-7c0c48a453be.jpeg)
![SW_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/263360/346b273e-e58e-24d2-e51c-5b194641740d.png)

#プログラム
```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. プログラムを実行する![2019-02-05-133348_1824x948_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/263360/5505b721-73c2-45c6-bf8d-6da2324d5ab6.png)
2. スイッチを押す
3. `CAM_DIR`で指定したディレクトリに写真が保存される![2019-02-05-133441_947x685_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/263360/cc49a4f4-2591-4ba7-a4cd-470425ec958d.png)
4. スイッチを押したら写真を撮るプログラム完成![20190205133530.jpeg](https://qiita-image-store.s3.amazonaws.com/0/263360/6584d976-6fde-b192-831e-efb93fcaf931.jpeg)
5. ファイル名が固定ではないので何回写真を撮ってもデータが上書きされない![2019-02-05-133625_947x685_scrot.png](https://qiita-image-store.s3.amazonaws.com/0/263360/a5d9385e-0f97-c281-3d53-512443aa5248.png)

#写真が何枚も撮れてしまう問題の対処法（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`はスイッチを離した時に処理を行う