Reputation: 420
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.
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)
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