スキルは無いのだけれども色々と組み合わせて RaspberryPi Zero を使ってアクションカメラを作れないかやってみました。"アクションカメラ"を構成する主な機能について以下に概要を挙げる事にします。
構成
RaspberryPi zero。pimoroniで"Scroll pHAT"付きキットを購入しました。
外ヘ持ち出すのでバッテリーが必要。(Anker PowerCore 10000)
USBカメラは探した中で最も安かった Logicool HD WEBCAM C270。
USBハブを使用して、カメラとBluetoothのUSBアダプタを接続しています。
Pi2や3ならばハブは必要ないですね。
AB Shutter 3 というのは自撮り棒についてきた安価なカメラリモコンで、これを使用して録画の開始停止を操作します。
USBカメラによる録画
以下を参考させて頂きました。
http://d.hatena.ne.jp/embedded/20151012/p2
gstreamerをインストールした後、以下で音声付きで録画される事を確認しました。
$ gst-launch-1.0 -e v4l2src ! "video/x-raw,width=640,height=480,framerate=30/1" ! omxh264enc target-bitrate=1000000 control-rate=variable ! video/x-h264,profile=high ! h264parse ! queue ! mp4mux name=mux alsasrc device=hw:1 ! audioresample ! audio/x-raw,rate=48000 ! queue ! voaacenc bitrate=32000 ! queue ! mux. mux. ! filesink location=test.mp4
pythonコード上では上記コマンドをpopenで実行させる事にしました。gstreamerを制御するpythonのライブラリを探したのですが、すぐに理解できる簡単なものがみつからなかったので。
また、解像度は640x480で低いのですが、これ以上解像度を上げるとC270の仕様上フレームレートが30fpsに満たなくなるため我慢です。
import subprocess
import shlex
import signal
exec_command = "gst-launch-1.0 -e v4l2src ! \"video/x-raw,width=640,height=480,framerate=30/1\" ! omxh264enc target-bitrate=1000000 control-rate=variable ! video/x-h264,profile=high ! h264parse ! queue ! mp4mux name=mux alsasrc device=hw:1 ! audioresample ! audio/x-raw,rate=48000 ! queue ! voaacenc bitrate=32000 ! queue ! mux. mux. ! filesink location={}".format(filename)
args = shlex.split(exec_command)
proc = subprocess.Popen(args)
録画を終了する場合、いきなりPopen.terminate()とかPopen.kill()をしてしまうとファイルフォーマットが正しい状態にならず再生出来ないファイルになってしまうようなので、SIGINTのシグナルを送って、プロセスが終了するのを待つようにします。
proc.send_signal(signal.SIGINT)
proc.wait()
Bluetoothデバイスによる制御
録画の開始と停止を制御したく、何か良い方法は無いかな考えていたところ、昔購入した自撮り棒に付いていた、カメラリモコンが使えないかなと思いました。ちなみに付いていたのは以下。
AB Shutter 3 というもの。
もしRaspberryPiでBluethooth接続できて、Pythonでボタン押下を検知できるならば録画の開始停止の制御に使えると思った次第。
$ bluetoothctl
[bluetooth]# scan on
Discovery started
[CHG] Controller YY:YY:YY:YY:YY:YY Discovering: yes
Bluethooth機器を探してみます。カメラリモコンの電源をOnにしてみると、
[NEW] Device XX:XX:XX:XX:XX:XX AB Shutter 3
見つかりました。ペアリングしてみます。
[bluetooth]# pair XX:XX:XX:XX:XX:XX
Attempting to pair with XX:XX:XX:XX:XX:XX
[CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
[CHG] Device XX:XX:XX:XX:XX:XX Modalias: bluetooth:v0A5Cp4502d011B
[CHG] Device XX:XX:XX:XX:XX:XX UUIDs:
00001000-0000-1000-8000-00805f9b34fb
00001124-0000-1000-8000-00805f9b34fb
00001200-0000-1000-8000-00805f9b34fb
[CHG] Device XX:XX:XX:XX:XX:XX Paired: yes
Pairing successful
つながりました。以降、自動接続されるようにしておく。
[bluetooth]# trust XX:XX:XX:XX:XX:XX
[CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes
Changing XX:XX:XX:XX:XX:XX trust succeeded
デバイスファイルを見てみます。
pi@pizero:/dev/input $ cd /dev/input/
pi@pizero:/dev/input $ ls
by-id by-path event0 mice
カメラリモコンの電源をONにすると
pi@pizero:/dev/input $ ls
by-id by-path event0 event1 mice
event1というデバイスファイルが増えました。ここから入力を検出できそう。
python-evdev(https://python-evdev.readthedocs.io) で/dev/inputにあるデバイスファイルから入力を取ります。evdevのサンプルコードを試してみます。
import evdev
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
for device in devices:
print (device.fn, device.name, device.phys)
#
shutterdev = evdev.InputDevice('/dev/input/event1')
print(shutterdev)
for event in shutterdev.read_loop():
if event.type == evdev.ecodes.EV_KEY:
print(evdev.util.categorize(event))
pi@pizero:~/app/python3 $ python3 evdev_test.py
/dev/input/event1 AB Shutter 3 00:1b:dc:06:a6:39
/dev/input/event0 UVC Camera (046d:0825) usb-20980000.usb-1.2/button
device /dev/input/event1, name "AB Shutter 3", phys "00:1b:dc:06:a6:39"
key event at 1478875240.192857, 28 (KEY_ENTER), down
key event at 1478875240.305511, 28 (KEY_ENTER), up
key event at 1478875242.780943, 115 (KEY_VOLUMEUP), down
key event at 1478875242.826080, 115 (KEY_VOLUMEUP), up
カメラリモコンの2つのボタンを押すと、それぞれENTERとVOLUME_UPキーが検出されているのがわかりました。これでPythonでカメラリモコンのキー押下に応じて録画制御が出来そうです。
LED表示
録画中あるいは停止中などの状態表示が必要なので、Scroll pHATを使ってみます。
ライブラリが用意されていて、英字であれば簡単に表示できます。以下は例で"REC"をスクロール表示させているところ。
import scrollphat
import time
scrollphat.clear_buffer()
scrollphat.write_string("REC",11)
length = scrollphat.buffer_len()
for i in range(length):
scrollphat.scroll()
time.sleep(0.1)
できあがり
上記を組合せて、BluetoothデバイスからVloumeUpキーが得られれば、録画を開始してLEDに録画開始のメッセージを表示させる。Enterキーを得たのであれば、停止とその旨をLEDに表示させるようにします。
また、バッテリーが切れると録画ファイルが破損してしまうので、30分毎に自動的に録画を区切るようにしました。
バッテリーがどれほど持つのか確認するために、夜中の12時頃から録画を開始して放置しておきました。
最後に作成されたファイルはバッテリー切れでファイルが破損しているので、30分の動画が20個録画されています。10時間分は録画出来ているという事になりますが、深夜の時間帯は暗い部屋で放置していて、全く動きのない動画が作成されているので、バッテリーの消費が抑えられているのかもしれません。