はじめに
最近カムロボを素体に遠隔操作ロボを作って遊んでいるが,遠隔操作にはカメラが欲しいということで,映像と音声をストリーミングする手段を模索していた.
構成
映像+音声ストリーミングにはいくつかの手段があるようだが,今回は ffmpeg を利用してみる.全体像はこんな感じ.
必要なものは次の通り.
- RaspberryPi 本体
- カメラモジュール
- Raspi Zero 用 FFC ケーブル
- USB マイク
- USB OTG アダプタ
Raspi 本体は Amazon で買うと馬鹿みたいに高いので秋月等で買ったほうが良さげです.なお今回はカムロボに組み込む都合上 Raspi Zero W を利用するが,ストリーミングにはそれなりに CPU 性能と NW 帯域が必要になるので,クアッドコア + Gigabit Ethernet + 5GHz な 3B+ 以降を利用したほうが良さげです.
$ cat /proc/device-tree/model
Raspberry Pi Zero
映像+音声ストリーミング
raspi-config でカメラモジュールを有効化する.
$ sudo raspi-config
ffmpeg をインストールする.
$ sudo apt-get install ffmpeg
カメラの認識状態は次の通り.video0 として認識されている.
$ v4l2-ctl --list-device
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
mmal service 16.1 (platform:bcm2835-v4l2-0):
/dev/video0
マイクの設定は次の通り..asoundrc ファイルは無ければ作る.
$ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: Device [USB PnP Sound Device], デバイス 0: USB Audio [USB Audio]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
$ cat ~/.asoundrc
pcm.!default {
type asym
capture.pcm {
type plug
slave.pcm "input"
}
}
pcm.input {
type hw
card 1
}
ffmpeg でストリーミングを開始する前に, VLC の方で メディア > ネットワークストリームを開く から udp://@:1234
を指定して,ユニキャストの待ち受け状態にしておく必要がある.
VLC の準備ができたら ffmpeg コマンドでストリーミングを開始する.
$ ffmpeg -f alsa -ac 1 -thread_queue_size 8192 -i hw:1 \
-f video4linux2 -input_format yuyv422 -video_size 640x480 -r 12 -i /dev/video0 \
-c:a copy -b:a 64k \
-c:v h264_omx -b:v 512k -vf "rotate=PI" \
-fflags nobuffer -f mpegts \
udp://{ユニキャスト先のIPアドレス}:1234
一応コマンドの書き方はこんな形.
SYNOPSIS
ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
一応見やすいよう改行を入れているものの,オプションが長すぎて初見だとわけわからないので一応内容メモしておく.
- 音声入力の設定 (alsaの入力設定)
- -f alsa
- 入力を alsa に設定
- -ac 1
- オーディオチャンネル(audio channels)数を 1 に設定(モノラル)
- -thread_queue_size 8192
- キューのパケット数を設定
- -i hw:1
- 入力デバイスを arecord で確認した USB マイクに設定
- -f alsa
- 映像入力の設定 (v4l2の入力設定)
- -f video4linux2
- 入力を video4linux2(v4l2) に設定
- -input_format h264
- フォーマットを h264 に設定
- 指定可能なパラメータは次のコマンドで確認
$ ffmpeg -f v4l2 -list_formats all -i /dev/video0
- ビデオ圧縮方式の説明はこのサイトがわかりやすい
- -video_size 640×480
- ビデオサイズを設定
- -r 12
- フレームレートを 12fps に設定
- -i /dev/video0
- 入力デバイスを video0 に設定
- -f video4linux2
- 出力設定
- -c:a copy
- オーディオコーデックを入力のまま利用.
- -b:a 64k
- オーディオビットレートを設定
- -c:v h264_omx
- ビデオコーデックを設定
- copy の方が処理しなくて済むので軽量化できるが,カメラの設置向きの都合上回転フィルタを入れる必要がありやむなし.
- 回転有無によらずそれなりに遅延は発生したので大きな影響は無いのかもしれない
- -b:v 512k
- ビデオビットレートを設定
- -vf “rotate=PI”
- ビデオフィルタで pi[rad] 回転
- -f mpegts
- 出力形式を指定
- udp://{ユニキャスト先のIPアドレス}:1234
- 出力先を設定
- -c:a copy
私の環境では結構ばらつきがあって 2〜30 秒程度のラグ.Wi-Fi が混雑しているのか,このキャプチャでは 32 秒も遅れている.
この状態で loadavg≒1.4 くらい.
(ほぼ効果がなかった)遅延改善
ストリーミング中のロードアベレージは常に 1 を超えており CPU 性能が足りていない.またメモリは余裕があるものの,GPUはデフォルト 128M ではやや貧弱かも.
ffmepg のオプションで改善できる部分もあるらしいが,Raspi Zero ではほぼ効果が見られなかった.が,以下の設定変更でもほぼ改善は見られなかった.
GL Driver 有効化
raspi-config から GL Dirver を有効にする.
GPU増量
raspi-config から GPU を 128 → 256 に増量する.
クロックアップ
config.txt を編集して arm_freq にクロックアップする周波数を指定する.OS 動作中は負荷に合わせて周波数が変動するが,arm_freq を設定することで最大周波数が変更される.周波数固定のほうが動作が安定しそうなので,固定オプションも追加.編集が完了したら OS 再起動.
#uncomment to overclock the arm. 700 MHz is the default.
arm_freq=1100
force_turbo=1
CPU の周波数確認は次のコマンド.
$ vcgencmd measure_clock arm
frequency(48)=1100000000
おわりに
火星との通信遅延は 20 分もあるらしいが,ローカルで 30 秒の遅延は遅すぎる.このラグだとさながら自宅探査ロボ.一方で適当に実装中の操作プログラムのレスポンスはそれなりに早いので,映像を見ながら操作するのはかなり難しい.Raspi Zero で低遅延な映像+音声ストリーミングができた人がいればやり方教えてほしいところ.
カメラ固定パーツはこちら.
コメント