はじめに
Raspberry Pi と USB カメラを使った工作です。
仕事で、コンベアを流れてきたものを自動で撮影することになりました。場所は屋内ですが、PC を置ける場所がありません。そんな予算もありません。
そこで、Raspberry Piを使うことにしました。これなら 1 万円程度で収まります。
シャッターの代わりは、当初はボタンとか機械的なスイッチを考えていました。しかし、コンベアの周囲にスイッチを固定できそうな場所がありません。そこで、距離センサを使うことにしました。
画像は1日の終わりに取り出せれば良いので、撮影したらとりあえず micro SD に保存することにしました。
探せば、似たような(あるいはもっと高度な)システムを作っている方がたくさんいます。
それらの二番煎じですが、自分の備忘録として残します。
用意するもの
- Raspberry Pi ... 1 式
- Raspberry Pi 3 model B+ を使用したが、他のモデルでも大丈夫なはず。
- OS は、Rasbian Stretch。
- Python 3.5.3。
- USB カメラまたはカメラモジュール ... 1 個
- 手元にあった USB カメラ (Buffalo BSW13K05H) を使用したが、他の製品でも大丈夫なはず。
- カメラモジュールは v1 互換品を使用したが、v2 互換品でも大丈夫なはず。
- タクトスイッチ ... 2 個
- シャッター用とシャットダウン用。
- PC ケースから剥がしたものを使用したので、GPIO ピンに挿せるようになっていた。
- 部品単品を使うなら別途ジャンパワイヤ(オス-メス) が 4 本必要。
- 超音波距離センサ (HC-SR04) ... 1 個
- 距離の測定に使用。
- LED ... 緑と赤 各 1 個
- 緑は待機中表示に、赤は処理中表示に使用。
- 抵抗 ... 4 個
- 330Ω と 470Ω ... HC-SR04 用に各 1 個
- 330Ω ... LED用に 2 個
- ブレッドボード ... 小 1 個
- ジャンパワイヤ(オス-メス) ... 10 本程度
- 電源ラインがないブレッドボードを使用したので、ちょっと多め。
ハードウェアの接続
- Raspberry Pi の電源を切る。
- カメラを接続する。
- USB カメラなら、USB ポートに接続する。
- カメラモジュールなら、リボンケーブルを CPI に接続する。
- タクトスイッチを接続する。
- シャッタースイッチを 13 番ピン (GPIO27) と 14 番ピン (GND) に接続する。
- シャットダウンスイッチを 39 番ピン (GND) と 40 番ピン (GPIO21) に接続する。
- 超音波センサ HC-SR04 を接続する。
- HC-SR04 の Gnd を 9 番ピン (GND) に接続する。
- HC-SR04 の Gnd に 470Ω を接続する。
- HC-SR04 の Echo に 330Ω を接続する。
- 2つの抵抗の反対側を 11 番ピン (GPIO17) に接続する。
- HC-SR04 の Trig を 12 番ピン (GPIO18) に接続する。
- HC-SR04 の Vcc を 2 番ピン (5V) に接続する。
- LEDを接続する。
- 緑色と 330Ω を直列にして 29 番ピン (GPIO5) と 30 番ピン (GND) に接続する。
- 赤色と 330Ω を直列にして 33 番ピン (GPIO13) と 34 番ピン (GND) に接続する。
部品をブレッドボードに刺したもの。
Raspberry Pi に接続したもの。
左下でとぐろを巻いているのは、PC ケースから剥がしたタクトスイッチ。
システムの構築
準備
- カメラを使えるように、設定する。
- USB カメラであれば、
sudo apt-get install fswebcam
として fswebcam をインストールしておく。 - カメラモジュールであれば、
sudo raspi-config
などでカメラインターフェイスを有効化して、再起動する。
- USB カメラであれば、
- 下の Python スクリプト
auto_camera.py
を Raspberry Pi に転送する。
auto_camera.py
# auto_camera.py
# for python 3.5 and more
import os
import subprocess
import sys
from datetime import datetime
from time import sleep
from gpiozero import LED, Button, DistanceSensor
from picamera import PiCamera
## Configurations
#CAMERA_MODULE = 'PiCamera' # 'USB' or 'PiCamera'
CAMERA_MODULE = 'USB' # 'USB' or 'PiCamera'
SHUTTER = 'BUTTON' # 'BUTTON' or 'DISTANCE'
#SHUTTER = 'DISTANCE' # 'BUTTON' or 'DISTANCE'
SHUTTER_DISTANCE = 1.0 # Shutter when something will get close then 1.0m
USE_LED = True #
STOP_BY_SHUTDOWN = True # True for shutdown, False for exit()
stop_auto_camera = lambda _=None: subprocess.run(('sudo', 'shutdown', '-h', 'now')) if STOP_BY_SHUTDOWN else sys.exit()
dummy_led = type('', (), {'on': lambda: None, 'off': lambda: None, 'blink': lambda **kw: None})
## Set up LEDs, super sonic sensor and buttons on GPIO
led_wait = LED(pin=5) if USE_LED else dummy_led # HIGH = pin 29, GND = pin 30
led_busy = LED(pin=13) if USE_LED else dummy_led # HIGH = pin 33, GND = pin 34
if SHUTTER == 'BUTTON':
shutter = Button(pin=27) # HIGH = pin 13, GND = pin 14
wait_shutter = shutter.wait_for_press
else:
shutter = DistanceSensor(echo=17, trigger=18, max_distance=3.0, threshold_distance=SHUTTER_DISTANCE) # ECHO = pin 11, TRIG = pin 12, 5V = pin 2, GND = pin 9
wait_shutter = shutter.wait_for_in_range
exit_sw = Button(pin=21) # HIGH = pin 40, GND = pin 39
exit_sw.when_pressed = stop_auto_camera
## Guard from no camera
if not os.path.exists('/dev/video0'):
# shutdown withoutcamera
led_busy.blink(on_time=1, off_time=1, n=5)
stop_auto_camera()
## Set camera control object
if CAMERA_MODULE == 'PiCamera':
camera = PiCamera()
camera.resolution = (1024, 768)
else:
camera = type('', (), {})
camera.capture = lambda imgpath: subprocess.run(('fswebcam', '--quiet', '--resolution', '1024x768', '--no-banner', imgpath))
camera.start_preview = lambda: None
camera.stop_preview = lambda: None
## take a photo for each shutter
camera.start_preview()
while True:
led_wait.off()
led_busy.on()
cur = datetime.now()
imgdir = cur.strftime('%Y%m%d')
os.makedirs(imgdir, exist_ok=True)
imgpath = cur.strftime('%Y%m%d/%Y%m%d-%H%M%S.jpg')
camera.capture(imgpath)
led_busy.off()
led_wait.on()
wait_shutter()
camera.stop_preview()
ボタンで撮影
-
auto_camera.py
の定数の値を修正する。- カメラに合わせて、
CAMERA_MODULE
の値を'USB'
(USB カメラ)または'PiCamera'
(カメラモジュール) から選択する。 - LED を使わないなら、
USE_LED = False
にする。
- カメラに合わせて、
-
python3 auto_camera.py
を実行する。- 赤色 LED が点灯して、しばらくすると赤色 LED が消灯 LED して緑色が点灯する。
- 実行したディレクトリに、日付のサブディレクトリができている。書式は
yyyymmdd
。 -
yyyymmdd
の下に、日時を名前にした画像ファイルが保存されている。書式はyyyymmdd-HHMMSS.jpg
。
- シャッターボタンを押す。
- ボタンを押すと、緑色 LED が消灯して赤色 LED が点灯する。しばらくすると赤色 LED が消灯 LED して緑色が点灯する。
-
yyyymmdd
の下に、画像ファイルが追加されている。
- Ctrl+C を押して
auto_camera.py
を終了する。
超音波センサーで撮影
-
auto_camera.py
の定数の値を修正する。-
SHUTTER
の値を'DISTANCE'
(超音波センサー)に変更する。 - X m 以内に近づいたらシャッターを切るように、
SHUTTER_DISTANCE
の値を変更する。X は 0.5~4.0 くらいの間。
-
- 超音波センサーの前を空ける。
- 少なくとも
SHUTTER_DISTANCE
以内に、物がないようにする。
- 少なくとも
-
python3 auto_camera.py
を実行する。- ボタンの時と同様に動作する。
- 超音波センサーでシャッターを切る。
- 超音波センサーの前に何かを置いたり手をかざしたりすると、緑色 LED が消灯して赤色 LED が点灯する。しばらくすると赤色 LED が消灯 LED して緑色が点灯する。
-
yyyymmdd
の下に、画像ファイルが追加されている。
- Ctrl+C を押して
auto_camera.py
を終了する。
ボタンでシャットダウン
-
python3 auto_camera.py
を実行する。 - シャットダウンボタンを押す。
- シャットダウン処理が始まる。
- Raspberry Pi の電源付近にある緑色 LED が点滅して消灯したら、シャットダウン完了。
起動時に自動実行
-
crontab -e
を実行してcron
の設定ファイルを開く(sudo
はつけない)。 - 設定ファイルの末尾に
@reboot /usr/bin/python3 /home/pi/auto_camera.py &
を追加する。 - Raspberry Pi を再起動して撮影できることを確認する。
おわりに
とりあえず、何かが近づいたら撮影するカメラが出来上がりました。この後も、
- シャッターに連動してフラッシュを焚く。
- ブラウザ経由で画像を見られるようにする。
- 撮影したことを Twitter などで自分に通知する。
など、いろいろ発展させていきたいです。
- 2019/7/3: auto_camera.py 中の
dummy_LED
を修正