Jetson Xavier NXでRealSenseを使用する際のインストール方法・注意点・実装コード(4台編)
カフェチームの山本です。
現在、カフェではコンピュータビジョン用のカメラとして、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でも利用できるかと思われます。