注釈

こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 Enthusiast Community on Facebookへようこそ!他の愛好家と一緒に、Raspberry Pi、Arduino、ESP32の世界により深く入り込みましょう。

参加する理由

  • 専門家サポート: 購入後の問題や技術的な課題を、コミュニティと私たちのチームの助けを借りて解決します。

  • 学習と共有: ヒントやチュートリアルを交換して、スキルを向上させましょう。

  • 限定プレビュー: 新製品の発表や先行プレビューに早期アクセスできます。

  • 特別割引: 最新製品を特別割引でお楽しみいただけます。

  • 季節限定キャンペーンとプレゼント: プレゼント企画やホリデーキャンペーンに参加しましょう。

👉 一緒に発見し、創造する準備はできましたか? [こちら] をクリックして、今すぐ参加しましょう!

4.2 自動撮影カメラ

はじめに

留守中に、好奇心旺盛な小さなリスが窓辺を訪れたらどうでしょうか。このプロジェクトでは、そんな愛らしい瞬間を自動で撮影できるカメラを作成します。モーションセンサーを使って動きを検出し、一定間隔で写真を撮影します。


必要なもの

このプロジェクトで必要なコンポーネントは以下のとおりです。

COMPONENT INTRODUCTION

PURCHASE LINK

ブレッドボード

購入

ジャンパーワイヤー

購入

抵抗器

購入

PIRモーションセンサーモジュール

購入

カメラモジュール

購入

Fusion HAT+

-

Raspberry Pi

-


回路図

以下はこのプロジェクトの回路図です。

../_images/4.1.2_sch.png

配線図

  1. カメラモジュールを便利に使用するために、パン・チルトの組み立て(カメラ用) を推奨します。

    注釈

    パンチルトを組み立てると一部のピンが隠れてしまう場合があるため、カメラを使用するときだけ組み立てるか、組み立て後に外側へ配置することをおすすめします。

    ../_images/gimbal_assemble.png
  2. 以下の配線図に従って回路を組み立ててください。

    ../_images/4.1.2_bb.png
  3. 最適な動作のために、PIRモジュール上の2つの可変抵抗を調整してください。1つは感度、もう1つは検出距離を調整します。両方とも反時計回りいっぱいまで回してください。

    ../_images/PIR_TTE.png

サンプルの実行

  1. Raspberry Pi のデスクトップにアクセスします。

  2. ターミナルを開き、コードフォルダへ移動します。

    cd ~/ai-lab-kit/python
    
  3. スクリプトを実行してカメラを起動します。

    sudo python3 4.2_AutomaticCaptureCamera.py
    
  4. スクリプトを実行すると、次のように動作します。

    • カメラが起動し、GPIO17 に接続された PIR モーションセンサーを継続的に監視します。

    • PIR センサーが動きを検出して出力が HIGH になると、カメラは1枚の写真を撮影し、連番付きのファイル名で Pictures フォルダに保存します。

    • 撮影後は、連続撮影を防ぐために少し待機します。

    • システムは引き続き動きを監視し、Ctrl + C を押すまで動作し続けます。


コード

以下は、このプロジェクトで使用する Python コードです。

#!/usr/bin/env python3

import os
import time
import threading
from picamera2 import Picamera2, Preview
from fusion_hat.pin import Pin, Mode, Pull

# Resolve the correct user's home directory (works with sudo)
REAL_USER = os.getenv("SUDO_USER") or os.getlogin()
USER_HOME = f"/home/{REAL_USER}"
PICTURES_DIR = os.path.join(USER_HOME, "Pictures")
os.makedirs(PICTURES_DIR, exist_ok=True)

# Initialize camera
camera = Picamera2()
camera.configure(camera.create_preview_configuration(main={"size": (800, 600)}))

# Photo counter with thread safety
photo_index = 1
photo_lock = threading.Lock()

# Track whether preview was started successfully
preview_started = False

# Initialize PIR sensor (GPIO 17)
pir = Pin(17, mode=Mode.IN, pull=Pull.DOWN)

def take_photo():
   """Capture one photo and increment the index."""
   global photo_index
   with photo_lock:
      filepath = os.path.join(PICTURES_DIR, f"photo_{photo_index:03d}.jpg")
      print(f"\nMotion detected! Capturing: {filepath}")
      camera.capture_file(filepath)
      print("Saved.")
      photo_index += 1

def main():
   global preview_started

   # Start preview only when a GUI display is available
   preview_started = False
   if os.getenv("DISPLAY"):
      try:
         camera.start_preview(Preview.QT)
         preview_started = True
      except Exception as e:
         print(f"Preview start failed (continue without preview): {e}")
   else:
      print("No DISPLAY detected (running headless without preview).")

   camera.start()

   print("Camera is running.")
   print("PIR sensor monitoring on GPIO 17.")
   print(f"Photos will be saved to: {PICTURES_DIR}")
   print("Press Ctrl+C to exit.\n")

   try:
      while True:
         if pir.value():        # PIR detects motion (HIGH)
            take_photo()        # Take one photo
            time.sleep(2)       # Delay to avoid repeated shots

         time.sleep(0.1)

   except KeyboardInterrupt:
      print("\nExiting...")

   finally:
      try:
         camera.stop()
      except Exception:
         pass

      if preview_started:
         try:
            camera.stop_preview()
         except Exception:
            pass

      try:
         camera.close()
      except Exception:
         pass

