北の国から

忘れたことを思い出す為の記録

depthaiのxLinkを通して任意のデータをやり取りする方法

Introduction

depthai はLuxonisが作っている(?)VPUやカメラなどをひとまとめにしたデバイス(OAK-Dなど)を扱う際に必要となるライブラリです。

OAK-D-WIFI(製品として出てるのはOAK-D-IoT)にはESP32が搭載されているのでセンサのデータをやり取りしたり、ESPを通してモータを制御したりなどいろいろやれることがあります。

OAK-D-WIFIはSPIのピンもそのままコネクタとして引き出されているのでVPU側からSPIでセンサデータを直接取り出すこともできそうです。

Motivation

公式のサンプルは各機能の扱い方よりは「カメラ周りですでにライブラリ化されたものたち(NNやDepthなど)でこんなことができますよ」みたいな側面を強く感じたので、今回はホストーデバイス間でのデータのやり取りの基礎となるxLinkプロトコル部分について、コールバックするスクリプトの作成を通して学んでいきます。

Script

import depthai as dai
import time

def main():
    pipeline = dai.Pipeline()

    xIn = pipeline.createXLinkIn()
    xIn.setStreamName("stream_0")

    xOut = pipeline.createXLinkOut()
    xOut.setStreamName("stream_1")

    xIn.out.link(xOut.input)

    with dai.Device(pipeline) as device:
        start = time.time()
        xIn_queue = device.getInputQueue("stream_0")
        xOut_queue = device.getOutputQueue("stream_1",maxSize=5,blocking=False)
        
        while True:
            t = time.time() - start

            data_out = dai.RawBuffer()
            data_out.data = [t,t]

            xIn_queue.send(data_out)

            data_in = xOut_queue.tryGet()
            if data_in is not None:
                print(data_in.getData())

if __name__ == "__main__":
    main()

Explanation

import depthai as dai
import time

depthaiは大抵のサンプルでdaiエイリアスされているので私もそうします。
timeは結果を用意するために使います。

pipeline = dai.Pipeline()

xIn = pipeline.createXLinkIn()
xIn.setStreamName("stream_0")

xOut = pipeline.createXLinkOut()
xOut.setStreamName("stream_1")

xIn.out.link(xOut.input)

まず,depthaiでデバイスを扱うにはpipelineを用意する必要があるためdai.Pipeline()インスタンスを生成します。
createXLinkIn()createXLinkOut()メソッドによってパイプライン上にストリームを生成し、setStreamName命名します。
これらのcreateなんちゃらはcreateメソッドのノードごとの固有ラッパみたいなのでノードを自作する場合などはcreateメソッドから指定してあげる必要があります。(ノード自作のやり方や必要性はまだ理解していないです)

それぞれ名称設定等の初期設定が終わったら、出力の.out.linkメソッドに入力の.input変数を与えてストリームをつなぐ先を指定します。
今回の場合、stream_0がホストからのデータ取得、stream_1がホストへのデータ吐き出しなのでVPUデバイス内では stream_0 -> stream_1 とつないでいます。

  with dai.Device(pipeline) as device:
        start = time.time()
        xIn_queue = device.getInputQueue("stream_0")
        xOut_queue = device.getOutputQueue("stream_1",maxSize=5,blocking=False)
        
        while True:
            t = time.time() - start

            data_in = dai.RawBuffer()
            data_in.data = [t]

            xIn_queue.send(data_in)

            data_out = xOut_queue.tryGet()
            if data_out is not None:
                print(data_out.getData())

バイスーホスト間のデータのやり取りは``Queue```で行われます。
In/Outの関係性ですが、depthaiのAPIは基本的にデバイス視点で設定されているようです(In関数群がデータ取得、Out関数群データ吐き出し)

xIn_queuesendメソッドでデータを送信できます。RawBufferdata変数にlistを入れると好きにデータを遅れます。

また、データの取得はtryGetメソッドでデータがあるかを確認してから、getDataでデータを取得します。

今回はtimeを入れて試してみました。

f:id:r_u__r_u:20211114165156p:plain

送受信できたdataは基本的に整数の1列のリストか同じ長さのリストのリストでした。[[0], [1,2]]のようなデータは送れないようです。
また、リストのリストは1列に圧縮されます。( [[0,1],[2,3]]を送ると[0,1,2,3] )
どこでそうなるでかはわかっていませんが。

Conclusion

ひとまずやりたいこととして任意のデータ送信ができました。
目的はOAK上のESPによるサーボ制御なので整数型の一列listが送れれば十分です。
次回はSPIOutによるESP側とのコミュニケーションを実装します。

ruru