この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
カフェチームの山本です。
現在、カフェではコンピュータビジョン用のカメラとして、Intel製のRealSense Depth Camera D435Iというデバイスを利用して店内を撮影し、Jetson Xavier NXに接続して画像を処理しています。Jetsonに接続できるRealSenseの台数を増やせれば、Jetsonの台数が少なくてすみ、ハードウェアのコストを下げることができます。
前回は、Jetson1台にRealSenseを2台接続して利用できることを確認しました。
今回は、RealSenseを4台接続するために試行錯誤した内容についてまとめます。具体的には、接続ケーブルの長さ、電源ハブの有無、画像取得の解像度・フレームレートを変更しながら、同時に接続して画像を取得できる台数を調べました。
結論としては、RGB画像とdepth画像を取得する際、4台接続したい場合は、解像度を848*480以下に設定する必要があり、1280*720に設定した場合は2台までしか画像を取得できないことがわかりました。
0.Jetson Xavier NXでRealSenseを使用するためのセットアップ方法
前々回の記事をご参照ください。
1.4台接続する際の問題点(エラー内容)
今回は、以下のスクリプトを実装して使用しました。RealSenseからRGB画像とdepth画像を取得する処理を実行しています。前々回の記事に書いた用に、Jetson Xavier NXでRealSenseを利用する場合には、毎回接続をリセットする必要があるため、usbライブラリをで接続をリセットする処理を入れています(reset_realsense_devices)。
import pyrealsense2 as rs
import usb
import numpy as np
import cv2
import time
ID_VENDOR_REALSENSE = 0x8086 # Intel
MANUFACTURER_REALSENSE = "Intel(R) RealSense(TM)"
PRODUCT_REALSENSE = "Intel(R) RealSense(TM)"
CAPTURE_WIDTH = 1280 # 後で848に変更します
CAPTURE_HEIGHT = 720 # 後で480に変更します
CAPTURE_FPS = 30
N_REALSENSE_DEVICES = 4
def reset_realsense_devices():
usb_devices = usb.core.find(find_all=True)
def is_realsense_device(dev):
is_same_idVendor = dev.idVendor == ID_VENDOR_REALSENSE
if not is_same_idVendor:
return False
is_same_manufacturer = MANUFACTURER_REALSENSE in dev.manufacturer
is_same_product = PRODUCT_REALSENSE in dev.product
return is_same_manufacturer and is_same_product
realsense_devices = filter(is_realsense_device, usb_devices)
for dev in realsense_devices:
dev.reset()
# reset usb connection of realsense devices
def reset_realsense_devices_with_retry(n_retry=5):
i_retry = 0
while True:
try:
reset_realsense_devices()
break
except:
print("Exception in reset_realsense_devices")
import traceback
traceback.print_exc()
i_retry += 1
if i_retry >= n_retry:
return None
print("try again in 1 second")
time.sleep(1)
continue
return True
def get_realsense_serial_numbers(max_n_device=1):
# pyrealsense2.context
ctx = rs.context()
# pyrealsense2.device_list
devices = ctx.query_devices()
serial_numbers = map(lambda device: device.get_info(rs.camera_info.serial_number), devices)
serial_numbers_ = list(serial_numbers)[:max_n_device]
return serial_numbers_
def get_realsense_serial_numbers_with_retry(max_n_device=1, n_retry=5):
# setup pipeline
i_retry = 0
while True:
serial_numbers = get_realsense_serial_numbers(max_n_device=max_n_device)
if len(serial_numbers) > 0:
break
else:
print("failed to get realsense serial number")
i_retry += 1
if i_retry >= n_retry:
return None
print("try again in 1 second")
time.sleep(1)
continue
return serial_numbers
def start_realsense_camera(serial_number, width, height, fps):
# ストリーム(Color/Depth)の設定
config = rs.config()
config.enable_device(serial_number)
config.enable_stream(rs.stream.color, width, height, rs.format.bgr8, fps)
config.enable_stream(rs.stream.depth, width, height, rs.format.z16, fps)
# ストリーミング開始
pipeline = rs.pipeline()
profile = pipeline.start(config)
print(profile)
return pipeline, profile
def start_realsense_camera_from_bagfile(bag_filepath):
config = rs.config()
config.enable_device_from_file(bag_filepath)
# config.enable_stream(rs.stream.color, width, height, rs.format.bgr8, fps)
# config.enable_stream(rs.stream.depth, width, height, rs.format.z16, fps)
# ストリーミング開始
pipeline = rs.pipeline()
profile = pipeline.start(config)
print(profile)
return pipeline, profile
def setup_realsense_cameras(n_realsense_devices, capture_width, capture_height, capture_fps):
print("reset_realsense_devices_with_retry")
ret = reset_realsense_devices_with_retry()
if ret is None:
print("Error: reset_realsense_devices_with_retry")
return
print("get_realsense_serial_numbers_with_retry")
serial_numbers = get_realsense_serial_numbers_with_retry(max_n_device=n_realsense_devices)
if serial_numbers is None:
print("Error: get_realsense_serial_numbers_with_retry")
print("start_realsense_camera")
pipelines = []
for serial_number in reversed(serial_numbers):
pipeline, _ = start_realsense_camera(serial_number, capture_width, capture_height, capture_fps)
pipelines.append(pipeline)
return pipelines, serial_numbers
def setup_realsense_cameras_from_bagfile(input_bag_filepaths):
print("start_realsense_camera")
pipelines = []
serial_numbers = []
for bag_filepath in input_bag_filepaths:
pipeline, _ = start_realsense_camera_from_bagfile(bag_filepath)
pipelines.append(pipeline)
serial_numbers.append(bag_filepath)
return pipelines, serial_numbers
def get_images(pipeline):
frames = pipeline.wait_for_frames()
# RGB
RGB_frame = frames.get_color_frame()
try:
RGB_image = np.asanyarray(RGB_frame.get_data())
except:
RGB_image = None
# depth
depth_frame = frames.get_depth_frame()
try:
depth_image = np.asanyarray(depth_frame.get_data())
except:
depth_image = None
return RGB_image, depth_image
def main():
pipelines, serial_numbers = setup_realsense_cameras(N_REALSENSE_DEVICES, CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS)
print(serial_numbers)
# get image and show
print("get_images")
while True:
RGB_images = []
for j, pipeline in enumerate(pipelines):
print(j)
RGB_image, depth_image = get_images(pipeline)
RGB_images.append(RGB_image)
# depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.08), cv2.COLORMAP_JET)
for j, RGB_image in enumerate(RGB_images):
cv2.imshow(f"realsense image {j}", RGB_image)
key = cv2.waitKey(1)
if key == 27: # ESC
break
if __name__ == "__main__":
main()
上記のスクリプトを実行すると、RealSenseに接続してセットアップする処理(setup_realsense_cameras)までは動作し、main関数中の最初のforループで、2つ目のpipelineまでは画像を取得できましたが、3つ目のpipelineで画像を取得する処理(get_images中のpipeline.wait_for_frames)で以下のエラーが発生し、画像を取得することができませんでした。
RuntimeError: Frame didn't arrived within 5000ms
2.4台同時に接続できる条件
上記のエラーに対処するため、どのような条件であれば画像を取得できるか調べました。
調べてみると、ケーブルが悪いとうまく認識されないというコメント(下リンク)や、電流が足りていないのではという意見がありました。
そのため今回は、パラメータとしてケーブルの長さ・電源ハブの有無・解像度・フレームレートを変えながら、接続できる台数を調べました。
使用機材
今回は以下の機材を使用しました。
- ケーブル:USB3.1 2m(https://www.yodobashi.com/product/100000001002559477/)
- 延長ケーブル:USB3.0 2m(https://www.yodobashi.com/product/100000001004052920/)
- 電源つきハブ:定格電流 2.5A(ACアダプタ接続時)(https://www.yodobashi.com/product/100000001003501194/)
- RealSense 435I:ファームウェアのバージョンは05.12.01.00でした。
電源ハブを使用する際は、RealSense1つにつき、電源ハブ1つを使用しました(3ポートは空きの状態です。念のため複数接続せず、1つだけにしました。)。RealSenseは1台につき700mA使用するので、定格電流以内です。
実験
パラメータは以下のように設定しました。
ケーブル長
RealSenseに接続するケーブルの長さ
- 2m:上記の「ケーブル」のみ
- 2m+2m:上記の「ケーブル」+「延長」ケーブル
電源つきハブ
JetsonからRealSenseへのケーブルに接続する前に電源つきハブを介すか
- あり:上記の「電源つきハブ」を通して、ケーブルに接続
- なし:そのままケーブルに接続
解像度
RealSenseで取得する画像の解像度。前節のプログラムのCAPTURE_WIDTH・CAPTURE_HEIGHTの値。
- 1280 * 720[px]
- 848 * 480[px]
- 640 * 480[px]
- 640 * 360[px]
(RealSenseはRGB画像のみを取得する場合、960540・19201080で設定できますが、depthはこれらのサイズで設定できないため、対象外としました。)
フレームレート
RealSenseで画像取得する速度。前節のプログラムのCAPTURE_FPSの値。
- 30[fps]
- 15[fps]
- 6[fps]
(RealSenseが対応している値を設定しました。)
結果
それぞれの条件で、接続するRealSenseの台数(スクリプト中のN_REALSENSE_DEVICES)を変えながら、画像を取得できる台数を調べた結果は、以下の表のとおりです。(FPSが複数かかれている箇所は、それらのFPSで同じ結果だったことを表します。)
ケーブル | 電源ハブ | 解像度 | FPS | 結果 |
---|---|---|---|---|
2m | なし | 1280*720 | 30, 15, 6 | 2台まで可 |
2m | なし | 848*480 | 30 | 4台まで可 |
2m | なし | 640*480 | 30 | 4台まで可 |
2m | なし | 640*360 | 30 | 4台まで可 |
2m+2m | なし | 1280*720 | 30, 15, 6 | 2台まで可 |
2m+2m | なし | 848*480 | 30 | 4台まで可 |
2m+2m | なし | 640*480 | 30 | 4台まで可 |
2m+2m | なし | 640*360 | 30 | 4台まで可 |
2m | あり | 1280*720 | 30, 15, 6 | 2台まで可 |
2m+2m | あり | 1280*720 | 30, 15, 6 | 2台まで可 |
この表からわかることは以下のとおりです。
- RealSenseを4台使用したい場合は、解像度を848*480以下にする必要がある。
- 解像度を1280*720に設定すると、2台までしか画像を取得できない。フレームレートを変えても同様。
- ケーブルの長さや電源ハブの有無は影響がない。
まとめ
Jetson Xavier NXでRealSenseを4台利用するために、エラーが発生しない条件を調査しました。結果として、RealSenseで取得する画像の解像度を848*480以下に設定することで、4台から同時に画像を取得できることがわかりました。
PCの方でも同様に、RealSenseを4台接続して、realsense-viewerで撮影動画を確認しようとすると、プログラムが落ちるというエラーがありました。今回の記事の内容はJetson Xavier NXでの結果でしたが、PC版でも同じような結果になるかもしれません(未確認)。
参考にさせていただいたページ
補足
- USB3の規格
USB3の規格として、ケーブルの長さは最大3mであるようです。今回の実験で延長ケーブルを使用した際、合計4mになっており、規格をオーバーしています。どこかで影響が出ていた可能性はあります。
設置する状況によっては、10mを利用したい場合などあるかと思います。その際に問題が起きた場合は、以下のページが参考になりそうです。
Intel RealSense USBエクステンダー | 株式会社TKS2
- 正しく設定してもRealSenseが動かない場合
今回実験している中で、解像度を848*480以下にしても、1.で述べたエラーがまれに出ることがありました。このエラーは、設定を変更してプログラムを再度実行すると発生したのですが、再現性がなく、正確な原因は把握できていません。再起動してから、設定を変えずに実行している限りではエラーが発生していないため、一度再起動するとよさそうです。
また、RealSenseが動かない場合に確認すべき点として、以下のページが参考になりそうです。Raspberry Piの場合が書かれていますが、Jetsonでも利用できるかと思われます。