Raspberry Piとタクトスイッチでデジカメを製作

今回はRaspberry Piを使ってデジカメもどきを作ってみます。もどきと呼んだのは、デジカメサイズにパッケージングしていないからです。ディスプレイはPCモニタを使用します。シャッターボタンはタクトスイッチを使用し、押した瞬間のカメラ画像が保存される仕組みです。

▼完成し、プログラムを実行したときの動作がこちらになります。

タクトスイッチを押すとカメラ画像がフォルダに保存されます。このデジカメもどきの製作方法を解説していきます。

目次

準備したもの

  • Raspberry Pi
  • Raspberry Pi用カメラモジュール
  • PCモニタ
  • ブレッドボード
  • ジャンパワイヤ オス-メス
  • タクトスイッチ

回路図

Raspberry Piの3.3V端子、GPIO 17とタクトスイッチを繋ぎます。今回、Raspberry Piの内部プルダウン抵抗を使うため、タクトスイッチ側にプルダウン抵抗は設けていません。

この他にHDMI端子にPCモニタを接続、カメラ端子にカメラモジュールを接続しています。

▼ブレッドボード図

▼回路図

▼実機の接続写真(PCモニタはまだ接続していません)

プログラム

サンプルプログラム

▼デジカメプログラムのサンプルはこちら

import RPi.GPIO as GPIO
import cv2 as cv
import datetime
import threading

global frame

def saveImg():
    d = datetime.datetime.today()
    filename = "IMG{0}{1:02d}{2:02d}_{3:02d}{4:02d}{5:02d}.jpg".format(d.year, d.month, d.day, d.hour, d.minute, d.second)
    print("Save image")
    cv.imshow(filename, frame) #撮影した画像をディスプレイに表示
    cv.imwrite(filename, frame) #撮影した画像の保存

def shutter_callback(channel):
    if channel==17:
        t = threading.Thread(target=saveImg)
        t.start()
        print("SW ON")

cap = cv.VideoCapture(0)

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(17, GPIO.RISING, callback=shutter_callback, bouncetime=200)

try:
    #カメラ画像をリアルタイムでディスプレイに表示
    while True:
        ret, frame = cap.read()
        if not ret:
            print("Can't receive frame")
            break
        cv.imshow("frame", frame)
        k = cv.waitKey(1) & 0xFF
        
        #「q」キーが押されたらプログラム終了
        if k==ord('q'):
            print("Exit")
            break

except KeyboardInterrupt:
    pass

cap.release()
GPIO.cleanup()
cv.destroyAllWindows()

プログラムの要点は以下のとおりです。

  1. タクトスイッチON/OFFを検知するためのGPIO設定
  2. カメラに映った画像をリアルタイムでディスプレイに表示
  3. タクトスイッチONのエッジを検出してカメラ画像を保存

タクトスイッチON/OFFを検知するためのGPIO設定

GPIO.setmode(GPIO.BCM)

GPIO.setmode()でGPIOの各端子指定方法をGPIO番号に指定します。引数を”GPIO.BOARD”にすれば物理端子番号指定となります。

GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

タクトスイッチON/OFFを検出出来るよう、GPIO.setup()メソッドでGPIO 17をInputに設定しています。第3引数でプルアップ・プルダウン抵抗を有効に設定できます。今回、プルダウン抵抗を配置していないので、pull_up_down引数にGPIO.PUD_DOWNを代入し、プルダウン抵抗を有効化しました。これによってスイッチON時は入力がHigh、OFF時はLowと検出されます。

GPIO.add_event_detect(17, GPIO.RISING, callback=shutter_callback, bouncetime=200)

GPIO.add_event_detect()メソッドは、GPIO入力のエッジを検出したときに、呼び出す関数を指定できます。第1引数でGPIO番号を指定。第2引数でアップエッジ、ダウンエッジどちらを検出するか指定します。第3引数は、呼び出す関数を指定します。第4引数は次のエッジ検出まで検出を無視する時間”bouncetime”を指定します。今回、200msを設定しました。

どうしてbouncetimeが必要なの?

タクトスイッチなどの機械スイッチでは、ボタンを押したときに電圧が短時間に変動するチャタリングが生じます。bouncetimeを設定しないとチャタリングによるエッジを検出し、誤動作を招いてしまうので、boucetimeが必要となります。

カメラに映った画像をリアルタイムでディスプレイに表示

cap = cv.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame")
        break
    cv.imshow("frame", frame)
    k = cv.waitKey(1) & 0xFF

OpenCVを用いてカメラ画像をディスプレイに表示します。whileで無限ループさせることで動画としています。

タクトスイッチONのエッジを検出してカメラ画像を保存

def shutter_callback(channel):
    if channel==17:
        t = threading.Thread(target=saveImg)
        t.start()
        print("SW ON")

GPIO.add_event_detect()メソッドでshutter_callback関数を登録したので、タクトスイッチONでエッジ検出されたらshutter_callback関数が呼び出されます。カメラ画像のリアルタイムPCモニタ表示は継続したいので、新しくスレッドを立ち上げます。

threading.Thread()メソッドの引数に、実行する関数”saveImg”を指定してインスタンスを生成します。

t.start()メソッドでsaveImgを実行します。

def saveImg():
    d = datetime.datetime.today()
    filename = "IMG{0}{1:02d}{2:02d}_{3:02d}{4:02d}{5:02d}.jpg".format(d.year, d.month, d.day, d.hour, d.minute, d.second)
    print("Save image")
    cv.imshow(filename, frame) #撮影した画像をディスプレイに表示
    cv.imwrite(filename, frame) #撮影した画像の保存

カメラ画像を保存するための関数を作成しました。この関数は、タクトスイッチが押されたときの時間をファイル名とし、カメラ画像をカレントフォルダに保存します。

プログラム実行結果

▼タクトスイッチを押す前です。フォルダに画像は保存されていません。

▼タクトスイッチを押した後です。押した瞬間のカメラ画像がフォルダに保存されました。

まとめ

以上、Raspberry Piを使ったデジカメもどきの製作解説でした。デジカメ製作の基本プログラムは出来ましたので、デジカメサイズに収まるハードウェアを設計すれば(これが一番難しい・・・)デジカメが出来上がります。機会があれば小型ディスプレイ購入、筐体を製作し、パッケージングしてみたいと思います。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

大学で機械工学を学んだ後、製造業で働く40代の会社員です。
IT系、電気系を学んでこなかった機械系人間が、ゲーム制作、電子工作に奮闘してます。
極力低コストでものづくりを楽しむのがモットー。

目次