Raspberry PiとPythonによるドライブレコーダー

元々Raspberry Piに興味があったので、ようやく入手したRaspberry Piとカメラモジュールを組み合わせてドライブレコーダーを作成してみた時のメモです。なお、OSインストールや基本設定は済んでいることを前提としています。

# 使用したもの
* Raspberry Pi 3
* Raspbian Stretch Lite
* Python3
* カメラモジュール 
* カーチャージャー
* USBメモリ(東芝製 16GB)

# 構成
特別なところはなく、Raspberry Piにカメラモジュールと動画ファイルの保存先としてUSBメモリを接続しただけです。(カメラはとりあえずテープで固定(^^;))これだけでドライブレコーダーにもなるところがRaspberry Piは素晴らしいところですね。

![IMG_1003.JPG](https://qiita-image-store.s3.amazonaws.com/0/165991/ee8821aa-f379-48fb-0d8a-9c771c4d55f5.jpeg)

# カメラモジュール
今回購入したカメラモジュールはこちら。

[サインスマート Raspberry Pi 用 カメラモジュール](https://www.amazon.co.jp/gp/product/B00FGKYHXA/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)

# 電源
電源はRaspberry Pi3が要求する2.5Aに対応するため、車載のシガーソケット経由で5.5Aまで供給可能で、他の用途にも併用できそうな下記のUSBカーチャージャーを使用しました。

[PISEN カーチャージャー 車載充電器 USBポート×3 （合計5.5A出力）](https://www.amazon.co.jp/gp/product/B00ILUHN74/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)

# USBメモリ
Raspberry Piの内蔵ディスクであるSDカードはサイズに余裕が無く、書き込み回数に制限がある点から、動画の保存先にはUSBメモリを使用しました。

USBメモリはRaspberry Piでの利用実績が確認された東芝製のUSBメモリを使用しました。
[TOSHIBA 16GB USBフラッシュメモリ](https://www.amazon.co.jp/gp/product/B071V5VYKP/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1)

# USBメモリの設定
USBメモリを挿してOSを起動したところ、今回は他にUSBデバイスを挿していなかったこともあって/dev/sdaで認識されました。

```zsh
# lsusb
Bus 001 Device 005: ID 0930:6544 Toshiba Corp. TransMemory-Mini / Kingston DataTraveler 2.0 Stick (2GB)

# fdisk -l /dev/sda
Disk /dev/sda: 14.5 GiB, 15518924800 bytes, 30310400 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
```

USBメモリをext4でフォーマットします。

```zsh
# mkfs -t ext4 /dev/sda
mke2fs 1.43.4 (31-Jan-2017)
Found a dos partition table in /dev/sda
Proceed anyway? (y,N) y
Creating filesystem with 3788800 4k blocks and 948416 inodes
Filesystem UUID: 5abc6e6d-bed2-4898-a263-13e07621deae
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208

Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
```

次にOS起動時に自動マウントするため/etc/fstabに設定しますが、その前に/dev/sdaに対応するby-path名を確認しておきます。(/dev/sdaなどのデバイス名は常に一意にUSBメモリを指す訳では無いため。USBメモリを挿すポートも、変えるとby-path名が変わるはずなので安易に変えないよう気を付けます。)

```zsh
# ls -l /dev/disk/by-path | grep sda
lrwxrwxrwx 1 root root  9 Mar 25 17:17 platform-3f980000.usb-usb-0:1.5:1.0-scsi-0:0:0:0 -> ../../sda
```

上記で取得した値を使用して、/etc/fstabに設定します。USBメモリのマウント先は/dataとしました。

```zsh
# cd /etc
# cp -p fstab fstab.YYYYMMDD
# vim fstab

/dev/disk/by-path/platform-3f980000.usb-usb-0:1.5:1.0-scsi-0:0:0:0 /data  ext4  defaults        0       0
```

最後にOS起動時に/dataにUSBメモリがマウントされることを確認します。

```zsh
# mkdir /data
# reboot

# df -h /data
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda         15G   41M   14G   1% /data
```

# 動画撮影
いくつかの撮影用ソフトウェアを比較した結果、今回はPython用のカメラライブラリであるpicameraを使用させて頂きました。(当初はmotionを使用する想定でしたが、必要なライブラリがRaspbian Stretch Liteでは見つからなかったので)

まず、カメラを有効にします。

```zsh

# raspi-config

[5 Interfacing Options  Configure connections to peripherals]
[P1 Camera Enable/Disable connection to the Raspberry Pi Camera]
[Would you like the camera interface to be enabled?]→[Yes]

# reboot
```

次にpicameraをpipでインストールします。

```zsh

# pip3 install picamera
```
picameraを用いて書いた動画撮影用のコードが下記。

```python:movie.py
#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

import picamera
import time
import sys

FILEPATH = '/data/'
MOVIE_INTERVAL = 600

def main(now):
    filename = FILEPATH + now + ".h264"
    with picamera.PiCamera() as camera:
        camera.hflip = True
        camera.vflip = True
        camera.resolution = (1024,768)
        camera.brightness = 70
        camera.start_recording(filename)
        time.sleep(MOVIE_INTERVAL)
        camera.stop_recording()

if __name__ == '__main__':
    if len(sys.argv[1:]) != 1:
        print("Invalid argument.")
        sys.exit(1)
    main(sys.argv[1])
```

コードの補足です。

* 動画ファイルはUSBメモリのマウント先である/data以下に保存します。
* 動画の撮影時間は10分間
* hflipメソッドとvflipメソッドでカメラの向きを調整
* resolutionメソッドで解像度を調整
* brightnessメソッドで明るさを調整
* スクリプトの引数には日時を渡す想定です。
* その他、picamera使用時に発生したエラーは、[picameraでエラー発生時の対象方法](https://qiita.com/kutsurogi194/items/69f73664a729d1d5df8f) に書きました。

最後に作成したPythonスクリプトのラッパーを作成します。

```zsh:driverecord.sh
#!/bin/zsh -x

DATE=""

while :
do
    DATE=$(date "+%Y%m%d_%H%M%S")
    /usr/local/bin/movie.py "${DATE}"
    if [ $? -ne 0 ]; then
        echo "Camera Recording Error."
        exit 1
    fi
done
```

# 動画撮影スクリプトの自動起動
OS起動時に作成した動画撮影用スクリプトの自動起動設定を入れます。
今回使用したRaspbian Stretch Liteではsystemdが採用されているので、従来の/etc/rc.localではなく、systemdのUnitファイルを作成します。

```zsh:/etc/systemd/system/driverecord.service
[Unit]
Description=run drive record during boot
After=network.target

[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/usr/bin/zsh -c "/usr/local/bin/driverecord.sh >> /data/camera_$$(/bin/date +%%Y%%m%%d_%%H%%M%%S).log 2>&1"

[Install]
WantedBy=multi-user.target
```

こちらの記事を参考にさせて頂きました。ありがとうございます。
[systemdでOS起動時に任意のプログラムを実行する](https://qiita.com/irotoris/items/5187e0c741eca4d0c563)

# 車への搭載
写真のように搭載しています。ここでもRaspberry Pi本体の固定にはテープが活躍(^^;)

![IMG_1019.JPG](https://qiita-image-store.s3.amazonaws.com/0/165991/52bb41cd-8223-d64f-65a8-63593f510944.jpeg)

# 動画の変換
USBメモリに保存された動画ファイル(h264)はmp4に変換しました。
変換処理は今回はMacBookで行っています。

変換処理で使用するMP4Boxを含むGPACをMacにインストールします。
https://gpac.wp.imt.fr/downloads/gpac-nightly-builds/

Raspberry Piから動画ファイルをMacの適当なディレクトリにコピーして纏めてmp4に変換します。

```zsh
# cd DriveRecord
# scp -r "username@hostname:/data/*" .
# ls -1 *264 | awk -F "." '{print $1}' | while read l; do MP4Box -fps 30 -add $l.h264 $l.mp4; done
```

# 撮影した動画
mp4からさらに変換・圧縮したgifなので若干粗めですが、実際はもう少しよく撮れてます。

![drivetest5.gif](https://qiita-image-store.s3.amazonaws.com/0/165991/d1a2f176-8a41-d23b-1005-fd30704ef75d.gif)


# 課題
現状は、車のエンジンの停止と同時にRaspberry Piが止まるため(要は電源ブチ切り)、OSやディスクに対する不安と、次回起動時にOSの時刻が狂ってしまう点が課題です。
一応、電源ブチ切り後でも動きますし(一度、USBメモリのファイルシステムが壊れました(汗))、時間も家のwi-fiやスマホのテザリング環境下でNTPを使えば元に戻りますが、、シャットダウンボタンの取り付けとGPSで解決できそうなので追々対応できればと考えています。