Craftonix - AA
Craftonix - AA

Reputation: 420

Luxonis OAK-D S2 PoE: how do I use the SDK and flash a standalone application?

I am unable to flash a standalone application if it is based on the SDK.

It seems there might be a conflict between using the SDK OakCamera() and the API dai.DeviceBootloader() but I don't know why the conflict is there or how to resolve it. It does seem that each of these 2 calls results in some kind of device state that does not allow the other call to proceed.

Flashing works for API-based applications

By following the Luxonis documentation under API heading, when I try the Standalone mode, I'm able to flash any application which is based on the API, for example, this webserver code works (both when STAND_ALONE=True and when STAND_ALONE=False):

#!/usr/bin/env python3

STAND_ALONE = True
# STAND_ALONE = False

import depthai as dai
import time

# Start defining a pipeline
pipeline = dai.Pipeline()

# Define a source - color camera
cam = pipeline.create(dai.node.ColorCamera)
# VideoEncoder
jpeg = pipeline.create(dai.node.VideoEncoder)
jpeg.setDefaultProfilePreset(cam.getFps(), dai.VideoEncoderProperties.Profile.MJPEG)

# Script node
script = pipeline.create(dai.node.Script)
script.setProcessor(dai.ProcessorType.LEON_CSS)
script.setScript("""
    from http.server import BaseHTTPRequestHandler
    import socketserver
    import socket
    import fcntl
    import struct

    PORT = 8080
    ctrl = CameraControl()
    ctrl.setCaptureStill(True)

    def get_ip_address(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            -1071617759,  # SIOCGIFADDR
            struct.pack('256s', ifname[:15].encode())
        )[20:24])

    class HTTPHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            if self.path == '/':
                self.send_response(200)
                self.end_headers()
                self.wfile.write(b'<h1>[DepthAI] Hello, world of STANDALONE!</h1><p>Click <a href="img">here</a> for an image</p>')
            elif self.path == '/img':
                node.io['out'].send(ctrl)
                jpegImage = node.io['jpeg'].get()
                self.send_response(200)
                self.send_header('Content-Type', 'image/jpeg')
                self.send_header('Content-Length', str(len(jpegImage.getData())))
                self.end_headers()
                self.wfile.write(jpegImage.getData())
            else:
                self.send_response(404)
                self.end_headers()
                self.wfile.write(b'Url not found...')

    with socketserver.TCPServer(("", PORT), HTTPHandler) as httpd:
        node.warn(f"Serving at {get_ip_address('re0')}:{PORT}")
        httpd.serve_forever()
""")

# Connections
cam.still.link(jpeg.input)
script.outputs['out'].link(cam.inputControl)
jpeg.bitstream.link(script.inputs['jpeg'])

if STAND_ALONE:
    # Flash the pipeline
    (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
    bootloader = dai.DeviceBootloader(bl)
    progress = lambda p : print(f'Flashing progress: {p*100:.1f}%')
    bootloader.flash(progress, pipeline)

else:
    # Connect to device with pipeline
    with dai.Device(pipeline) as device:
        while not device.isClosed():
            time.sleep(1)

Need help flashing SDK-based applications

However, the Luxonis documentation under SDK heading does not have a Standalone mode section. So, I tried to combine the interoperability example, and the Flash the pipeline example. Both examples work well on their own. Just to clarify, the interoperability example explains how to use the SDK to create oak=OakCamera(), get the pipline using pipeline=oak.build(), then run the pipeline using oak.start(). Also, following the docs about standalone, we need to remove all XLinkOut nodes because we don't have a host to communicate to. So, I tried to use the principle of getting pipeline from the SDK and passing it to bootloader.flash() as in this code:

#!/usr/bin/env python3

# SDK version

STAND_ALONE = True
# STAND_ALONE = False

from depthai_sdk import OakCamera
import depthai as dai
import time

# Try putting bootloader in location #1
# (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
# bootloader = dai.DeviceBootloader(bl)
# progress = lambda p : print(f'Flashing progress: {p*100:.1f}%')

with OakCamera() as oak:
    color = oak.create_camera('color')
    # nn = oak.create_nn('mobilenet-ssd', color)
    # oak.visualize([nn.out.passthrough, nn], fps=True)

    # Build the pipeline, connect to the oak, update components. Place interop logic AFTER oak.build()
    pipeline = oak.build()

    # nn.node.setNumInferenceThreads(2) # Configure components' nodes

    # features = pipeline.create(dai.node.FeatureTracker) # Create new pipeline nodes
    # color.node.video.link(features.inputImage)

    # out = pipeline.create(dai.node.XLinkOut)
    # out.setStreamName('features')
    # features.outputFeatures.link(out.input)

    if STAND_ALONE:
        # # Flash the pipeline
        # Try putting bootloader in location #2
        (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
        bootloader = dai.DeviceBootloader(bl)
        progress = lambda p : print(f'Flashing progress: {p*100:.1f}%')
        bootloader.flash(progress, pipeline)

    else:
        oak.start() # Start the pipeline (upload it to the OAK)

        q = oak.device.getOutputQueue('features') # Create output queue after calling start()
        while oak.running():
            if q.has():
                result = q.get()
                print(result)
            # Since we are not in blocking mode, we have to poll oak camera to
            # visualize frames, call callbacks, process keyboard keys, etc.
            oak.poll()

but I'm getting the following error:

Closing OAK camera
Traceback (most recent call last):
  File "/Users/user/try/4-luxonis/3-http-server-standalone/oak-sdk.py", line 38, in <module>
    bootloader = dai.DeviceBootloader(bl)
RuntimeError: Device not in UNBOOTED, BOOTLOADER or FLASH_BOOTED state

There is no explanation in the docs about these device states and how to get to one of them: UNBOOTED, BOOTLOADER or FLASH_BOOTED

So, I tried moving the 3 lines of code from location #2 to location #1, but now I get the error:

Traceback (most recent call last):
  File "/Users/user/try/4-luxonis/3-http-server-standalone/oak-sdk.py", line 17, in <module>
    with OakCamera() as oak:
  File "/Users/user/try/4-luxonis/1-baby-steps/.venv/lib/python3.10/site-packages/depthai_sdk/oak_camera.py", line 71, in __init__
    self._init_device()
  File "/Users/user/try/4-luxonis/1-baby-steps/.venv/lib/python3.10/site-packages/depthai_sdk/oak_camera.py", line 229, in _init_device
    self._oak.device = dai.Device(
RuntimeError: Failed to connect to device, error message: X_LINK_DEVICE_NOT_FOUND

So, it seems there might be a conflict between using the SDK OakCamera() and the API dai.DeviceBootloader() but I don't know why the conflict is there or how to resolve it. It does seem that each of these 2 calls results in some kind of device state that does not allow the other call to proceed.

Upvotes: 0

Views: 403

Answers (0)

Related Questions