if __name__ == "__main__":
   main()

コードの解説

  1. インポート

    import os
    import time
    import threading
    from picamera2 import Picamera2, Preview
    from fusion_hat.pin import Pin, Mode, Pull
    

    このスクリプトでは、ファイル処理( os )、時間制御( time )、スレッド安全性( threading )、カメラ操作( Picamera2 )、GPIO 制御( Pin )のためのライブラリをインポートしています。

  2. パスの設定

    REAL_USER = os.getenv("SUDO_USER") or os.getlogin()
    USER_HOME = f"/home/{REAL_USER}"
    PICTURES_DIR = os.path.join(USER_HOME, "Pictures")
    os.makedirs(PICTURES_DIR, exist_ok=True)
    

    この部分では、正しいユーザーのホームディレクトリを取得し、写真保存用の Pictures フォルダが存在することを確認します。

  3. カメラの初期化

    camera = Picamera2()
    camera.configure(camera.create_preview_configuration(main={"size": (800, 600)}))
    

    カメラを初期化し、プレビュー解像度を 800 × 600 に設定しています。

  4. 写真カウンターとスレッドロック

    photo_index = 1
    photo_lock = threading.Lock()
    

    連番付きファイル名を作成するために写真カウンターを使用し、ロックによって撮影処理を安全に行えるようにしています。

  5. PIR センサーの初期化

    pir = Pin(17, mode=Mode.IN, pull=Pull.DOWN)
    

    PIR モーションセンサーは GPIO17 に接続され、プルダウン抵抗付きの入力として設定されています。

  6. 写真撮影関数

    def take_photo():
       """Capture one photo and increment the index."""
       global photo_index
       with photo_lock:
          filepath = os.path.join(PICTURES_DIR, f"photo_{photo_index:03d}.jpg")
          print(f"\nMotion detected! Capturing: {filepath}")
          camera.capture_file(filepath)
          print("Saved.")
          photo_index += 1
    

    この関数は動きが検出されるたびに1枚の写真を撮影し、 Pictures ディレクトリへ保存します。

  7. プレビュー処理とカメラ起動

    preview_started = False
    if os.getenv("DISPLAY"):
       try:
          camera.start_preview(Preview.QT)
          preview_started = True
       except Exception as e:
          print(f"Preview start failed (continue without preview): {e}")
    else:
       print("No DISPLAY detected (running headless without preview).")
    

    グラフィカルな表示環境が利用できる場合のみカメラプレビューを開始し、それ以外の場合はヘッドレスモードで動作します。

  8. メインループ(動き検出)

    while True:
       if pir.value():
          take_photo()
          time.sleep(2)
    

    プログラムは PIR センサーを継続的に監視します。動きが検出されると(HIGH)、1枚の写真を撮影し、その後短い待機時間を入れて連続撮影を防ぎます。

  9. 終了処理とクリーンアップ

    except KeyboardInterrupt:
       camera.stop()
       camera.close()
    

    ユーザーが Ctrl + C を押すと、プログラムは安全に終了し、カメラを停止して閉じます。


トラブルシューティング

  1. 写真が撮影されない

    • 原因:PIR モーションセンサーが動作していない、または配線が正しくありません。

    • 対処方法

      • PIR センサーが GPIO17、電源、GND に正しく接続されていることを確認してください。

      • 必要に応じて、PIR センサーの感度と遅延時間の可変抵抗を調整してください。

  2. PIR センサーが常に動きを検出する

    • 原因:PIR センサーの不具合、または周囲環境による過剰な干渉です。

    • 対処方法

      • マルチメーターでセンサーを確認し、正しく動作しているかテストしてください。

      • 誤検出を避けるため、安定した環境で使用してください。

  3. カメラエラーでスクリプトが停止する

    • 原因:カメラが正しく初期化されていない、または他のプロセスが使用中です。

    • 対処方法

      • カメラが正しく接続され、 raspi-config で有効化されていることを確認してください。

      • Raspberry Pi を再起動して、競合しているプロセスを解放してください。


拡張アイデア

  1. タイムスタンプ付きファイル名:整理しやすいように、写真をタイムスタンプ付きのファイル名で保存します。

    timestamp = time.strftime("%Y%m%d-%H%M%S")
    camera.capture_file(f'{user_home}/capture_{timestamp}.jpg')
    
  2. LED インジケーター:PIR センサーが動きを検出したときに LED を点灯させます。

    from fusion_hat import Pin
    led = Pin(27)
    if pir.value() == 1:
       led.on()
    else:
       led.off()
    
  3. フォトギャラリー管理:撮影した写真を日付やイベントごとにフォルダ分けして自動整理します。


まとめ

このプロジェクトでは、PIR モーションセンサーと Raspberry Pi カメラモジュールを使って、自動撮影カメラシステムを構築する方法を紹介しました。思いがけない瞬間を記録するのに最適であり、IoT やコンピュータビジョンの可能性を広げる良い題材でもあります。さらに動画録画やクラウドアップロードなどの機能を追加して、リアルタイム監視システムへ発展させてみてください。