OpenAuto ProでAndroid Auto搭載カーナビを自作するにあたって外せないのがこの機能。ギアをリバースに入れたら自動的にバックカメラの映像を映し出すようにしたいです。これがないと十中八九、家族にシバかれるでしょう。
OpenAuto Proはバックカメラ、リアカメラの利用をサポートしていますが、RCA端子で接続するカメラをRaspberry Piに直接繋ぐことはできません。基本的にはUSB接続のビデオキャプチャが必要になります。
また筆者が使用したビデオキャプチャの場合、バックカメラを接続して映像を映すことはできたものの、
- 画質が悪い
左右が反転している→元々反転していました。そもそもバックカメラはデフォルトだと左右反転で表示されるのが一般的のようです。今までまったく意識してなかった…- ディスプレイとアスペクト比が一致せず表示位置が偏っている
といった問題があり、常用するにはかなり厳しい状態でした。
そこで諸々の問題を解決するスクリプトを作成、実装してみることにしました。スクリプト利用時はOpenAuto Proが不可解な挙動を示すということもあって、同じようにバックカメラの接続で躓く方は多そうな気がするので、備忘録がてらその方法を紹介しておきます。
ちなみにこの記事で筆者が使用しているのはOpenAuto Pro 15です。OpenAuto Pro 16など他のバージョンでは仕様が変わっているかもしれないのでご注意を。
OpenAuto Proのリアカメラ機能の問題点と解決策
OpenAuto Proにはリアカメラ機能が搭載されています。
Raspberry Piにビデオデバイスを接続して、車からバック信号を取り出してGPIOで検知させてやれば、Android Autoの起動中でも自動的にカメラの映像に切り替えさせることが可能です。
RCA端子で接続する車用のリアカメラはそのままだと接続できませんが、Linuxで動作するUSB接続のビデオキャプチャを使用すれば何とかなりそうではあります。
公式にサポートしているカメラはRaspberry Pi公式カメラモジュールのみ?
ただ厄介なことに、公式にサポートされているカメラはRaspberry Pi公式のカメラモジュールのみとなっています。車用のRCA接続のカメラは一切サポートされておらず、推奨のビデオキャプチャというものありません。
一応OpenAuto ProのベースはRaspberry Pi OSなので、Raspberry Pi OSもといLinuxで使えるビデオキャプチャを使用すれば車のリアカメラも使えると思われます。
ただそもそもLinux対応を謳っている製品が少なく、OpenAuto Proのフォーラムを読み漁ってもどのコントローラーチップを搭載しているビデオキャプチャが良いのか、情報が錯綜していてあまり参考になりませんでした。
下記ブログではデジ造映像版 PCA-DAV2を使用したそうなので、筆者も中古品を購入してみましたが…故障しているのかなかなかRaspberry Pi側から安定して認識されず、映像を映し出すことはできませんでした。。
動作保証はないもののUSBビデオキャプチャでRCA端子のリアカメラも使用可能
中古はダメだなと思い直しまして、Amazonで購入したのがこちらのFS-VC200を名乗っているビデオキャプチャ。
本当にこれがFS-VC200なのかこれまた怪しい香りがしますが、とりあえず使えることは使えました。
デフォルトの設定だと画質が悪くなる?
ただし冒頭でも述べた通り、この自称FS-VC200はデフォルトの設定だと画質等々に問題があって使い物になりませんでした。まあ問題が発生するかどうかは、接続するカメラにもよるかとは思いますが。他のビデオキャプチャでも多々起きている問題のようです。
画質が悪い原因は、カメラの映像をNTSC形式ではなくPAL形式で取り込んでいるからと推測できました。あれこれ調べてみた結論としては、NTSC形式で取り込むように指定してやれば解決しそうです。
独自のスクリプトを設定することで対策可能
OpenAuto Proのリアカメラ機能の設定画面を開くと、3種類のモードが用意されています。デフォルトのV4L2は単純にカメラの映像をそのまま映し出すので、NTSC形式を指定することができません。
Scriptモードであれば、カメラ映像に切り替える代わりに独自のスクリプトを実行させることが可能です。つまりNTSC形式を指定した上で映像を表示するようなスクリプトを作れば、画質の問題は解決します。
左右反転や表示位置などの問題についても、スクリプトでこれらを調整するオプションを指定してやれば対策可能です。
Scriptモードだとバック信号を遮断しても画面表示が切り替わらない?
しかしScriptモードもちょっと不十分で厄介な仕様になっています。
デフォルトのV4L2モードだとGPIOでバック信号を検知してるあいだはカメラ映像に切り替え、信号を失うと元の画面表示に戻ります。
一方でScriptモードで実行される処理は、バック信号検知時に実行するスクリプトの内容がすべてです。つまりカメラ映像に切り替えることは可能ですが、信号を失った際にカメラ映像を終了させることができません。
厳密に言えば、表示自体は手動で元に戻せます。しかしバックグラウンドでカメラ周りのプロセスが動き続けているのです。そのせいで再度信号を検知してもカメラ映像に切り替わりません。フォーラムで同様の症状を訴えている方がいますが、メーカーは特に問題視しておらず修正する気はなさそうです。。
別途プログラムを用意してプロセスを強制終了することで対策可能
これの対策方法もないわけではありません。別途Pythonなどでプログラムを作成し、バック信号を失った際にカメラ周りのプロセスを終了するように仕組めば済む話です。ただしバックカメラ切り替え用とは別でもう1つGPIOピンを使用する必要があり、二度手間感は否めません。
OpenAuto Pro側で終了用のスクリプトも実行できるように作り替えてくれれば楽なんですけどねえ…
ともかく、これらに留意してスクリプトを作れば十分実用的なシステムを実装できました。
Scriptモードでリアカメラの映像を綺麗に表示させる方法
キャプチャしたビデオデバイスの映像をそのまま表示すると問題があるので、まずは仮想ビデオデバイスを作成。ビデオデバイスから受け取った映像は、FFmpegで諸々のオプションを指定して仮想ビデオデバイスに出力することにします。
仮想デバイスが受け取った映像はVLCで再生することにしました。
以下に作成例を示しますが、もっと良い方法やシンプルな書き方があればどなたか教えてください(ぇ
仮想ビデオデバイスを作成する
仮想ビデオデバイスの作成はv4l2loopbackモジュールを使用します。番号は他のビデオデバイスと被らないようにvideo_nr=xで固定しておくと良いです。
$ sudo apt install v4l2loopback-dkms $ sudo modprobe v4l2loopback video_nr=5 #/dev/video5を作成
なおRaspberry Pi OSのカーネルを最新バージョンに更新している場合、モジュールが対応しておらず自力でビルドしないといけない可能性があるので注意してください。やらかした人からの忠告です。
また手動でコマンドを実行するわけにはいかないので、udevを利用して自動化しました。
udevのルールファイルを作成するために、先にlsusbコマンドでUSBビデオキャプチャのidVendorとidProductの値を確認しておきます。
$ lsusb ・ ・ ・ $ Bus 001 Device 003: ID 18ec:5555 Arkmicro Technologies Inc.
ルールファイルの名前は以下のような数字と文字列の組み合わせにします。またidVendorとidProductの値は使用するUSBビデオキャプチャに合わせて書き換えてください。
$ sudo nano /etc/udev/rules.d/99-rearcam.rules
ATTRS{idVendor}=="18ec", ATTRS{idProduct}=="5555", RUN+="/sbin/modprobe v4l2loopback video_nr=5"
これでUSBビデオキャプチャの接続を検知すると自動的に仮想ビデオデバイスが作成されるようになります。
FFmpegでNTSC形式を指定する
FFmpegを利用してビデオデバイス /dev/video0から取り込んだ映像を、NTSC形式で仮想ビデオデバイス /dev/video5に出力するには以下のコマンドを実行します。
ちなみに見やすいように改行してますが、改行せず1行で書いても問題ないです。
ffmpeg -f v4l2 -standard NTSC -i /dev/video0 -vf format=yuv420p -f v4l2 /dev/video5
FFmpegで映像を左右反転させる
基本的に不要かと思われますが、もし映像を左右反転して出力させたいなら-vf hflipを追加します。
ffmpeg -f v4l2 -standard NTSC -i /dev/video0 -vf hflip,format=yuv420p -f v4l2 /dev/video5
なおこのUSBビデオキャプチャから出力される映像の解像度は640×480でした。Raspberry Pi公式タッチスクリーンのディスプレイ解像度は800×480なので、この組み合わせだと表示位置が左に偏って右側に黒帯ができてしまうようです。
ちゃんと中央に表示させたい場合、アスペクト比が異なるのは仕方がないので、以下のようにビデオサイズの横幅を160px増やし、表示位置を右側に80px寄せれば中央に表示させることが可能です。デフォルトの設定で問題ないようであればもちろんそのままで構いません。
ffmpeg -f v4l2 -standard NTSC -i /dev/video0 -vf pad=w=iw+160:x=80,hflip,format=yuv420p -f v4l2 /dev/video5
仮想ビデオデバイスの映像をVLCでストリーミング再生する
/dev/video5の映像をVLCで全画面表示、ストリーミング再生するためには以下のコマンドを実行します。なおデフォルトだとビデオデバイスの名前が表示されて邪魔だったので–no-video-title-showも付け加えました。
cvlc v4l2:///dev/video5 --fullscreen --no-video-title-show
FFmpegとVLCの処理をまとめて実行させるには以下のようなスクリプトを作成します。同時に実行させると失敗するので、cvlcコマンドはsleepで1秒から2秒ほど遅らせるのが良さそうです。
#!/bin/bash ffmpeg -f v4l2 -standard NTSC -i /dev/video0 -vf format=yuv420p -f v4l2 /dev/video5 & sleep 1 cvlc v4l2:///dev/video5 --fullscreen --no-video-title-show
スクリプトが完成したらopenauto_system.iniを編集してパスを設定しましょう。バック信号の検知などに利用するGPIO番号はGUIでも設定可能ですが、GUIで設定しようとすると途中で誤作動する場合があるので設定ファイルを編集するやり方が安全です。ちなみに筆者はGPIO19に設定しています。
$ cd /home/pi/.openauto/config/ $ sudo nano openauto_system.ini
配線については以下のような5極リレーを使用して繋ぎましょう。バック信号消失の際にもプログラムを実行するなら4極リレーではダメです。
バック信号が消えたらkillallコマンドを実行するPythonプログラムを作成する
先述したように、Scriptモードだと一度ギアをリバースに入れるとカメラ周りのプロセスがバックグラウンドで動き続けて障害を引き起こします。
そこでバック信号が消えたらkillallコマンドを実行してVLCとFFmpegを強制終了するプログラムをPythonで作成しました。
$ sudo nano /opt/killcam.py
#!/usr/bin/env python3 import RPi.GPIO as GPIO import time import sys import os GPIO.setmode(GPIO.BCM) GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) while True: try: GPIO.wait_for_edge(13, GPIO.RISING) os.system('killall vlc ffmpeg') time.sleep(0.1) except KeyboardInterrupt: GPIO.cleanup() sys.exit()
このプログラムの場合、GPIO13にプルダウン抵抗を設定して電圧状態を監視します。そしてGPIO13にの電圧がHIGHになったらkillallコマンドを実行します。
回路にはスクリプトと同じ5極リレーを利用して、バック信号が消える(=リレー非作動時)とGPIO13とGPIO26が接続されるように繋ぎましょう。リレー動作時はGPIO19に通電するようにしておきます。
ただしこのままだとGPIO同士を接続しても何も起きません。GPIO26の電圧をHIGHにしておく必要があります。というわけで以下のPythonプログラムも作成。
$ sudo nano /opt/setgpio.py
#!/usr/bin/env python3 import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(26, GPIO.OUT) GPIO.output(26, GPIO.HIGH)
2つのプログラムを同時に実行してみて、ギアの変更に合わせてバックカメラの映像が切り替われば成功です。
期待通りに動作することを確認したら、それぞれSystemdで自動実行されるようにしておきましょう。例として前者のみ記しておきます。
$ sudo nano /etc/systemd/system/killcam.service
[Unit] Description = killall vlc ffmpeg [Service] ExecStart = /opt/killcam.py Restart = always Type = simple [Install] WantedBy = multi-user.target
$ sudo chmod 0755 /opt/killcam.py $ sudo systemctl enable killcam $ sudo systemctl start killcam
懸念点と課題
実際に使用してみたところ、FFmpegによる処理を経由しているからか若干表示にラグがあり、ちょっと気を付けないといけない気がしました。まあ一気にバックせず、ちょっとずつ後退するだけで惨劇は回避できると思いますが。
あとUSBビデオキャプチャがマイクデバイスとしても認識されるせいで、Googleアシスタントが正常に動作しないことがあるようです。これについては以下の作業を実施することで対策できていると思います。
- PulseAudioをデフォルトのVer.12.2からアップデートさせない(要検証)
- GUIでPulseAudioの設定を変更してUSBビデオキャプチャをオーディオデバイスとして認識しないようにする
PulseAudioを自動的にアップデートされないように更新対象から除外するには以下のコマンドを実行すればOK。解除する場合はunholdです。
$ apt-mark hold pulseaudio
まとめ
以上、OpenAuto Proにおける車のバックカメラ接続方法とScriptモードの使い方を紹介しました。
デフォルトのV4L2モードで正常に動作してくれるならそれが1番楽ですが、上手くいかない場合はScriptモードで独自のスクリプトを設定してやりましょう。
またScriptモードで1度カメラ映像を表示した後、再度表示させることができない場合は最初に実行したプロセスが残ったままになっているのが原因と思われます。表示を終了する際にkillallコマンドなどでプロセスをしっかり終了してやれば、2回目以降もちゃんと切り替わるようになるはずです。
コメント