Raspberry Pi 3 Model BにインストールしたDocker上からカメラを扱う

Raspberry Pi 3 Model BにDockerをインストールし、さらにDockerコンテナ上からRaspberry Piカメラモジュールを使った際のメモです。

結論から言えば、`raspistill`コマンドで静止画を、`raspivid`コマンドで動画をそれぞれ撮影することができました。
本記事ではRaspberry Piカメラモジュール（CSI接続）のみを扱い、USBカメラについては述べていませんのでご注意ください。

Raspberry Pi 3 Model BにDockerをインストール方法については別のQiita記事『[Raspberry Pi 3 Model B(Raspbian)にDockerをインストールする](http://qiita.com/yuyakato/items/1cdc7fa511f7767c95ac)』を書きました。

## 3行まとめ

* Dockerコンテナ上からもRaspberry Piカメラモジュールを使用できる。
* `raspistill`コマンド、`raspivid`コマンドは`libraspberrypi-bin`パッケージに含まれている。
* Raspberry Piカメラモジュールを使用するためには、`docker run`コマンドに`--privileged`オプションが必要となる。

## 環境

本記事の執筆時の環境は以下の通りです。

```
# Raspberry Piに接続する。mDNS名称を使う。
macOS$ ssh pi@raspberrypi.local

# OSのバージョンを確認する。
pi@raspberrypi$ uname -a
Linux raspberrypi 4.4.34-v7+ #930 SMP Wed Nov 23 15:20:41 GMT 2016 armv7l GNU/Linux
pi@raspberrypi$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

# Dockerのバージョンを確認する。
pi@raspberrypi$ docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:13:32 2017
 OS/Arch:      linux/arm

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:13:32 2017
 OS/Arch:      linux/arm
 Experimental: false
```

## `libraspberrypi-bin`パッケージのインストール

Raspbianのベースイメージには`sdhibit/rpi-raspbian`を使用しました。よく紹介される`resin/rpi-raspbian`は`bash`すら正常に起動できなかったためです。（詳しくは調べていません）
また、ハードウェアにアクセスするため、`docker run`コマンドに`--privileged`オプションが必要です。もっと細かく権限を指定することもできるかと思いますが、今回は詳しく調べていません。

`raspistill`コマンド、`raspivid`コマンドは`libraspberrypi-bin`パッケージに含まれており、該当パッケージは`firmware`リポジトリに含まれていますので、それをインストールします。

```
# Dockerコンテナ上でRaspbianのbashを起動する。
pi@raspberrypi$ docker run --interactive --tty --rm --privileged \
  sdhibit/rpi-raspbian \
  /bin/bash

# ここからDockerコンテナ内。
# OSのバージョンを確認する。
root@docker$ uname -a
Linux 3eb8e87bda27 4.4.34-v7+ #930 SMP Wed Nov 23 15:20:41 GMT 2016 armv7l GNU/Linux
root@docker$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

# デフォルトのパッケージソースを確認する。
root@docker$ cat /etc/apt/sources.list
deb http://archive.raspbian.org/raspbian jessie main

# パッケージソースを書き換える。
root@docker$ echo "deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi firmware" > /etc/apt/sources.list

# libraspberrypi-binパッケージをインストールする。
root@docker$ apt-get update
root@docker$ apt-get install --yes libraspberrypi-bin

# raspistillコマンド、raspividコマンドが存在することを確認する。
root@docker$ which raspistill
/usr/bin/raspistill
root@docker$ which raspivid
/usr/bin/raspivid
```

## 撮影

`raspistill`コマンド、`raspivid`コマンドは、通常の環境（Dockerホスト側）と同様に使用できます。

```
# 静止画を撮影する。
root@docker$ raspistill --output /tmp/still.jpg
# 動画を撮影する。
root@docker$ raspivid --output /tmp/video.h264 --timeout 3000

# 撮影したファイルをDockerホスト側にコピーする。（「0cd3938672a8」はコンテナID）
pi@raspberrypi$ docker cp 0cd3938672a8:/tmp/still.jpg .
pi@raspberrypi$ docker cp 0cd3938672a8:/tmp/video.h264 .
```

`docker run`コマンドに`--privileged`オプションを指定しなかった場合は、以下の様なエラーが出力されます。

```
root@docker$ raspistill --output /tmp/still.jpg
* failed to open vchiq instance
root@docker$ raspivid --output /tmp/video.h264 --timeout 3000
* failed to open vchiq instance
```

## 参考

参考にしたサイトは以下の通りです。

* [docker run | Docker Documentation](https://docs.docker.com/engine/reference/commandline/run/)
* [Raspberry Pi • View topic - Raspistill not working in docker container](https://www.raspberrypi.org/forums/viewtopic.php?t=155660&p=1017941)
* [Raspberry Pi メモ (23) - カメラモジュールの使い方](http://www.mztn.org/rpi/rpi23.html)
* [raspistill - Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/usage/camera/raspicam/raspistill.md)
* [raspivid - Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/usage/camera/raspicam/raspivid.md)