Jetson Xavier NXでRealSenseを使用する際のインストール方法・注意点・実装コード(2台編)

2020.07.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

カフェチームの山本です。

現在、カフェではコンピュータビジョン用のカメラとして、Intel製のRealSenseというデバイスを利用し、RGB画像とDepth画像を取得しています。

(8/17:タイトルを「複数台編」から「2台編」に変更しました。)

前回は、RealSenseデバイスを1台のみ利用する場合でしたが、今回は2台利用する場合について記載します。

Jetson Xavier NXでRealSenseを使用する際のインストール方法・注意点・実装コード

0.Jetson Xavier NXを準備

前回の記事をご覧ください。

Jetson Xavier NXでRealSenseを使用する際のインストール方法・注意点・実装コード

1.RealSense用ライブラリをインストール

前回の記事をご覧ください。

Jetson Xavier NXでRealSenseを使用する際のインストール方法・注意点・実装コード

2.接続する場合の問題点と解決法

問題点:2つ目のRealSenseデバイスに接続できない

前回の記事で実装したコードを元に、以下のようなコードを実装しました。

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 = 640
CAPTURE_HEIGHT = 480
CAPTURE_FPS = 60

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()

def get_realsense_serialnumbers(max_n=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]

    return serial_numbers_

def setup_realsense_camera(device_serial_number, width, height, fps):
    # ストリーム(Color/Depth)の設定
    config = rs.config()
    config.enable_device(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)

    return pipeline, profile

def get_images(pipeline):
    frames = pipeline.wait_for_frames()

    # RGB
    RGB_frame = frames.get_color_frame()
    RGB_image = np.asanyarray(RGB_frame.get_data())

    # depth
    depth_frame = frames.get_depth_frame()
    depth_image = np.asanyarray(depth_frame.get_data())

    return RGB_image, depth_image

def main():
    # reset usb connection of realsense devices
    print("reset_realsense_devices")
    while True:
        try:
            reset_realsense_devices()
            break
        except:
            print("Exception in reset_realsense_devices")
            print("try again in 1 second")

            import traceback
            traceback.print_exc()
            print()

            time.sleep(1)
            continue

    # setup pipeline
    print("get_realsense_serialnumbers")
    while True:
        serial_numbers = get_realsense_serialnumbers(max_n=2)
        if len(serial_numbers) > 0:
            break
        else:
            print("failed to get realsense serial number")
            print("try again in 1 second")
            time.sleep(1)
            continue
    print(serial_numbers)

    print("setup_realsense_camera")
    pipelines = []
    for serial_number in serial_numbers:
        pipeline, _ = setup_realsense_camera(serial_number, CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS)
        pipelines.append(pipeline)

    # get image and show
    print("get_images")
    i = 0
    while True:
        # print(i)
        RGB_images = []
        for pipeline in pipelines:
            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

        i += 1

if __name__ == "__main__":
    main()

このプログラムを実行すると、setup_realsense_cameraで2つ目のRealSenseデバイスに接続する際に、65行目のprofile = pipeline.start(config)で処理止まり関数から帰って来ない、という問題が発生しました(ターミナルでctrl+cを入力しても止まらず、ctrl+zを入力すると止まります)。プログラムを何度実行したり、OSを再起動したり、RealSenseデバイスを接続し直しても同様の結果でした。

解決策:設定する順序を変更する

色々試した結果、RealSenseデバイスに接続する順番を変えるとうまくいくことがわかりました。

3.実装したコード

上のコードとほとんど同じですが、110行目を変更しています。get_realsense_serialnumbersで取得したシリアル番号を、逆順に取り出してsetup_realsense_cameraで接続することで、処理が止まらず動作させることができました。プログラムを再実行、OS再起動、RealSenseデバイスを接続し直しても、動作しました。

確認したのは2台までの場合で、3台以上の場合はこの方法では動作しない可能性があります。ご注意ください。

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 = 640
CAPTURE_HEIGHT = 480
CAPTURE_FPS = 60

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()

def get_realsense_serialnumbers(max_n=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]

    return serial_numbers_

def setup_realsense_camera(device_serial_number, width, height, fps):
    # ストリーム(Color/Depth)の設定
    config = rs.config()
    config.enable_device(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)

    return pipeline, profile

def get_images(pipeline):
    frames = pipeline.wait_for_frames()

    # RGB
    RGB_frame = frames.get_color_frame()
    RGB_image = np.asanyarray(RGB_frame.get_data())

    # depth
    depth_frame = frames.get_depth_frame()
    depth_image = np.asanyarray(depth_frame.get_data())

    return RGB_image, depth_image

def main():
    # reset usb connection of realsense devices
    print("reset_realsense_devices")
    while True:
        try:
            reset_realsense_devices()
            break
        except:
            print("Exception in reset_realsense_devices")
            print("try again in 1 second")

            import traceback
            traceback.print_exc()
            print()

            time.sleep(1)
            continue

    # setup pipeline
    print("get_realsense_serialnumbers")
    while True:
        serial_numbers = get_realsense_serialnumbers(max_n=2)
        if len(serial_numbers) > 0:
            break
        else:
            print("failed to get realsense serial number")
            print("try again in 1 second")
            time.sleep(1)
            continue
    print(serial_numbers)

    print("setup_realsense_camera")
    pipelines = []
    for serial_number in reversed(serial_numbers):
        pipeline, _ = setup_realsense_camera(serial_number, CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS)
        pipelines.append(pipeline)

    # get image and show
    print("get_images")
    i = 0
    while True:
        # print(i)
        RGB_images = []
        for pipeline in pipelines:
            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

        i += 1

if __name__ == "__main__":
    main()

まとめ

コンピュータビジョン用のカメラとして利用できるIntel製のRealSenseを、Jetson Xavier NXで動かすためのコードを実装しました。接続順をpyrealsenseから得られる順番の逆にすることで、2台接続することができました。