DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

python3でopenCVを使って2台のカメラ画像をゲットするために ラズパイでUSBカメラを2台認識しない問題を物理的に解決してみた

以前にapt-getを使ってopenCVをインストールしていましたが、これでインストールされるのはpython2系だそうです。 

dreamerdream.hateblo.jp

python2系のインストールコマンド

sudo apt-get install python-opencv

 

 

python3でカメラを使うにはpip3を使うそうです。

sudo pip3 install opencv-python

 

しかし、ソース上の

import cv2 

 

これだけでエラーが出ました。

エラー内容

ImportError: libcblas.so.3: cannot open shared object file: No such file or directory

 

ググるとこちらの記事がヒットしました。

rikoubou.hatenablog.com

 

こちらの記事の通り不足しているライブラリをインストールします。

sudo apt-get install libatlas-base-dev

 

上記の記事は他にもいろいろライブラリを入れていますが僕の環境の場合はこれだけでpython3でopenCVが使えるようになりました。

 

さて、問題はカメラの方です。

 

ls -la /dev/v4l/by-pathとlsusbコマンドでデバイスの確認

カメラ無接続

f:id:DreamerDream:20210423163328p:plain

カメラ1台接続

f:id:DreamerDream:20210423163338p:plain

カメラ2台接続

f:id:DreamerDream:20210423163354p:plain

 

デバイスが1つ増えるごとにvideoの番号が2つ増えています。

理屈はよく解りませんが、左右のカメラをopenCVで取得するには増えた番号の先頭である0と2をインデックス番号として

cap_L = cv2.VideoCapture(0)

cap_R = cv2.VideoCapture(2)

 

とすれば良いだけのようです。

 

しかし、これ起動ごとに左右入れ替わることは無いのだろうか?

 

と思って再起動すると・・・

f:id:DreamerDream:20210423164422p:plain

えええ???

2台目が認識されていません!!

 

テストで2台の画像を取得していたコードもエラー出現!

[ WARN:0] global /tmp/pip-wheel-qd18ncao/opencv-python/opencv/modules/videoio/src/cap_v4l.cpp (893) open VIDEOIO(V4L2:/dev/video2): can't open camera by index
Traceback (most recent call last):
File "camera.py", line 60, in <module>
caps()
File "camera.py", line 46, in caps
cv2.imwrite(path_R, frame_R) # ファイル保存
cv2.error: OpenCV(4.5.1) /tmp/pip-wheel-qd18ncao/opencv-python/opencv/modules/imgcodecs/src/loadsave.cpp:753: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'

画像が無いので保存出来ませんよというエラーです。 

 

ははーん、どうやらUSBの接続に問題があるようです。

 

そこで、こちらの記事を参考にソフトウェア的にUSBの電源を一度OFFにしてONにすることでUSB接続の情報をリセットが出来るかも?と試してみました。 

vogel.at.webry.info

 

スクリプトも書きました。

### usb_rebind.py ###

#!/usr/bin/python
#coding:utf-8

import subprocess
import time

def off():
  subprocess.call('sudo sh -c "echo -n \"1-1\" > /sys/bus/usb/drivers/usb/unbind"',shell=True )

def on():
  subprocess.call('sudo sh -c "echo -n \"1-1\" > /sys/bus/usb/drivers/usb/bind"',shell=True )

if __name__=='__main__': # if script
  off()
  time.sleep(3)
  on()

 

結果、ダメでした orz...。

試しにUSBハブに2台繋いで同時に接続してみても認識しません。

 

別々で繋ぐと認識出来ます。おそらくカメラの相性ですね。

・・・困りました。(ーー;ムムム。。。

 

 

ということで、物理的に切断&接続するという暴挙に出ます。

f:id:DreamerDream:20210427121108p:plain

USBケーブルのここを切り、手持ちのFETでGNDに落とします。(推奨しません)

 

回路

f:id:DreamerDream:20210427123317p:plain

FETはNchパワーMOSFET 2SK4017(Q) (60V5A)を使用しました。

 

 

この回路の状態で試しにマウスを接続して起動させると、なんと信号線をGNDとしてマウスが普通に使えてしまいました orzやっぱりか。。。

しかし、純粋にUSBカットは出来ないようですが、カメラを繋いでON-OFF-ONと繰り返すと電圧差の加減なのかカメラのOFF→ONは出来ました。(これもカメラの相性があるかもしれません。)

 

スクリプトには

time.sleep(3)
on()
time.sleep(1)
off()
time.sleep(1)
on()
print('USB-3 RESET')
while True:
  time.sleep(60)

と書いてサービスに登録、ラズパイ起動3秒後にon-off-onとさせます。

GPIOの制御は基本のLチカですので割愛します。

dreamerdream.hateblo.jp

 

 

これでやっとカメラ2台を認識するようになりました。

f:id:DreamerDream:20210423163354p:plain

 

信号線にGNDが流れてしまうのでラズパイの回路には優しくないと思うので推奨はしませんが、今回はこんな方法で認識しましたという報告でした。

 

以上です。

 

<参考> 

dev.classmethod.jp

 

qiita.com

www.fixes.pub

kampa.me